How to intercept "Could not load file or assembly"? - c#

During testing of a command line based program I delibrately removed a DLL from the execution directory. This of course caused the Could not load file or assembly exception to trigger when the program started, and dumped the raw exception details onto the command line:
Unhandled Exception: System.IO.FileNotFoundException: Could not load
file or assembly 'MyDLL, Version=1.2.3.14056, Culture
=neutral, PublicKeyToken=0a0932194e205074' or one of its dependencies. The system cannot find the file specified. at
MyApp.Program.Program.Main(String[] args)
I don't want the user to see these raw details, but I can't see how/where to catch this exception in order to sanitize the presented message.
So what is the best/accepted way to catch something like this?

You can register to the Unhandled Exception handler and treat it like so:
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler((x, y) =>
{
var exception = y.ExceptionObject as Exception;
if (exception is System.IO.FileNotFoundException)
Console.WriteLine("Please make sure the DLL is in the same folder.");
});
Make sure this event registration is executed before any reference to MyDLL in your code. A static constructor in Program.cs might be a good option.

Related

Troubleshooting Unity IoC container exception ("The given assembly name or codebase was invalid")

In my codebase, I have created a container sucessfully, but then run into an exception when trying to configure it:
_container = new UnityContainer();
var unityConfigurationSection = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
if (unityConfigurationSection != null)
{
try
{
unityConfigurationSection.Configure(_container);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
the unityConfigurationSection.Configure(_container); line is what does me in. I get:
The given assembly name or codebase was invalid. (Exception from HRESULT: 0x80131047)
It looks like there's a type that can't be resolved from its name, judging from the stack trace.
But how do I figure out what type?
The exception indicates that the name of the assembly that was requested is in some way not able to be parsed and looked up. If the assembly name was valid but it just wasn't found you'd get a different error.
Usually the message of the exception includes the assembly that failed to resolve.
For instance, this code throws the exact exception:
var asm = Assembly.Load("test,,;''");
This is obviously not a valid assembly name, so you get:
System.IO.FileLoadException: 'Could not load file or assembly '"test\,\,;''"' or one of its dependencies. The given assembly name or codebase was invalid. (Exception from HRESULT: 0x80131047)'
I'd debug the code and see if you can get to the message of the exception.
One thing I'd try is to go into Tools -> Options -> Debugging -> Enable Just My Code and remove the check mark. This should let you see the unwrapped exception that gets thrown when Unity tries to resolve the dependency.
Another quick approach would be to handle the AssemblyResolve Event. Whenever an assembly that was looked for by name fails to resolve for whatever reason that Event is invoked. The args parameter contain the name of the assembly that was tried to be resolved.
Put this as the first line in your Program:
AppDomain.CurrentDomain.AssemblyResolve += Resolver;
and then put this method into the same class:
private static Assembly Resolver(object sender, ResolveEventArgs args)
{
string assemblyName = args.Name;
throw new Exception(args.Name);
}
Now you can set a breakpoint and check out the name of the assembly that tried to get resolved.

CS-Script persistent cache for better performance when loading scripts

Is there a way to persist CS-Script internal assembly cache between subsequent application's runs?
Used component: http://www.csscript.net/
The desired behavior is:
when I compile an assembly form a script string and I close the application, the next time I run the application the compiled assembly with matching script string is found and no recompilation is needed.
This question is follow-up of another question:
Is there a way to call C# script files with better performance results?
Here is my code, but every script string requires recompilation with every restart of parent .NET application.
public interface ICalculateScript
{
Exception Calculate(QSift qsift, QSExamParams exam);
}
...
void Calculate(string script)
{
CSScript.CacheEnabled = true;
//Can following command use built-in cache to load assembly, compiled by this line of code, but by another instance of this app which run in the past and has been meanwhile closed?
Assembly assembly = = CSScript.LoadCode(script, null);
AsmHelper asmHelper = new AsmHelper(assembly);
ICalculateScript calcScript = (ICalculateScript)asmHelper.CreateObject("Script");
calcScript.Calculate(this, exam);
}
Related problem:
The folder of temp scripts created by Cache in CS Script C:\Users\vdohnal\AppData\Local\Temp\CSSCRIPT\Cache\2015108000 has 41 MB and growing with files few months old.
In the output window of WPF App there are first chance exceptions:
A first chance exception of type 'System.IO.FileLoadException' occurred in mscorlib.dll
A first chance exception of type 'System.IO.FileLoadException' occurred in mscorlib.dll
A first chance exception of type 'System.IO.FileLoadException' occurred in mscorlib.dll
A first chance exception of type 'System.IO.FileLoadException' occurred in mscorlib.dll
A first chance exception of type 'System.IO.FileLoadException' occurred in mscorlib.dll
'ESClient.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:\Users\vdohnal\AppData\Local\Temp\CSSCRIPT\Cache\2015108000\af621e10-d711-40d7-9b77-0a8e7de28831.tmp.compiled'
C:\Users\vdohnal\AppData\Local\Temp\CSSCRIPT\Cache\2015108000
I got an answer fom Oleg Shilo which pointed me in the right direction:
The cache folder indeed grows as new scripts are compiled/loaded. This
is the nature of the caching. It seems that it "grows without control"
though it is not. Once cache is created for a given script file it is
never duplicated and the new cache update is always written over the
existing one.
The problem in your case is that every time you load the file you give
it a unique name thus you are creating a new unique cache. To fix it
you need to start using the same name for the script file every time
you load/execute it.
Alternatively you can completely take over the caching location and
specify what ever cache name you want. It is that second parameter
that you pass null for:
Assembly assembly = CSScript.LoadCode(script, null);
I used following code:
if (assemblyFileName == null)
assembly = CSScript.LoadCode(script, null); //In case there is no name specified - when my custom temp folder cannot be created etc.
else
assembly = CSScript.LoadCode(script, assemblyFileName, false, null); //Specify full path and file name with extension
Thanks to this I have complete control over cached assembly name and location.
If cached assembly with appropriate script already exists, I can simply load it instead of compiling a new one:
Assembly assembly = Assembly.LoadFrom(assemblyFileName);
AsmHelper asmHelper = new AsmHelper(assembly)
The speed of initial loading is better and there is no uncontrollably growing cache.

Is there a way I can safely check to see if an assembly CAN be loaded before I actually do so?

I am working on some software that will dynamically build menu items for certain dlls so that we can load components in dynamically based on what dlls are available on the users machine. Any dlls that I want to load have been flagged with an Assembly Attribute in the AssemblyInfo.cs file and how I determine whether or not I want to build a menu item for that dll. Here is my method so far:
private void GetReportModules() {
foreach (string fileName in Directory.GetFiles(Directory.GetCurrentDirectory())) {
if (Path.GetExtension(fileName) == ".dll" || Path.GetExtension(fileName) == ".exe") {
System.Reflection.Assembly assembly = System.Reflection.Assembly.LoadFrom(fileName);
object[] attributes = assembly.GetCustomAttributes(typeof(ReportNameAttribute), false);
if (attributes.Count() > 0) {
ReportNameAttribute reportNameAttribute = attributes[0] as ReportNameAttribute;
Type type = assembly.GetType(reportNameAttribute.BaseType);
MenuItem customReportsMenuItem = new MenuItem();
customReportsMenuItem.Header = reportNameAttribute.ReportName;
ReportsMenuItem.Items.Add(customReportsMenuItem);
customReportsMenuItem.Click += (s, ev) => {
var obj = Activator.CreateInstance(type);
type.InvokeMember("Show", System.Reflection.BindingFlags.Default | System.Reflection.BindingFlags.InvokeMethod, null, obj, null);
};
}
}
}
}
For the most part its working fine, I am getting the dlls that I am expecting back out and am creating my menu items fine. The problem is that in order to check for the attribute I first need to load the assembly using Reflection. Some of the other local dlls are throwing errors when I try to load them about missing dependencies or he module was expected to contain an assembly manifest. Is there a way I can safely check to see if an assembly CAN be loaded before I actually do so? (sounds stupid as I write it out). Any thoughts on the problem I'm running into or better suggestions for how to accomplish what I'm trying here? Feeling a little bit in over my head.
You can create a separate AppDomain, try to load the assemblies there, send the results back, and unload the AppDomain. This way you do not change your current AppDomain with 'garbage' of any loaded assemblies.
One way would be to make use of a try catch block. If it throw's an exception, you're not interested...
EDIT:
MSDN explains clearly the type of exceptions LoadFrom can throw. FileLoadException looks likely in your case.
I'm sure there is code out there that carried on after a catch. For example a logging framework. I would not want my framework to catch an exception and make my executable stop etc, i'd want it to smother the exception. My application should not fail just because a line of log miss fired.
You can try the Unmanaged Metadata API (http://msdn.microsoft.com/en-us/library/ms404384.aspx) or the Common Compiler Infrastructure Metadata API (http://ccimetadata.codeplex.com/) as alternatives to plain reflection.

How to get Type value from assembly

I have the lines of code shown below
Can anybody provide me the code which will create type value as shown below
The exception I get is: " ex = {"Could not load file or assembly , Version=0.0.0.0, Culture=neutr..."
If you do have the file: _UNIX_Linux_TesterTEST-MACHINE.dll, then you should look for the libraries that this one depends on. One way to find out which they are is to run Fuslogw.exe(the Assembly Binding Log Viewer).
/Tibi

FileNotFoundException on MyProject.resources

I am trying to add an image to a button (C# Winform, VS2010). I have added the resource by Adding Existing Item in the Resources.resx file. I then assign my image to the button and all appears well. When i run my program i get:
An unhandled exception of type 'System.IO.FileNotFoundException' occurred in mscorlib.dll
Additional information: Could not load file or assembly 'BmsReplayAnalysis.resources, Version=1.0.0.0, Culture=en-US, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
in this code:
public static System.Drawing.Bitmap play1 {
get {
object obj = ResourceManager.GetObject("play1", resourceCulture); <-- DIES HERE
return ((System.Drawing.Bitmap)(obj));
}
}
Can anyone tell me what i am doing wrong?
When you just give it a name of a file, when you run it, it looks for it in the folder that it is running out of. If you are running in debug mode, it will look for play1 inside the debug folder. if its not there its an error.

Categories