Dynamic Assembly Loading in .Net 4.0 - c#

My problem begins with moving a .Net 2.0 application to .Net 4.0. The reason I had to do this was that Windows 8 does not enable the earlier .Net versions by default and my application cannot ask the user to enable it.
The application is a NPAPI plugin which uses .Net components via UnmanagedExports. I designed it as a low integrity application and therefore it has to reside in the users 'LocalLow' directory.
In my application I used a dynamic assembly loading mechanism to load several assemblies at runtime. I used the following method to load an assembly,
MyInterface Instance;
Assembly assembly = Assembly.LoadFrom(AssemblyFile);
Type type = assembly.GetType(Identifier); // Identifier is implementing the MyInterface
Instance = Activator.CreateInstance(type) as MyInterface;
// Do something with the Instance
After modifying the project to .Net 4.0, I noticed that the plugin crashes when the binaries are placed inside the LocalLow directory (It works in other places). My next step was to create a minimalistic plugin with least possible code to figure out the issue. I noticed that the dynamic assembly loading failed with the following exception,
System.IO.FileLoadException: Could not load file or assembly '<assemblyPath>' or one of its dependencies. Operation is not supported. (Exception from HRESULT: 0x80131515 (COR_E_NOTSUPPORTED)) --->
System.NotSupportedException: An attempt was made to load an assembly from a network location which would have caused the assembly to be sandboxed in previous versions of the .NET Framework. This release of the .NET Framework does not enable CAS policy by default, so this load may be dangerous. If this load is not intended to sandbox the assembly, please enable the loadFromRemoteSources switch. See http://go.microsoft.com/fwlink/?LinkId=131738 for more information.
I tried the following approaches to create a separate domain and load the assemblies but with no luck,
http://blogs.msdn.com/b/shawnfa/archive/2009/06/08/more-implicit-uses-of-cas-policy-loadfromremotesources.aspx
http://www.west-wind.com/weblog/posts/2009/Jan/19/Assembly-Loading-across-AppDomains
Adding the configuration 'loadFromRemoteSources' did not work either. It seems that the .Net component does not load .dll.config files. (Could be because of UnmanagedExporting)
My questions are,
Is it possible to dynamically load an assembly from LocalLow?
Does the new CAS policy in CLR 4.0 apply to LocalLow as well? From what I understood so far it should affect only assemblies loaded over the network
Is there any other way to overcome this issue?

While it doesn't address your LocalLow issue specifically, if you are able to "read a file" from the directory, you might be able to use the "work around" detailed here:
How can I get LabView to stop locking my .NET DLL?

Related

AssemblyLoadContext.Default in netcore 3.1 resolve the plugin type but can't excute its instance when the plugin use transitive dependency

I have a console application in netcoreapp3.1 that use a netstandard2.0 plugin.
The plugin reference a class library and implement an interface
All dll dependencies are in the the plugin folder and the plugin.dep.json include all referenced library.
When I run:
AssemblyLoadContext.Default.LoadFromAssemblyPath("path/to/main_myplugin.dll");//load plugin
it resolve the type of interface
When i try to run an instance as given below it fail:
if (type != null) //type is resolved and not null
{
var instance = (IContract)Activator.CreateInstance(type); //instance is created
Console.WriteLine($"Create instance : {instance.GetType()}"); // ok instance is created
var ret = instance.Execute(); //!!!fire exception here
Console.WriteLine(ret);
}
and fire error message:
System.IO.FileNotFoundException: 'Could not load file or assembly 'MyLibObjectsLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified.'
If I loaded all dependencies, it works fine.
Should I load all dependencies when using AssemblyLoadContext.Default or it's a bug?
I asked this question in the dotnet project
All credit go to #vitek-karas.
The detailed answer is:
Currently this is by design. LoadFromAssemblyPath as well as any other LoadAssembly-like methods only ever load that assembly, they don't try to load a "plugin". For this case to work you would need the AssemblyDependencyResolver and hook it up to the Default ALC (probably via the Resolving event), and hope that there are no collisions between the host app and the plugin (since they will share all dependencies) and so on. Generally this is why it's better to load plugins into their own ALCs as that creates the necessary isolation and also makes it easy to hook up AssemblyDependencyResolver.
Higher-level answer - in 3.0 we didn't try to provide a "plugin load" API as there were too many open questions in how it should behave (the exact isolation behavior is very tricky to get right so that it would work for most use cases). Instead we provided the necessary building blocks (ALC, ADR, diag improvements, ...) and rely on users to write the cca 20 lines of code to implement the custom ALC. In 5.0 we are improving diagnostics by adding detailed tracing around the entire assembly binding process, that should help debugging issues when loading assemblies in general, but specifically when implementing custom ALCs.

