Exception setting up handler for AppDomain.AssemblyResolve - c#

Create a new appdomain, setup the assemblyResolve handler and
you always get an exception saying 'assembly [current executing assembly] not found'
what gives ? code is below
string _fileName = #"c:\temp\abc123.dll";
AppDomain sandBox = AppDomain.CreateDomain("sandbox");
sandBox.AssemblyResolve += new ResolveEventHandler(sandBox_AssemblyResolve);
// the line generates the exception !
System.Reflection.Assembly asm = sandBox.Load(System.Reflection.AssemblyName
.GetAssemblyName(fileName).FullName);
foreach (System.Reflection.AssemblyName ar in asm.GetReferencedAssemblies())
dbgWrite("Ref: " + ar.FullName );
System.Reflection.Assembly sandBox_AssemblyResolve
(object sender, ResolveEventArgs e)
{
System.Reflection.Assembly asm =
System.Reflection.Assembly.LoadFrom(_fileName);
return asm;
}
exception is:
System.IO.FileNotFoundException: Could not load file or assembly 'appAdmin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified. File name: 'appAdmin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' [snip]

Your resolver may not fire on your new AppDomain, try setting it on the AppDomain.CurrentAppDomain instead.
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(sandBox_AssemblyResolve);
In the sandBox_AssemblyResolve method you can load the assembly up from whatever directories you like, this is where the load from a byte[] may come into play.
As for the loading of an Assembly using byte[] this fixes file locking issues, it won't fix what ails you I don't think see here

You're trying to load assemblies that aren't under the AppDomain's base location. I've never had the AssemblyResolve event work for me, either.
I'd suggest loading your out-of-base assembly into a byte array (System.IO.File.ReadAllBytes) and then hand that array to your newly created AppDomain to load.

Related

Could not load file or assembly but they are loaded

I have a project going on witch uses a DLL from an ERP system.
The DLL is used to get information from the ERP, like invoices and such.
The error i am getting is:
Inner Exception 1: FileNotFoundException: Could not load file or
assembly 'SnelStartGatewayInterface, Version=12.48.37.0,
Culture=neutral, PublicKeyToken=null' or one of its dependencies. The
system cannot find the file specified.
But in the same window I used 'watch 1' to see the current using assembly's with the method:
AppDomain.CurrentDomain.GetAssemblies()
It returns a couple of assembly's.
This is the one loaded in and exactly the same as seen in the error:
+ [36] {SnelStartGatewayInterface, Version=12.48.37.0, Culture=neutral, PublicKeyToken=null} System.Reflection.Assembly
{System.Reflection.RuntimeAssembly}
Why would it return me the error?
Ps. I have tried the exact same method and dll in a windows forms test app and it was running fine.
Like Pawl Lukasik mentioned in the comments, you should look at the dependencies.
To do this, use:
private List<string> ListReferencedAssemblies()
{
List<string> refList = new List<string>();
var assemblies = Assembly.GetExecutingAssembly().GetReferencedAssemblies();
foreach (var assembly in assemblies)
{
refList.Add(assembly.Name);
}
return refList;
}
to see all referenced assemblies.
Or with LINQ:
private List<string> ListReferencedAssemblies()
{
return Assembly.GetExecutingAssembly().GetReferencedAssemblies().Select(x => x.FullName).ToList();
}

Instantiating a class produces ReflectionTypeLoadException at Assembly.GetTypes()

I discovered that after my application generates Telerik report
var result = new ReportProcessor().RenderReport("PDF", new InstanceReportSource { ReportDocument = new MyTelerikReport(data) }, null);
var stream = new MemoryStream(result.DocumentBytes);
return CreateHttpFileResponse("MyReport.pdf", stream, "application/pdf");
I am not able to get all types within CurrentDomain
var typesWithAttribute = (from a in AppDomain.CurrentDomain.GetAssemblies()
from t in a.GetTypes() //error appears here
//some filtering logic
select t).ToList();
I am getting error
System.Reflection.ReflectionTypeLoadException: Unable to load one or
more of the requested types. Retrieve the LoaderExceptions property
for more information.
LoaderExceptions:
System.IO.FileNotFoundException: Could not load file or assembly
'DocumentFormat.OpenXml, Version=2.0.5022.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The
system cannot find the file specified. File name:
'DocumentFormat.OpenXml, Version=2.0.5022.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35'
After some investigation I found that assembly that fails to load: Telerik.Reporting.OpenXmlRendering, Version=8.0.14.311, Culture=neutral, PublicKeyToken=a9d7983dfcc261be and that assembly doesn't exists in AppDomain.CurrentDomain.GetAssemblies() before I generate report (I assume that assembly loaded dynamically by Telerik.Reporting, Version=8.0.14.311, Culture=neutral, PublicKeyToken=a9d7983dfcc261be).
I could filter out that assembly as I don't need any types from that but I am a bit worried about fact of having assemblies in domain that cannot be loaded - seems a bit wrong to me.
Could someone explain what there happens? Is it my issue or that is fault of 3rd party library that doesn't load all required assemblies?
The issue is not the assembly but the Type coming from a dependent assembly that has not been loaded.
If the GetTypes method is called on an assembly and a type in that assembly is dependent on a type in an assembly that has not been loaded (for example, if it derives from a type in the second assembly), a ReflectionTypeLoadException is thrown.
http://msdn.microsoft.com/en-us/library/system.reflection.assembly.gettypes(v=vs.110).aspx

Service reports 'cannot find the file specified' for a file that exists

