I'm loading an Assembly dinamically using:
Assembly _assembly = Assembly.ReflectionOnlyLoadFrom(PathToDllAssembly);
And I can check the Class and/or Methods names.
In order to access Methods i have to Load the assembly:
Assembly _assembly = Assembly.LoadFile(PathToDllAssembly);
But it is possible to get a String value inside the Assembly without actually load it or load it in a ReflectionOnly context?
Edit:
Just so you know and maybe you can point me in the right direction, I'm asking that because inside my Assembly I have key String, it is an encrypted string, and I only want to load that assembly if decrypted key is equal to a string.
It is a sort of little protection I'm trying to implement.
Based on the ReflectionOnlyLoadFrom documentation
You cannot execute code from an assembly that has been loaded into the
reflection-only context. To execute the code, load the assembly with
the LoadFile method.
Accessing the value of a field or property, or invoking a method, is executing the code. As such, you have to use LoadFile.
As for your security measures, perhaps you should instead look at assembly signing to properly verify the authenticity of your target assemblies.
Related
What does assembly GetTypes() do behind the scenes? Assuming an assembly has been loaded to the AppDomain does it still need to read from the physical DLL? And what the assembly manifest do?
Iterating through the assembly like this:
AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes())
I'm occasionally getting the following error:
Could not load file or assembly
Which tells me that because an assembly is loaded into the AppDomain it's not necessarily fully loaded to memory. Sometimes it still needs to go back to the file.
My questions:
Why is it doing that?
What can I do to detect these semi-loaded assemblies?
Getting a type from a assembly may require additional assemblies to be loaded so that is most probably the reason for the error; a failure to load a dependent assembly. However a .NET assembly may be constructed from several modules in different files so I believe you may also face this problem if you have a multifile assembly and one or more of the files are missing or corrupt.
Associated with the error you should get more information about the specific assembly that could not be loaded.
If you just want to load a list of the loadable types in the assembly you can use a extension method like this:
public static IEnumerable<Type> GetLoadableTypes(this Assembly assembly)
{
if (assembly == null) throw new ArgumentNullException(nameof(assembly));
try
{
return assembly.GetTypes();
}
catch (ReflectionTypeLoadException e)
{
return e.Types.Where(t => t != null);
}
}
(Source: Get All Types in an Assembly)
Behind the scenes, GetType method returns the address stored in the specified object's type object pointer member (When the object is stored in the heap, this information is stored along with couple of others like Sync Block Index). This is how the GetType method returns the true type of any object. An assembly might be dependent on some other assembly that must be loaded. And unless it is required by the application, it won't be loaded by JIT. So, yes, it requires the assemblies to be physically available at all times.
This question is a bit old, but leaving a note here that GetTypes might throw an exception if the application has not loaded the assembly dependencies especially in the newer .NET Core/.NET 5/6 .dlls.
Microsoft has introduced{assemblyName}.deps.json file which contains dependencies for an assembly, so you will need to load those too before you can call GetTypes without getting an exception.
I found these blog posts to be helpful on how to do that:
https://jeremybytes.blogspot.com/2020/01/using-typegettype-with-net-core.html
https://learn.microsoft.com/en-us/dotnet/core/tutorials/creating-app-with-plugin-support#load-plugins
In my Windows Azure role C# code I do the following:
Assembly.Load( "Microsoft.WindowsAzure.ServiceRuntime" );
and FileNotFoundException is thrown. The problem is an assembly with such name is present and has even loaded before the code above is run - I see a corresponding line in the debugger "Output" window and when I do:
AppDomain.CurrentDomain.GetAssemblies().Any(
assembly => assembly.FullName.StartsWith("Microsoft.WindowsAzure.ServiceRuntime"));
the result is true and if I use Where(), then SingleOrDefault() I get a reference to a corresponding Assembly object.
Why can't I load an assembly with Assembly.Load()?
That Load() call can only succeed if Microsoft.WindowsAzure.ServiceRuntime.dll is stored in your app's probing path. By default the same directory as your EXE. Problem is, it isn't stored there, it is stored in the GAC.
The point of the GAC is to act as a depository of assemblies with the same name but different [AssemblyVersion]s, culture or processor architecture. Which is the problem with your Load(), you don't specify any. There is no reasonable way that fusion can pick an assembly for you, it is apt to give you the wrong one. So it doesn't bother, even if there is only one to pick from.
Specifying the full AsssemblyName.FullName is required. Use Project + Add Reference to avoid.
You should load it with a full assembly qualified name.
From the MSDN documentation:
// You must supply a valid fully qualified assembly name.
Assembly SampleAssembly = Assembly.Load
("SampleAssembly, Version=1.0.2004.0, Culture=neutral, PublicKeyToken=8744b20f8da049e3");
The documentation for Assembly.Load says that you're meant to supply the full name for the assembly (including e.g. version information).
Using just a plain name for the assembly will fail if the assembly is normally loaded from e.g. the GAC. E.g.:
try
{
Assembly.Load("System");
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
Console.WriteLine(AppDomain.CurrentDomain.GetAssemblies().Any(
assembly => assembly.FullName.StartsWith("System")));
Console.ReadLine();
Exhibits similar behaviour.
I have program which loads an assembly using Asssembly.LoadFrom method. Some time later I attempt to use Type.GetType to create a type from that assembly (using AssemblyQualifiedName), but the method returns null. If I set it to throw exception, it tells
Could not load file or assembly '...'
or one of its dependencies. The system
cannot find the file specified.
But I am sure the exact same assembly is already loaded (it shows in the AppDomain.CurrentDomain.GetAssemblies() list).
Anybody has an idea what could be wrong and/or how to solve this issue?
In order to understand why this doesn't work, you need to understand the issue of "load contexts". Type.GetType only looks at the "Load" context. The assembly you loaded into memory was in the "LoadFrom" context.
The only way to really get binds in the load context to see assemblies in the load-from context is to use the AssemblyResolve event and write code to return the correct assembly. The AssemblyResolve event fires right before the bind fails and all other assembly lookup did not succeed.
See the following links for more information about load contexts and issues that arise when using LoadFrom.
MSDN - http://msdn.microsoft.com/en-us/library/dd153782.aspx
AssemblyResolve - http://msdn.microsoft.com/en-us/library/system.appdomain.assemblyresolve.aspx
Suzanne Cook - Link
If you can get the assembly using Assembly.LoadFrom then you can get the type by doing:
Assembly assembly = Assembly.LoadFrom("whatever");
Type myType = assembly.GetType("typeName")
The assembly.GetType has other overloads which you can find out about here
How do I obtain an instance of a Type class for a type not defined in the currently executing assembly or in mscorlib.dll?
a) Namely, I've defined a class type someType in assembly CSharpSnapIn.dll, located at E:\CSharpSnapIn.dll, but for some reason when I try to specify an absolute path to this assembly, I get an exception:
Type t = Type.GetType("someType, E:\\CSharpSnapIn.dll"); // exeception
b) I've also tried by putting CSharpSnapIn.dll into \bin\debug directory of a currently running application, but I still get an exception:
Type t = Type.GetType("someType, CSharpSnapIn.dll"); // exeception
thanx
EDIT:
1) I've declared another class type someType2 ( inside CsharpSnapIn.dll )and this time it worked:
Type.GetType("someType2, CSharpSnapIn");
Difference between someType and someType2 is that someType implements an interface declared in external assembly asmIn, but this shouldn't cause an exception, since CsharpSnapIn.dll does have a reference to asmIn?!
2)
Note that the assembly doesn't need to
be loaded first, so long as the
assembly resolver can find it
In other words, calling Type.GetType() first loads an assembly and then creates a Type instance?
3)
The assembly has to be found by
probing, so it would have to be in the
bin directory as per your second
example. If it's an assembly with a
strong name, you have to give all the
details.
So you're saying we can't specify an absolute path ( to an assembly ) using Type.GetType(), but instead assembly needs to reside inside a bin directory?
You will need to first load the assembly:
Type t = Assembly
.LoadFrom(#"e:\CSharpSnapIn.dll")
.GetType("SomeNs.SomeType", true);
You need to give the assembly name - not the file which contains it.
For example:
Type t = Type.GetType("someType, CSharpSnapIn");
The assembly has to be found by probing, so it would have to be in the bin directory as per your second example. If it's an assembly with a strong name, you have to give all the details. Note that someType here also has to be fully qualified in terms of the namespace.
Note that the assembly doesn't need to be loaded first, so long as the assembly resolver can find it. For example, if the assembly is in the same directory as the currently executing assembly, that will be fine in most cases.
As Darin says, an alternative is to load the assembly directly - although in my experience there are quite a few "gotchas" in loading assemblies explicitly, particularly if you've got two assemblies in different locations which both rely on a third assembly. Making sure you only get that third assembly loaded once can be tricky.
You need to choose between LoadFile and LoadFrom etc. Here are some remarks from MSDN:
Use the LoadFile method to load and
examine assemblies that have the same
identity, but are located in different
paths. LoadFile does not load files
into the LoadFrom context, and does
not resolve dependencies using the
load path, as the LoadFrom method
does. LoadFile is useful in this
limited scenario because LoadFrom
cannot be used to load assemblies that
have the same identities but different
paths; it will load only the first
such assembly.
I'm doing a addin system where the main app loads assemblies Addin1.dll and Addin2.dll on runtime in new AppDomain's.
However, in case that Addin1.dll is signed (strong name) with my key and Addin2.dll is not, I want to be able to only load Addin1.dll and reject Addin2.dll.
I'm suspecting that it needs to be done by setting some parameters in AppDomainSetup?
Look into the Assembly.Load method that takes an Evidence parameter. You can find an example of how to create an evidence from your public key here.
You can implment a DomainManager and base your load/block decision's on whatever you like. I answered a somewhat related question here.
You can use Load method of AppDomain class to load new assembly into Appdomain, provided the assembly's publisher policy is satisfied by the client or end user environment.
Also the strong named assembly follows all the rules laid down by publisher of the assembly and the CLR. So the user of the assembly needs to satisfy the security aspect of the assembly being loaded into the appdomain.
The CLR loads the referenced global assembly from the GAC using the strong name properties. If the referenced assembly is available in the GAC, CLR will return its containing subdirectory and the file holding the manifest is loaded. Finding the assembly this way assures the caller that the assembly loaded at runtime came from the same publisher that built the assembly the code was compiled against. Now comparison of public key token in the referencing assembly’s assemblyRef table and public key token in the referenced assembly’s AssemblyDef table. If the referenced assembly isn’t in the GAC, the CLR looks in the application’s base directory and then in the private paths identified in the application’s configuration file; if the application containing the assembly is installed using the MSI, then CLR invokes MSI to load the required assembly. IF the assembly is not found in any of these location, an exception is thrown and finally the binding of assembly fails.