Unable to load assembly when referencing BindingFlags type in Windows 10 Universal Windows library

When running unit tests, calling any method in my portable runtime library DLL that references the "System.Reflection.TypeExtensions" generates a FileNotFound exception, searching for "System.Reflection.TypeExtensions". The error does not occur when the same code is executed in a Windows 10 Universal app.
The project is a C# portable runtime library, configured to support .net Framework 4.6 and Windows Universal 10.0. The Test project is configured to use .net Framework 4.6.
Whenever I attempt to call a method that uses the System.Reflection.BindingFlags type, I get the following exception. The exception occurs as the call starts (presumably while jit-ing the function).
Test method Sfx.Test.SignalExpressionTest.TestAddExpressions threw exception:
System.IO.FileNotFoundException: Could not load file or assembly 'System.Reflection.TypeExtensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.=== Pre-bind state information ===
LOG: DisplayName = System.Reflection.TypeExtensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
(Fully-specified)
Adding those packages is the right thing to do. Here is why you see this behavior:
BindingFlags is currently [1] exposed in System.Reflection.TypeExtensions.
When you compile a .NET Core class library, the compiler records the type reference as System.Reflection.TypeExtensions!System.Reflection.BindingFlags.
When you consume the class library from a .NET Framework application, you need to add a reference to System.Reflection.TypeExtensions otherwise the compiler cannot resolve the type. The same is true for a unit testing project which has to deploy all the code in order to run.
At runtime, the CLR will resolve the type, find a type forward that points to mscorlib!System.Reflection.BindingFlags and happily run your code.
As a general rule of thumb: .NET Core is designed to deploy the framework in an app-local fashion, in other words, when your application is deployed to a folder, the closure of all your dependencies need to be deployed too. Although unit test projects are conceptually class libraries, the same applies because they are executed like applications.
Of course, we don't expect folks to manually tweak the references and hunt down dependencies. What you currently see are pre-release bits where not all pieces in our tooling experiences do the right thing.
Two questions from my side:
Which unit testing framework do you use? I assume it's MSTest (Microsoft.VisualStudio.TestTools.UnitTesting), as opposed to xUnit or NUnit?
Which runner are you using? I assume it's the built-in Visual Studio Test Explorer (as opposed to ReSharper or TestDriven.NET)?
[1] I say currently because based on customer feedback we decided to move it back into System.Reflection, together with the APIs that take BindingFlags.
add reference to nuget packages:
System.Reflection
System.Reflection.Extensions
System.Reflection.Primitives

Can I have my assembly reference any version of another assembly? [duplicate]