I'm writing C# code that can run either as a console app or a service. When run as a console app, it works fine. When run as a service I'm getting an odd error.
On startup, my service spawns a thread and this thread searches a directory for plugin .dll's that implement some of the service's functionality. I enumerate the files in the plugin directory, then for each file found, attempt to load the assembly and determine if it implements a desired interface.
This architecture is described here: http://code.msdn.microsoft.com/windowsdesktop/Creating-a-simple-plugin-b6174b62
I'm finding that I can enumerate all of my plugins, but when I call Assembly.GetTypes(), I get a LoaderException with the message: "Could not load file or assembly 'MyProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified."
Well, that's bunk because in the line of code just before this one, the file was enumerated from a call to Directory.GetFiles(path, "*.dll"). Remember, this code also works find when run as a console app.
My service is running as Local System and the SYSTEM account has full permissions to the files, as do Administrators. Per this page, Local System's token includes both the NT AUTHORITY\SYSTEM and BUILTIN\Administrators SID, so I don't think it's a filesystem permissions issue.
I'm flummoxed. Can anyone suggest a cause and a solution?
Here's the code (it looks long but a lot of it is logging):
private void LoadPlugins()
{
lstPlugins = new List<MyDesiredInterface>();
string path = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
path += "\\PlugIns";
if (Directory.Exists(path))
{
Log("PlugIns folder exists.", TAG);
string[] dllFileNames = Directory.GetFiles(path, "*.dll");
ICollection<Assembly> assemblies = new List<Assembly>(dllFileNames.Length);
foreach (string dllFile in dllFileNames)
{
AssemblyName an = AssemblyName.GetAssemblyName(dllFile);
Assembly assembly = Assembly.Load(an);
assemblies.Add(assembly);
}
Log("Found " + assemblies.Count + " assemblies.", TAG);
Type pluginType = typeof(MyDesiredInterface);
ICollection<Type> pluginTypes = new List<Type>();
foreach (Assembly assembly in assemblies)
{
if (assembly != null)
{
Log("Evaluating assembly: " + assembly.Location, TAG);
try
{
Type[] types = assembly.GetTypes(); <-- error happens here
foreach (Type type in types)
{
if (type.IsInterface || type.IsAbstract)
{
Log("Assembly does not implement our interface.", TAG);
continue;
}
else
{
if (type.GetInterface(pluginType.FullName) != null)
{
Log("Assembly implements our interface!", TAG);
pluginTypes.Add(type);
}
}
}
}
catch (ReflectionTypeLoadException ex)
{
StringBuilder errMsg = new StringBuilder("An exception occurred tying to load types in an assembly.\r\n");
errMsg.Append("The assembly is: " + assembly.Location + "\r\n");
errMsg.Append("Exceptions are:\r\n");
foreach (Exception e in ex.LoaderExceptions)
{
errMsg.Append(e.Message + "\r\n");
}
Log(errMsg.ToString(), TAG);
}
}
}
foreach (Type type in pluginTypes)
{
MyDesiredInterface plugin = (MyDesiredInterface)Activator.CreateInstance(type);
this.Log("Loading plugin: " + plugin.CommandName(), TAG);
plugin.Register(this);
lstPlugins.Add(plugin);
}
this.Log("Total plugins loaded: " + lstPlugins.Count, TAG);
}
else
{
Log("PlugIns folder not found.", TAG);
}
}
Here's the log file:
3/12/2014 9:53:46 AM chatInterface LoadPlugIns()
3/12/2014 9:53:46 AM chatInterface PlugIns folder exists.
3/12/2014 9:53:46 AM chatInterface Found 13 assemblies.
3/12/2014 9:53:46 AM chatInterface Evaluating assembly: C:\Users\MyUsername\Documents\Visual Studio 2010\Projects\MyProject\MyProjectService\bin\Debug\PlugIns\PlugIn1.dll
3/12/2014 9:53:46 AM chatInterface An exception occurred tying to load types in an assembly.
The assembly is: C:\Users\MyUsername\Documents\Visual Studio 2010\Projects\MyProject\MyProjectService\bin\Debug\PlugIns\PlugIn1.dll
Exceptions are:
Could not load file or assembly 'MyProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
3/12/2014 9:53:46 AM chatInterface Evaluating assembly: C:\Users\MyUsername\Documents\Visual Studio 2010\Projects\MyProject\MyProjectService\bin\Debug\PlugIns\PlugIn2.dll
3/12/2014 9:53:46 AM chatInterface An exception occurred tying to load types in an assembly.
The assembly is: C:\Users\MyUsername\Documents\Visual Studio 2010\Projects\MyProject\MyProjectService\bin\Debug\PlugIns\PlugIn2.dll
Exceptions are:
Could not load file or assembly 'MyProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
It was suggested that I use the Assembly Binding Log Viewer (fuslogvw.exe) to log the failures. Here's what that log shows:
*** Assembly Binder Log Entry (3/13/2014 # 9:50:30 AM) ***
The operation was successful.
Bind result: hr = 0x0. The operation completed successfully.
Assembly manager loaded from: C:\Windows\Microsoft.NET\Framework\v2.0.50727\mscorwks.dll
Running under executable C:\Users\MyUsername\Documents\Visual Studio 2010\Projects\MyProject\MyProjectService\bin\Debug\MyProjectService.exe
--- A detailed error log follows.
=== Pre-bind state information ===
LOG: User = NT AUTHORITY\SYSTEM
LOG: Where-ref bind. Location = C:\Users\MyUsername\Documents\Visual Studio 2010\Projects\MyProject\MyProjectService\bin\Debug\PlugIns\MyPlugIn.dll
LOG: Appbase = file:///C:/Users/MyUsername/Documents/Visual Studio 2010/Projects/MyProject/MyProjectService/bin/Debug/
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = NULL
Calling assembly : (Unknown).
===
LOG: This bind starts in LoadFrom load context.
WRN: Native image will not be probed in LoadFrom context. Native image will only be probed in default load context, like with Assembly.Load().
LOG: No application configuration file found.
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v2.0.50727\config\machine.config.
LOG: Attempting download of new URL file:///C:/Users/MyUsername/Documents/Visual Studio 2010/Projects/MyProject/MyProjectService/bin/Debug/PlugIns/MyPlugIn.dll.
LOG: Assembly download was successful. Attempting setup of file: C:\Users\MyUsername\Documents\Visual Studio 2010\Projects\MyProject\MyProjectService\bin\Debug\PlugIns\MyPlugIn.dll
LOG: Entering run-from-source setup phase.
LOG: Assembly Name is: MyPlugIn, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
LOG: Re-apply policy for where-ref bind.
LOG: Binding succeeds. Returns assembly from C:\Users\MyUsername\Documents\Visual Studio 2010\Projects\MyProject\MyProjectService\bin\Debug\PlugIns\MyPlugIn.dll.
LOG: Assembly is loaded in LoadFrom load context.
In this test run, I was using Assembly.LoadFrom() instead of Assembly.Load(), but in both cases the assembly loads. This log shows it in LoadFrom load context, I have other runs that show it in Load load context with the other call. In any case, the load succeeds, but attempting to enumerate GetTypes fails with "The system cannot find the file specified."
Any help would be appreciated!
Please check if you are referencing an assembly which in turn referencing an older version. Delete, rebuild and re-referencing might help.
"FuseLogVw" is helpful to find who is loading your assemblies, define the log path, and run your solution, then check first line in FuseLogVw
From http://msdn.microsoft.com/en-us/library/ky3942xh(v=vs.110).aspx:
"FileLoadException is thrown if assemblyString specifies the full assembly name, and the first assembly that matches the simple name has a different version, culture, or public key token. The loader does not continue probing for other assemblies that match the simple name."
So are there multiple versions of the assembly present?

Error when I load a workflow from the instance store. Type is not found

I'm having problems when I try to load a workflow from the instance store. Its seems that it can't deserialize this workflow.
This is my code:
//Get workflow through WorkflowDefinitionManager
Activity workflow = WorkflowDefinitionManager.GetWorkflow(wfDefinitionId);
//Create wf application
WorkflowApplication instance = new WorkflowApplication(workflow);
instance.InstanceStore = InstanceStore;
instance.Completed += WorkflowApplication_OnCompleted;
instance.Aborted += WorkflowApplication_OnAborted;
instance.Idle += WorkflowApplication_OnIdle;
instance.OnUnhandledException += WorkflowApplication_OnUnhandledException;
instance.PersistableIdle += WorkflowApplication_OnPersistableIdle;
instance.Load(inGuid); //<--- I get the error here
Error:
The deserializer cannot load the type to deserialize because type 'System.Activities.Variable`1+VariableLocation[[MYCLASS, MYASSEMBLY, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' could not be found in assembly 'System.Activities, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'. Check that the type being serialized has the same contract as the type being deserialized and the same assembly is used.
I don't understand why I get this error if I can start and persist the workflow
before. Could you help me? Please
Thanks
There could be a couple of reasons.
The most common is that the workflow definition changed between the time it was persisted and the time you are reloading it. This is a no go at the moment.
Another possibility is that the workflow was started on one machine and later resumed on another machine that doesn't have all required assemblies to resume it.
The other possibility is that the type in question was already loaded because of some other code executing the first time and is not loaded when you reload the workflow state. Now normally the assembly would just be found and loaded using the CLR rules but it might not be available using normal rules.
Finally I solved my errors resolving the assemblies in runtime:
AppDomain appDomain = AppDomain.CurrentDomain;
appDomain.AssemblyResolve += AppDomain_AssemblyResolve;
instance.Load(inGuid);
appDomain.AssemblyResolve -= AppDomain_AssemblyResolve;
This is the callback:
private Assembly AppDomain_AssemblyResolve(object sender, ResolveEventArgs e)
{
try
{
string strTempAssmbPath = ExtensionsFolder + e.Name.Substring(0, e.Name.IndexOf(",")) + ".dll";
return Assembly.LoadFile(strTempAssmbPath);
}
catch (Exception ex)
{
log.Error(ex);
}
return null;
}

InvalidCastException for two Objects of the same type

I have this weird problem that I cannot handle myself. A class in the model of my mvp-project designed as singleton causes an InvalidCastException.
The source of error is found in this code line where the deserialised object is assigned to the instance variable of the class: engineObject = (ENGINE)xSerializer.Deserialize(str);. It occurs whenever I try to add one of my UserControls to a Form or to a different UC. All of my UCs have a special presenter that accesses the above mentioned instance variable of the singleton class.
This is what I get when trying to add a UC somewhere:
'System.TypeInitializationException: The type initializer for 'MVP.Model.EngineData' threw an exception. ---->
System.InvalidCastException: [A]Engine cannot be cast to [B]Engine. Type A originates from 'MVP.Model, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' in the context 'LoadNeither'
at location '[...]\AppData\Roaming\Microsoft\VisualStudio\9.0\ProjectAssemblies\uankw1hh01\MVP.Model.dll'.
Type B originates from 'MVP.Model, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' in the context 'LoadNeither'
at location '[...]\AppData\Roaming\Microsoft\VisualStudio\9.0\ProjectAssemblies\u_hge2de01\MVP.Model.dll'
...
So I somehow have two assemblies and they are not accessed from my project folder, but from a VS temp folder? I googled a lot and only found this: IronPython Exception: [A]Person cannot be cast to [B]Person. There is a solution offered, but it concerns IronPhyton and I don't know where to use it within my project.
Types are per-assembly; if you have "the same" assembly loaded twice, then types in each "copy" of the assembly are not considered to be the same type.
These issues normally crop up when the two assemblies are in the Load and LoadFrom contexts. See
Difference between LoadFile and LoadFrom with .NET Assemblies?
and the link to suzcook's blog for details on that issue.
Also, consider using the fusion log viewer to help diagnose the problem.
http://msdn.microsoft.com/en-us/library/e74a18c4%28VS.71%29.aspx
Judging by the context in which the assembly is getting loaded (the context is "LoadNeither"), some developers may be doing something like loading an assembly that has been internally packaged as a resource with your application. If you do this, you will be using the AppDomain.CurrentDomain.AssemblyResolve event handler, so that your application can specify where .NET should get any particular assembly that it needs.
My answer will not explain the machinations of how to do that - but I'm mentioning it because this process led directly to the same exact error encountered by the original poster. As Eric Lippert mentions, types are per-assembly. So if you load an individual assembly more than once, the same defined class will appear as different classes - even though visual inspection shows that they appear to be the same.
We've seen instances in which .NET will call the ResolveEventHandler more than once for the same DLL. I'm not sure why .NET sometimes does this (it happened on some machines, but not all machines). But to resolve the problem, we needed keep a global list of handles to loaded assemblies, so that if .NET wanted to load the assembly again, we returned a handle to the same Assembly that was originally loaded, instead of loading another copy into memory.
I have included the code that caused the issue for us, and notes about how to handle it properly.
public void AppStartup (object sender, StartupEventArgs e)
{
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}
public System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string dllName = args.Name.Contains(',') ? args.Name.Substring(0, args.Name.IndexOf(',')) : args.Name.Replace(".dll", "");
dllName = dllName.Replace(".", "_");
if (dllName.EndsWith("_resources")) return null;
System.Resources.ResourceManager rm = new System.Resources.ResourceManager(GetType().Namespace + ".Properties.Resources", System.Reflection.Assembly.GetExecutingAssembly());
byte[] bytes = null;
try
{
bytes = (byte[])rm.GetObject(dllName);
}
catch (Exception ex)
{
}
if (bytes != null)
{
// the following call will return a newly loaded assembly
// every time it is called
// if this function is called more than once for the same
// assembly, you'll load more than one copy into memory
// this can cause the InvalidCastException
// instead of doing this, you keep a global list of loaded
// assemblies, and return the previously loaded assembly
// handle, instead of loading it again
return System.Reflection.Assembly.Load(bytes);
}
return null;
}
My situation involved two copies of the same dll. One was in the bin folder and one was in a sub-folder of the same bin folder. Both were loaded, amazingly some things worked fine, but some things didn't and that's when this error message appeared:
System.InvalidOperationException; There was an error generating the XML document.; Source: System.Xml; TargetSite: Void Serialize(System.Xml.XmlWriter, System.Object, System.Xml.Serialization.XmlSerializerNamespaces, System.String, System.String);
Hidden in this was the following inner exception (this was to do with Microsoft Dynamics CRM 4.0, but could relate to anything)
System.InvalidCastException; [A]XXX.CRMCustomCode.YYY.CreateCompanyRequest cannot be cast to [B]XXX.CRMCustomCode.YYY.CreateCompanyRequest. Type A originates from 'XXX.CRMCustomCode, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null' in the context 'LoadFrom' at location 'C:\Program Files\Microsoft CRM\Server\bin\assembly\XXX.CRMCustomCode.dll'. Type B originates from 'XXX.CRMCustomCode, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null' in the context 'Default' at location 'C:\Program Files\Microsoft CRM\Server\bin\XXX.CRMCustomCode.dll'.;
I simply deleted the duplicate dll (in C:\Program Files\Microsoft CRM\Server\bin) and the error went away.
My particular case - class library referenced in web application was renamed and rebuilt. Older version of library was still in bin folder under old name. The framework loads whatever in bin folder (both libraries) and emits this error. So it happens not only when assemblies are loaded explicitly.
The obvious solution in my case is to clean bin folder.
I got it working when I tried changing this cast:
var t = (TeacherWebPages)Session["TeachersAD"];
To this:
var t = Session["TeachersAD"] as TeacherWebPages;
However the assembly/session/memcache was different and no data got back but no error occurred. So later I still had to delete specific temporary files every time source page was changed from the folder it was complaining about which would require me to kill IIS process from task manager. Or in my case I can just logout and it clears the session state.

Categories

Resources