Rupreet's Weblog

Looking deep inside under the hood

  Home  |   Contact  |   Syndication    |   Login
  14 Posts | 0 Stories | 45 Comments | 58 Trackbacks

News

Archives

Post Categories

Setting the context…

We have a web application which communicates with WCF based service façade for any business functionality. This service façade then loads assembly (based on configuration) at the runtime for making the system pluggable. By default the implementation is in the service assembly itself. Below is the sample code for loading the assembly and creating an instance of the desired class.

 

Assembly asm = Assembly.LoadFrom(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, assemblyName));

if (asm != null)

{

     Type type = asm.GetType(typeName));

     if (type != null)

     {

         return Activator.CreateInstance(type);

      }

}

 

Testing this code from a console application works like a charm but when the service façade is integrated with the web application, we get the below error:

[A]<Type> cannot be cast to [B]<Type>. Type A originates from <assembly> in the context 'Default' at location 'C:\Windows\Microsoft.NET\Framework\v4.0.21006\Temporary ASP.NET Files\root\10e649fb\634e3b21\assembly\dl3\9f96095e\325f141a_f8aaca01\<assemblydllName>. Type B originates from <assembly> in the context 'LoadNeither' at location 'D:\<myproject>\ \bin\<assemblydllName>.

 

Debugging the issue…

In the initial debugging, everything seemed correct and on inspecting the “type” of the object, it seems correct but the cast failed. When nothing helped, I revered back to the debugging basics – read the error message clearly.

The error message said - Type A originates from <assembly> in the context 'Default' at location 'C:\Windows\Microsoft.NET\Framework\v4.0.21006\Temporary ASP.NET Files\root\10e649fb\634e3b21\assembly\dl3\9f96095e\325f141a_f8aaca01\abc.dll Type B originates from <assembly> in the context 'LoadNeither' at location 'D:\work\Projects\<Project>\bin\ abc.dll.

Now – from the message we can see the abc.dll (name changed) is getting loaded twice in the application domain and from two different locations. To verify this, I debugged the application again and saw the output window which shows the assembly getting loaded again from a different location. Below is the content of the output window:

 

'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Web.DynamicData\v4.0_4.0.0.0__31bf3856ad364e35\System.Web.DynamicData.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.

 

'WebDev.WebServer40.EXE' (Managed (v4.0.21006)): Loaded

 

'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\Microsoft.CSharp\v4.0_4.0.0.0__b03f5f7f11d50a3a\Microsoft.CSharp.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.

 

'WebDev.WebServer40.EXE' (Managed (v4.0.21006)): Loaded

 

'D:\work\Projects\<Project>\bin\ abc.DLL', Symbols loaded.

 

'WebDev.WebServer40.EXE' (Managed (v4.0.21006)): Loaded

 

'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.WorkflowServices\v4.0_4.0.0.0__31bf3856ad364e35\System.WorkflowServices.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.

 

We have same assembly, loaded twice in the app domain from two different locations. When the managed environment tries to type cast the objects, it throws this error.

Conclusion:
To answer as to why the assembly loaded twice in the application domain – it is because the first assembly was loaded by the web application while calling the service façade and it was loaded from the web application temporary location. The assembly was loaded again by the code mentioned above is because we are using “LoadFrom” where we specify the path of the assembly from it needs to be loaded from and this by-passes the assembly probing mechanism. While loading this assembly, CLR thinks this assembly is a different assembly from the previously loaded assembly because the context of both the assemblies is different. Hence the type casting between these type from different assemblies fails.

How to fix?
To fix this issue, we should use Assembly.Load instead of Assembly.LoadFrom where CLR will probe the assembly and load it correctly, if not already loaded. Below code is the recommended code to load the assembly

Assembly asm = Assembly.Load(assemblyName); //assembly name is full assembly name

if (asm != null)

{

     Type type = asm.GetType(typeName));

     if (type != null)

     {

         return Activator.CreateInstance(type);

      }

}

 

 

posted on Tuesday, February 16, 2010 12:49 AM

Feedback

# sorenha 2/17/2010 12:22 AM pro duo memory stick
Thanks. I just tried that and it gives me the same "Strong name validation failed" although I point it to the correct assembly: var assemblyName = AssemblyName.GetAssemblyName(correctFileName); var assembly = Assembly.Load(assemblyName); I'm thinking this is because the correctFileName is outside the app CodeBase folder. I guess I'll just leave it and go a different route

# re: Avoid Assembly.LoadFrom; instead use Assembly.Load 2/17/2010 9:57 PM Rupreet
Sorenha - can you please explain the problem a bit more. What exactly are you trying to do and what issue you facing? I can see if i can help you with it.

# re: Avoid Assembly.LoadFrom; instead use Assembly.Load 5/23/2010 1:38 PM Atmapuri
This all makes sense up to one point. When the application starts it makes a copy of assemblies needed to the C:\Users\..\AppData\...\Project Assemblies\XXX\MyDll.dll. If there is a designer assembly in need of that dll, you get the same error message when trying to invoke the designer, if the MyDll.dll is also in the assembly root search path:

HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\AssemblyFolders

How to prevent the VS.IDE from making a copy of assemblies needed to its Project Assemblies\ folder? It does not happen for the framework assemblies for example, so there must be a way.



# re: Avoid Assembly.LoadFrom; instead use Assembly.Load 10/23/2012 9:12 PM Cristian
Thanks for this post. This worked for me. But using the "Assembly.Load(assemblyName)" method I've seen that at present this method is deprecated. Is there another alternative to use and avoid the above issue?

Post A Comment
Title:
Name:
Email:
Comment:
Verification: