3

Long time lurker, first time poster.

Background: I have an asp.net webforms application that currently references a third party assembly that contains various web controls. The third party controls are sometimes used directly on various pages or are part of user controls that are used else where. The application also makes use of custom server controls that extend various third party controls as well. These custom controls are also used in a similar manner.

Reference(s): Related Post, There are several more that discuss multiple versions of an assembly, but nothing i found where the assemblies referenced contained webcontrols.

Problem: Its been discovered that one of the third party controls has an issue with IE10. The issue is addressed in the latest version of the third party assembly. However I cannot fully upgrade the entire application to the latest version of the third party assembly.

Question: Is it possible to run two versions of the third party assembly side by side?

Research: I have taken the assembly binding approach as mentioned in several other posts regarding multiple versions of the same assembly:

<dependentAssembly>
<assemblyIdentity name="thirdParty" publicKeyToken="XXX"/>
<codeBase version="OldVersion" href="bin"/>
<codeBase version="NewVersion" href="2013/ThirdParty.dll"/>
</dependentAssembly>
</assemblyBinding>

I've also referenced both assemblies in the project file and alias the new version of the assembly:

<Reference Include="ThirdParty, Version=OldVersion, Culture=neutral, PublicKeyToken=XXX, processorArchitecture=MSIL">
<SpecificVersion>True</SpecificVersion>
<HintPath>..\..\Library\ThirdParty.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="ThirdParty, Version=NewVersion, Culture=neutral, PublicKeyToken=XXX, processorArchitecture=MSIL">
<SpecificVersion>True</SpecificVersion>
<HintPath>2013\ThirdParty.dll</HintPath>
<Private>False</Private>
<Aliases>newVersion</Aliases>
</Reference>

In the target user control that I want to use the new version of the controls, I have the following markup:

<%@Assembly Name="ThirdParty,  Version=NewVersion, Culture=neutral, PublicKeyToken=XXX" %>
<%@Register tagPrefix="2013" namespace="ThirdPartyNamespace" Assembly="ThirdParty,  Version=NewVersion, Culture=neutral, PublicKeyToken=XXX"  %>

In the designer codebehind i have the following (newVersion is the alias assigned to the reference above):

extern alias newVersion;

protected newVersion::ThirdParty.ControlName cbRangeType;

Everything builds and runs until I get to the portion where the asp.net compiler is parsing the markup. It fails with the CS0433 error. Which pretty much indicates that type of cbRangeType control exists in two different places.

\AppData\Local\Temp\Temporary ASP.NET Files\root\9f04cc99\85cc721e\assembly\dl3\5dc4ef04\77c80123_27b9ce01\ThirdParty.DLL

\WebSites\Site\2013\ThirdParty.dll'

Looking at the generated code, I see that the control type is not using the newVersion alias, but the default global alias:

Line 348:        [System.Diagnostics.DebuggerNonUserCodeAttribute()]
Line 349:        private global::ThirdParty.ControlName @__BuildControlcbRangeType() {
Line 350:            global::ThirdParty.ControlName @__ctrl;

Is it even possible for me to override whats generated by the call to BuildControl() at the user control level? Is what I am attempting to do even possible? Thanks in advance.

Regards, Noobian

Noobian
  • 35
  • 3

2 Answers2

1

Nope, this isn't possible. If they differ only by version but have the same identity, they can't run side by side. Use the newer one.

Scott Hanselman
  • 17,712
  • 6
  • 74
  • 89
1

Is it even possible for me to override whats generated by the call to BuildControl() at the user control level?

It would be more of a replacement than an override, requiring re-implementing the entire ASP.NET build provider for user controls. (In v4.5 it remains an inextensible maze of internal sealed classes; you could start from the Mono project / ASP.NET vNext instead!)

Is what I am attempting to do even possible?

As of this writing (v4.5), the ASP.NET build providers (markup code generators) do not emit the extern alias declaration + namespace alias qualifier (::) combo required. Thus, using multiple versions of 3rd party controls in ASP.NET web forms is possible only for server controls (a.k.a. custom, web, or composite controls; not user controls with .ascx markup... more details on the distinction here).

Commercial-quality ASP.NET controls are typically implemented as server controls, and the standard technique for using multiple versions of the same assembly works fine when instantiating them programmatically. However, no objects with multiple versions from different assemblies can be accessed in ASP.NET markup - all interaction has to be in the code-behind. Use a PlaceHolder in the markup and add the server control to it in CreateChildControls. Access the control by creating method/property wrappers as needed.

If the new version of your example's 3rd party assembly contains a server control:

  1. Move the manual modifications made in the .ascx.designer.cs designer code-behind (the extern alias and member variable) to the .ascx.cs code-behind to ensure they are not overwritten.
  2. Remove the @Assembly and @Register directives referencing the 3rd party assembly from your target user control markup.
  3. Add a PlaceHolder to your target user control markup where you want to the server control to appear: <asp:PlaceHolder id="phMarkupRangeTypePlaceHolder" runat="server" />
  4. Add the following to your code-behind:
    protected override void CreateChildControls()
    {
    base.CreateChildControls();
    this.cbRangeType = new newVersion::ThirdParty.ControlName();
    this.phMarkupRangeTypePlaceHolder.Controls.Add(this.cbRangeType);
    }
    protected string cbRangeTypeCustomProperty //-ish
    {
    get { return this.cbRangeType.CustomProperty; }
    }

PS. Assemblies and their dependencies require strong names when using multiple versions.

Community
  • 1
  • 1
user423430
  • 3,654
  • 3
  • 26
  • 22
  • 1
    Very useful! It helped me to load two versions of the control on the same page (although I have almost given up). The only correction - the PlaceHolder does not have the Add method. It has the Controls collection with the Add method. So to add a control to the PlaceHolder, you have to call it as `this.phMarkupRangeTypePlaceHolder.Controls.Add(this.cbRangeType);` – Andrew Simontsev Jul 20 '16 at 12:19