I have the fully qualified name of an assembly (and/or an AssemblyName object), e.g.
System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
These can be names of assemblies that are not currently loaded in the running application
I would like to figure out where this assembly located is located / would be loaded from on the user's machine.
For example, if I tried Assembly.Load() or .ReflectionOnlyLoad() on above string, this would load fine and I could inspect the resultig Assembly object's "Location" property.
However, I would like to get this information without having to actually load (and having to go through the trouble with AppDomains etc. to unload afterwards) the assembly.
So basically, how can I get the file path that Assembly.Load() would use to load from (but without me having to actually Load the assembly)?
Thanks!
edit: Just some info on why (I think I) need to do this:
I'm creating a C# script editor, in which users should be able to target certain .Net Framework versions, ideally without having the development SDKs installed on their machines (yay, Roslyn!).
So in my editor, I'm including the FrameworkList.xml files for all framework versions, which contain all information to construct the fully qualified assembly names that ship with the given Framework version.
Now in my editor, I am listing all of these. When the user wants to reference them in their project, I need to create a Microsoft.CodeAnalysis.MetadataReference in order to pass this reference on to the Microsoft.CodeAnalysis.Project. The only factory method for such a MetadataReference I can use (without loading the assembly) is the one accepting a full physical file path to it. Hence, I'm looking to figure out where the assemblies with the given AssemblyName are located on disk.
Related
Suppose you have an assembly B that references A and you have the source code for the assembly A only. Is it possible to build from source code the assembly A and debug it?
Currently we get this error:
Could not load file or assembly 'name' or one of its dependencies. The
located assembly's manifest definition does not match the assembly
reference.
Is there any way to bypass it?
This will depend on if the original assembly A that is referenced is strongly named. This is a feature where assemblies are signed. Keys for all compile time references are stored in the built assembly, B in your case. When loading assemblies the loader may then verify the signatures of all references to ensure the correct assembly is loaded.
So if strong naming is used it is not easy to replace the assembly A with a newer version without recompiling B. There is however a strong name validation bypass feature for full trust application domains.
If you manage to bypass or disable the strong naming you should simply be able to replace the file in the directory with the new version and attach visual studio.
INTRODUCTION
I'm writing a plugin for Navisworks and i'm using the Dropbox api to download/upload documents from a repository.
PROBLEM
Dropbox.Api uses the Newtonsoft.Json.dll version 7.0, the problem is that Navisworks uses the 4.0 version of the same assembly, so I cannot use the Dropbox api because it throws an exception every time:
System.AggregateException: One or more errors occurred. ---> System.IO.FileLoadException: Could not load file or assembly 'Newtonsoft.Json, Version=7.0.0.0, ...
So as I understand the program has the assembly 4.0v so Dropbox.Api cannot execute properly.
By now, what I've done is to use another process which I can load the right assembly and download/upload the files from there, but I would like to avoid using a second process.
I'm trying to use reflection to load the assembly at runtime, but it takes no effect, the program still cannot find the newer assembly.
//Load the assembly at the beginning of the plugin
var ass = System.Reflection.Assembly.Load(Properties.Resources.Newtonsoft_Json);
//Use the Dropbox api
//Exception...
Can I force, somehow, the program to use the newer assembly (temporary)?
Is there some solution that I've missed?
You are encountering this issue because you cannot load two different non-strong-named versions of a .NET assembly (no matter where it is on the file system) into the same AppDomain. By default you start with a single AppDomain called the Primary AppDomain for your process.
A strong-named assembly is one that takes the filename; version; signing key and culture to produce a unique assembly.
By now, what I've done is to use another process which I can load the right assembly and download/upload the files from there, but I would like to avoid using a second process.
No need to create a second process, you can instead create a 2nd AppDomain in the same process. Each AppDomain can load different versions of assemblies including Newtonsoft.Json without conflict.
I'm trying to use reflection to load the assembly at runtime, but it takes no effect, the program still cannot find the newer assembly.
That won't work, it's essentially the same as letting .NET doing it for you automatically.
The only time when you can load multiple versions of .NET assemblies into the same AppDomain is if the assembly (in this case the NuGet package) and dependent assemblies are all strong-named. For some reason I have never been able to fathom is why most open source .NET devs refuse to strong-name assemblies.
We have 2 different applications (developed with .NET):
1st App: A Winservice.
2nd App: A Desktop App.
The Desktop App is loading the assembly from the GAC.
The Winservice was in the past doing the same thing, but now we need that the Winservice loads THE SAME ASSEMBLY from another location.
But the GAC is winning and we can´t make this Winservice (using codebase in the app.config) to load the assembly. It always get the GAC´s one.
If we remove the GAC´s one. It works. But we need the other behavior. Desktop from the GAC and Winservice from the defined path in the codebase.
Is this possible without changing the version of the Assembly?
This is not possible without some kind of work around that modifies the assembly. In short, the GAC always wins. Period. If an assembly has a strong name the GAC is always checked first. Even if you load it into memory as a byte array and use Assembly.Load(byte[]), the strong name will be checked and if it is a GAC'd assembly it gets loaded from the GAC.
A couple possible work arounds:
Bump the assembly version.
Resign the assembly with a different strong name key. Build the service referencing this version.
I'm using AppDomain.CreateInstanceFromAndUnwrap() to create an object in a different AppDomain. I couldn't get it to work because it kept throwing the following error at me:
Could not load file or assembly 'COMon, Version=2.0.4960.27874, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The module was expected to contain an assembly manifest.
However, I found that it is because it tries to load my DLL (which has the same name as my .NET assembly).
This is how I call the method:
_script = (Script)_appDomain.CreateInstanceFromAndUnwrap(Assembly.GetExecutingAssembly().Location, "COMon.Scripting.Script");
It works fine as long as there isn't a native DLL file with the same name as my .NET assembly. Why does this happen when I'm passing it the full path and filename of my .NET assembly?
when I'm passing it the full path and filename of my .NET assembly?
That's not how the method works. The first argument is the display name of the assembly. It is not a file name. The MSDN article recommends that you take a look at Assembly.FullName to learn more about display names.
So the normal CLR search rules will be in effect for finding the assembly. It will look in the GAC first, then in the probing path for the AppDomain. With a quirk that you didn't count on, the CLR does not pay attention to the filename extension for a file. The display name for an assembly doesn't specify it. So it considers an EXE and a DLL equivalent. Something you can see back in the trace for Fuslogvw.exe, the utility you always want to use when you have trouble like this. And in other places, adding a reference to an EXE works fine for example.
So it finds COMon.exe and that's a kaboom, it is not a managed assembly.
It isn't that clear what the proper workaround might be in your case, other than simply renaming the assembly. When you tinker with AppDomains then you typically also want to use AppDomainSetup and set the ApplicationBase or PrivateBinPath property.
I have a .dll file in my project folder and would like to load it via Assembly.Load().
AssemblyName name = new AssemblyName("Portable.Store, Version=0.1.0.0, Culture=neutral, PublicKeyToken=12ay62c33eocf6uf");
Assembly assembly = Assembly.Load(name);
However this would throw a FileNotFoundException due to not specifying a path. And I am unable to use Assembly.LoadFrom() or Assembly.LoadFile() because Portable Class Libraries only support Assembly.Load()
Is there a way to do this inside a pcl? Any help is appreciated, thank you!
Edit #1: Would it matter if the assembly I'm trying to load is a non PCL? I know that this defeats the purpose of the PCL however there are a few libraries that are not included in the PCL. Therefore using conditional compilation, depending on the platform, I will load platform specific assemblies.
Edit #2: Found some more information on where the dll should be placed: https://stackoverflow.com/a/6440406/2464165
As of now I just placed it inside my project folder, with the .sln file and what not Where exactly would be the app probing path?
Edit #3: I was able to get my dll file placed inside the Resources Folder of a .dll file. So I have MyPCL.dll and inside that is where I have the ResourcesFolder/Portable.Store. How could I tell the Assembly.Load to look in specific folders instead of just the main AppX root directory?
I'm making the assumption that you are running the portable library in a Windows Store application (based on the assembly name you are trying to load).
There are two places that store apps find their assemblies, either in GAC if it is a framework assembly or the Appx package if it is a user assembly.
As "Portable.Store" (which I assuming is from my PclContrib project) is a user assembly, it must be loaded from the AppX package. To ensure that both assemblies end up in the AppX package, simply make sure that the Windows Store project containing the AppxManifest references both of them. That's it.
If Assembly.Load still cannot find the assembly, check to make sure that the strong name you are passing to Assembly.Load is correct.