This question already has answers here:
Is it possible to replace a reference to a strongly-named assembly with a "weak" reference?
(3 answers)
Closed 4 years ago.
I am developing a class library (MyClassLibrary).
I depend on a third party class library (ThirdPartyClassLibrary).
I need to use the same version of ThirdPartyClassLibrary as my users. e.g., if I set a static value in ThirdPartyClassLibrary the user needs to see that change.
Users of my class may be depending on any one of 4 different versions of ThirdPartyClassLibrary.
ThirdPartyClassLibrary is large, I do not want to distribute it with my software.
I have reflected on all 4 versions of ThirdPartyClassLibrary and validated that the things I will be doing with them are compatible across all versions (interfaces are the same, methods signatures are the same, etc.).
I need calls into ThirdPartyClassLibrary to be performant! I can't reflect on everything every time I need to call something.
MyClassLibrary will be loaded at runtime, so I can't expect users to mess with assembly binding redirects or other develop-time settings (or any settings at all, my users are resistant to doing anything).
I would like to benefit from compile-time checking of my code, so ideally no reflection at all.
How can I write MyClassLibrary such that when it is loaded into the process everything works correctly with whichever version of ThirdPartyClassLibrary the user has loaded?
One workaround would be to use the AppDomain.AssemblyResolve event at runtime. This fires whenever the resolution of an assembly fails. You can use this to load a different version of an assembly to that which the CLR is trying to load.
I've added a very simple demo on GitHub here:
https://github.com/danmalcolm/AssemblyResolutionDemo
This is set up as follows:
The main application App.exe directly references assembly ThirdPartyLibrary.dll version 2.0.0.0.
It also references MyLibrary, which references an older version of ThirdPartyLibrary version 1.0.0.0.
The AppDomain.AssemblyResolve event is used to redirect to the version used by the application when version 1.0.0.0 fails to load
AssemblyResolve is handled as follows:
public static void Initialise()
{
AppDomain.CurrentDomain.AssemblyResolve += ResolveThirdPartyLibrary;
}
private static Assembly ResolveThirdPartyLibrary(object sender, ResolveEventArgs args)
{
// Check that CLR is loading the version of ThirdPartyLibrary referenced by MyLibrary
if (args.Name.Equals("ThirdPartyLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=fbcbfac3e44fefed"))
{
try
{
// Load from application's base directory. Alternative logic might be needed if you need to
// load from GAC etc. However, note that calling certain overloads of Assembly.Load will result
// in the AssemblyResolve event from firing recursively - see recommendations in
// http://msdn.microsoft.com/en-us/library/ff527268.aspx for further info
var assembly = Assembly.LoadFrom("ThirdPartyLibrary.dll");
return assembly;
}
catch (Exception exception)
{
Console.WriteLine(exception);
}
}
return null;
}
We need to bind to the event before ThirdPartyLibrary is loaded, hence the explicit Initialise method.
Note also that the event only fires when the resolution of an assembly fails. If the version of ThirdPartyLibrary referenced by MyClassLibrary (1.0.0.0) were available in the GAC, then it would be loaded successfully and AssemblyResolve wouldn't fire. There would then be 2 different versions in use.
I'm demonstrating here that this mechanism could be used, I'm not saying it's a good idea. There are several things you'd need to take into account based on the environment in which your app is running and how it is set-up / installed / maintained etc.
No, you can't build MyClassLibrary with a reference to ThirdPartyClassLibrary in a way that says "just use whatever version of ThirdPartyClassLibrary.dll is available at runtime".
When you build your library, the version number of any referenced assemblies are included in the assembly manifest. Running the ILDASM tool against your assembly would show something like this:
...
.assembly extern ThirdPartyClassLibrary
{
...
.ver 1:0:0:0
}
...
Both the name and version of ThirdPartyClassLibrary are specified. At runtime, the CLR will attempt to load ThirdPartyClassLibrary.dll when it first runs instructions in MyClassLibrary.dll that reference it. It will look specifically for version 1.0.0.0 of ThirdPartyClassLibrary.dll (and will also require a matching public key if it's a strong-named assembly).
Here's a quick overview of how the CLR locates and binds to assemblies at runtime (full details at http://msdn.microsoft.com/en-us/library/yx7xezcf(v=vs.110).aspx):
Step 1 - Determine the correct assembly version by examining configuration files - we'll return to this below, but for now, if you don't tell it otherwise, the CLR will attempt to load the exact version specified in the referencing assembly, so it will be looking for version 1.0.0.0.
Step 2 - Check whether the assembly name has been bound to before and, if so, uses the previously loaded assembly. Note that "assembly name" in this context includes the name and version, public key token etc, not just the name of the dll file.
Step 3 - Check the Global Assembly Cache GAC (strong-named assemblies only)
Step 4 - Locate the assembly through codebases or probing - essentially the CLR looks in different places to try to find (the specific version of) AssemblyB.dll somewhere. An error will occur if it can't find the specific version. It won't automatically fall back to an earlier or later version.
Unfortunately, this means that things won't "just work" and support what you describe above. If an application that references MyClassLibrary itself references a later version (2.0.0.0) of ThirdPartyClassLibrary, some bad things could happen when resolving MyClassLibrary's reference to ThirdPartyClassLibrary:
The CLR can't find version 1.0.0.0 of AssemblyB used by Assembly A and an error occurs
Version 1.0.0.0 happens to be installed in the GAC and is loaded successfully. While the code in the application is using ThirdPartyClassLibrary version 2.0.0.0, your library is using ThirdPartyClassLibrary version 1.0.0.0.
One thing that you can do is configure the application using your library so that the CLR will unify references to different versions of ThirdPartyClassLibrary.dll to a single version. This brings us back to step 1 of the assembly binding process outlined above - we essentially change the version of ThirdPartyClassLibrary that the CLR is looking for.
Binding redirects (http://msdn.microsoft.com/en-us/library/twy1dw1e.aspx) are designed to channel references to different versions of an assembly to a single version. These are usually defined within an application's configuration file (Web.config, MyApp.exe.config), but can also be defined globally at machine level (machine.config).
Here's an example of a binding redirect that redirects all earlier versions of ThirdPartyClassLibrary.dll to version 2.0.0.0:
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="AssemblyB" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
Note that this can be automatically handled by Visual Studio 2013, which detects cases where different versions of an assembly are referenced and adds the binding redirects for you. There's also an Add-BindingRedirect command available in the NuGet Package Manager Console.
Binding redirects are a possible solution and could be a pragmatic choice in some scenarios. However, they could also confuse users of your library. If practical, you should consider distributing different versions of your library, built against the different versions of the third party library.

Xml.Serializer illegal cast exception in C++ ActiveX control hosted in C# .Net 4.0 Application

I have a C# .Net 4.0 Application hosting a C++ ActiveX control utilizing a C++ DLL with CLR enabled. The DLL has the main function of loading the parameters for the OCX and uses XML.Serializer for this purpose.
This stack is working fine when all components are built in MS Visual Studio .Net 2003 and the C# Application running in .Net 1.1.
However, when the entire modules are migrated to VS2010 and the Application to .Net 4.0, I get the dreaded Xml.Serializer illegal cast exception because of the mismatched context.
The exception occurs at the 4th line:
FileStream* fs = __gcnew FileStream( filename, FileMode::Open );
XmlReader* reader = __gcnew XmlTextReader( fs );
XmlSerializer* serializer = __gcnew XmlSerializer( __typeof(MyClass) );
MyClass* obj = __try_cast<MyClass*>(serializer->Deserialize(reader));
Here's the exception statement:
[A]MyClass cannot be cast to [B]MyClass.
Type A originates from 'ParameterModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' in the context 'Default'
at location 'C:\path\to\module\ParameterModule.dll'.
Type B originates from 'ParameterModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' in the context 'LoadNeither'
at location 'C:\path\to\modu~\ParameterModule.dll'.
at ParameterModule.ParaClass.execute_DeSerialize()
Exception was thrown.
Please note that the 'LoadNeither' context has location path with the tilde (~) character. The 'Default' context has the full path.
The interop DLL for the ActiveX control is automatically generated by VS2010.
I wonder what causes the exception.
Is it the mismatch in Path? I'm not sure, but I think the DLL was loaded only once.
Or is it the mismatch in context?
If it is because of the context mismatch, how do we make sure the loading context for Interop modules like the C++ ActiveX controls?
Or, can we specify Xml.Serializer to load the DLL containing the Serializing classes in the Default context?
I've looked everywhere and I could not find the solution. The more I comb the internet, the more this become a mystery to me. Thanks in advance.
but I think the DLL was loaded only once
No, it got loaded twice. And that's the problem, the identity of a .NET type is not just the namespace + type name, it also includes the assembly it got loaded from. It is a DLL Hell countermeasure, it ensures that you cannot have the same type loaded more than once from different DLLs with a conflicting definition.
The "LoadNeither" context is the cue to your problem. You are somehow loading this assembly in a unusual way. The common way to do so is by using Assembly.LoadFile(), a very dangerous method that should only be used in very special cases where you intentionally don't want types to match. You should always use LoadFrom() instead but really favor Load() when you can. And you usually can by putting the DLL in the right directory or by using the <probing> element in the app.exe.config file.
Getting version 0.0.0.0 isn't very healthy either btw, the [AssemblyVersion] is a very big deal in .NET.
It's odd, but the exception didn't occur when we used static_cast
MyClass* obj = static_cast<MyClass*>(serializer->Deserialize(reader));
Though this answer does not really solve the problem of the module being loaded twice, this workaround might help somebody out there.

How to use Easyhook with non managed executable

I am trying to do some hooking in c# (I'd rather not use Detours or c++) so i have been using EasyHook.
https://easyhook.github.io/
However When i'm doing this
Config.Register( "This description can be anything.", #"SomePathToAnExecutable.exe", "MyInjectionDll.dll");
I get the error:
There was an error while connecting to
target:
System.BadImageFormatException: Unable
to load given assembly
[SomePathToAnExecutable.exe] for
reflection.
Is this a valid NET assembly? --->
System.BadImageFormatException: Could
not load file or assembly
[SomePathToAnExecutable.exe] or one of
its dependencies. The module was
expected to contain an assembly
manifest.
Question 1) Am I right in thinking that SomePathToAnExecutable is the process that you want to hook into???
Question 2) Does the executable have to be managed code then??
I've also asked at on the codeplex project site, but no response.
http://easyhook.codeplex.com/Thread/View.aspx?ThreadId=235616
Answer 1) No. Config.Register registers managed assemblies with the GAC. Thus you register all assemblies participating from your code. This includes the dll you want to inject and the assembly that provides the common interface for the IPCServer. For my it looks like this one for example:
Config.Register("MyHook",
Path.Combine(startupPath, "HookManager.dll"),
Path.Combine(startupPath, "NetworkIncomingHook.dll"),
Path.Combine(startupPath, "NetworkOutgoingHook.dll")
);
The HookManager.dll contains the interface I use to create the IPCServer (and where all messages are send to from the hooked functions). The NetworkIncomingHook.dll and NetworkOutgoingHook.dll are both dlls I inject into my programm. This is done by RemoteHooking.Inject.
2) No. You can hook unmanaged assemblies aswell.

Categories