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.
Related
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.
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
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 have an Assembly Library1.dll which contains some Interfaces, which were serialized as a byte array into the database. For some reasons we have to change the Interface properties and defintion. so now i am writing a migration utility. So i have 2 versions of Library1.dll , In my utility i have created a folder where i store the new version of Library1.dll . This utility in turn also references Library1.dll hence in bin folder contains Library1.dll but this dll is compiled on older version. My new version of Library1.dll is stored in a private path which i am passing to Assembly.ReflectionOnlyLoadFrom function to instantiate and hence GetTypes on the assembly loaded which further would enable me to do conversion of data.
But I always get ReflectionTypeLoadException when trying to load Library1.dll from private path.
Please help guys!!!. any help would be appreciated. I am really stuck.
Thanks,
AG
If your Library is referencing another dll, GetTypes will fail when it hits a type that uses an external type. Unlike normal assembly loading, ReflectionOnly Assembly loading will not resolve dependencies. You can either subscribe to AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve and load the dependencies as required, or you could pre-load them.
This is the code I use for this:
var assembly = Assembly.ReflectionOnlyLoadFrom(assemblyPath);
foreach (var assemblyName in assembly.GetReferencedAssemblies()) {
try {
Assembly.ReflectionOnlyLoad(assemblyName.FullName);
} catch {
Assembly.ReflectionOnlyLoadFrom(Path.Combine(Path.GetDirectoryName(assemblyPath), assemblyName.Name + ".dll"));
}
}
This will try to load all dependencies of the reflection-only loaded assembly first by fullname, then by path (assuming that the dependency is in the same directory as the loaded 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.