After reading through the MSDN article How the Runtime Locates Assemblies and also reading this, I am still unsure about how weakly named assemblies are resolved at runtime.
Eg. if I have a reference to some dll file in my project, I compile and deploy, will it pick up a new version of the referenced dll file if I just replace the old one which was actually referenced at compile time? Does it matter if the reference in the project file specifies the version etc. of the referenced assembly?
Any enlightenment welcome
If the assembly is not found in the GAC then the CLR will search for it in the "probing path". Which by default is only the directory that contains the EXE. It only looks for a match on the assembly name and will stop searching on the first match.
It then checks the [AssemblyVersion] number. If it doesn't match you'll get an exception, it won't keep looking for another assembly with the same name. Whenever you have resolution trouble, you'll want to use the Fuslogvw.exe utility. It shows you exactly where the CLR looked and what went wrong.
The best place that I've found to learn about this is in Grimes Fusion Workshop as can be found here. It is very comprehensive while still easy to understand.
The answer to your questions is yes as long as long as you have Specific Version set to False in the properties for the reference to the assembly.
If version is not mentioned it will pick up the reference, if the version is mentioned it will try to find and load the assembly matching the signature with version mentioned. if not found it will throw an exception. To resolve this you can do assembly binding redirection.
Related
I got "Referenced assembly 'xxxxxxxxxx.GPUImage' does not have a strong name error" and according to How to fix "Referenced assembly does not have a strong name" error, I have corrected the issue. I have added the correct referencing also. (I have this problem with two other third-party assemblies and after signing them they work properly.)
But after I sign, it gives a new error which was not been given earlier. It is as follows.
Error 2 The type 'xxxxxxxxxx.GPUImage.ImageFilter' is defined in an assembly
that is not referenced. You must add a reference to assembly 'xxxxxxxxxx.GPUImage',
Version=2.0.0.0, Culture=neutral, 'PublicKeyToken=null'.
What is the reason for this? Can a .dll consist with an unassigned .dll inside the signed one?
As mentioned by #eric, I run fusion log and the following is the log file.
Search for all occurrences of the unsigned assembly on your hard disk, and delete them - keep just the signed version. Then do a complete rebuild. It'll either work, or you'll find who's referencing the old assembly.
Learn and use Process Monitor, and then you can see from where your process tries to load the assemblies,
http://technet.microsoft.com/en-us/sysinternals/bb896645.aspx
After knowing all the locations, go ahead and remove those unsigned versions. Usually they might be cached somewhere by your unit testing suite or something else. By deleting them, you should be able to resolve the problem.
Some assembly in your solution is still referencing an unsigned version of the assembly that defines GPUImage.ImageFilter. You get that from PublicKeyToken=null.
Try looking at how loading is resolving using the Fusion Log Viewer. It should tell you which assembly is trying to reference the unsigned one.
Preface: I know basically nothing about C#.
I've added a dll to my project. I have no build errors, but when I try to run, I get an error that says it can't find the dll. I've tried copying it to the output directories too. To no avail.
Any idea what could be happening?
Specific Error:
System.IO.FileNotFoundException was unhandled Message=Could not load
file or assembly 'controllib_clr.dll' or one of its dependencies. The
specified module could not be found. Source=controllib_demo_cs...
I'll be happy to add more information if need be. :) I just don't know what info would be beneficial given my (very) limited knowledge.
It looks like it is not able to find/load some dependencies dlls I will use DependencyWalker to figure out what it is missing http://www.dependencywalker.com/
Is it a managed (.NET) or an unmanaged (native) DLL? I'm assuming unmanaged.
FileNotFoundException is commonly thrown when missing a dependency. The DLL you are loading might require any number of other DLLs on load. In most cases it won't tell you which file it needs. You have to refer to the documentation for that DLL.
If it exists, in your output folder, then most likely its one of its dependencies that is missing. You can fix this by adding its dependencies as references in your project.
if it doesn't exist in your output, then, check that "Copy Local" is set in the properties of the reference.
I am not a .NET developer, so there might be some basic things I don't know.
I have some experience coding in C#, but now I have a question. One of my projects (A) references another ptoject (B), with "local copy" set. When B.dll is in the same location as A.exe everything works. But when B.dll is put in a common directory from PATH it doesn't work.
One of my coworkers said he thought I should make B strongly signed. Is he correct? Is that why one would strongly sign an assembly?
I read a bit about in in the internet but all I saw was about security... If so, how does one sign an assembly and what consequences does it have? Please note that I am using VS2003 .Net 1.1.
Edit: Thank you all very much for your answers, however all the links you provided refer to later versions of VS and .NET which have some sort of Signing tab in project properties. Does anybody know (or give a link )how to strongly name the assembly in VS2003 .Net1.1?
Your problem is not related to assembly signing in the first place. .NET does not use the PATH environment variable to load assemblies. The process is actually a bit more complex and you best read all details in MSDN (also see steps 1 to 4):
How the Runtime Locates Assemblies
In your case it might be the best to install the shared assembly to the GAC. Installing to the GAC requires that your assembly has a strong name, so this is probably what your co-worker referred to.
Update:
As you asked specifically about strong-naming a .NET 1.1 assembly I'd suggest checking out the following question:
How to give a .NET 1.1 dll a strong name in VS2003
I think that what your co-worker might be referring to is "Strong Naming" an Assembly.
Strong Naming is what enables you to deploy your assembly to the GAC.
Once it is in the GAC, then any application using that assembly can always locate it. Path's are irrelevant and that is the preferred way to have shared assemblies deployed.
To strong name an assembly, you can use the sn.exe tool that comes with Visual Studio to generate a strong name and then sign the assembly using the keyfile that is generated via sn.exe.
EDIT : Example of how to use SN.exe to strong name an assembly is here
Also, I think you should understand how the runtime loads assemblies. From MSDN
The runtime uses the following steps to resolve an assembly reference:
Determines the correct assembly version by examining applicable
configuration files, including the application configuration file,
publisher policy file, and machine configuration file.
If the configuration file is located on a remote machine, the
runtime must locate and download the application configuration file
first.
Checks whether the assembly name has been bound to before and, if so,
uses the previously loaded assembly.
Checks the global assembly cache. If the assembly is found there, the
runtime uses this assembly.
Probes for the assembly using the following steps: If configuration
and publisher policy do not affect the original reference and if the
bind request was created using the Assembly.LoadFrom method, the
runtime checks for location hints.
If a codebase is found in the configuration files, the runtime checks
only this location. If this probe fails, the runtime determines that
the binding request failed and no other probing occurs.
Probes for the assembly using the heuristics described in the probing
section. If the assembly is not found after probing, the runtime
requests the Windows Installer to provide the assembly. This acts as
an install-on-demand feature.
Note: There is no version checking for assemblies without strong
names, nor does the runtime check in the global assembly cache for
assemblies without strong names.
The right way to do this is by deploying your .dll in the GAC. http://support.microsoft.com/kb/815808
what is the reason you want to put the B.dll in a common directory? is it because it can be used by a another program? if so adding it to the GAC is the best option. See this one
As 0xA3 already mentioned you should read the article at MSDN. But what is not so good explained in the article is the usage of the AssemblyResolve event. It will be thrown if the Framework didn't find the assembly at any place, givin you a chance to start a search on yourself (maybe in your common folder) and return the needed assembly.
An example on how to use this, can be found in my question here.
Hey folks, I've got an ASP.NET web site project that for some reason is insisting on referencing both mscorlib 1.0.5 and mscorlib 2.0, and I can't figure out why.
I've analyzed all the referenced DLLs using NDepend, and they all appear to only reference mscorlib 2.0. I've got a couple web references, but I can't imagine why that would create an additional reference to the 1.0 dll.
Anyone have any ideas why I'd be getting this additional reference, or what I can use to find out that information? NDepend is great, but just comes back and says "found 2 references, using the newer version", so it doesn't help me figure out why I have the extra reference...
I think at this point your best bet is to use ildasm. Using ildasm on the assembly will bring up a node named "Manifest". Double click on that node and it will dump out the IL representation of assembly references including the referenced version number. Repeat this for all of your DLL's until you find the one referencing the 1.0 version.
EDIT
Another possible solution would be to enumerate the Assembly values and there associated GetReferencedAssemblies method. This will return an array of AssemblyName values which have a corresponding Version member. This should contain the actual version of the referenced assembly vs. the one that was actually loaded.
I'm not 100% sure on this matter and don't have a convenient way to test it right now.
Try removing the reference and recompiling - that will tell you what (if anything) depends on the older version.
An errant reference may be residing in your web.config file.
I'm developing a custom PowerShell snap-in, which references another project in the solution.
When I try to debug the snap-in (following [these instructions][1]), the assembly fails to load and my cmdlet fails with the message "Could not load file or Assembly..."
How do you instruct PowerShell on how to locate assemblies, or how do you specify where are located the assemblies needed by the snap-in?
I'd prefer to avoid registering the assemblies in the GAC, at least during development.
Not sure of the exact behaviour, but I would try and make use of fuslogvw to see exactly where the runtime is looking for the problematic assemblies. That would give you a clue as to how to get them to be copied into the correct place on build. This post by Scott Hanselman is quite useful, and this is the official documentation.
If you find the solution, please add an answer, as this must be a common scenario.
SOLUTION (Posting it here as suggested by one of the comments to my question)
My problem was rather specific, as I'm developing on a 64 bits server machine, but I'm posting the solution in case it could help someone else as well.
Using fuslogvw as suggested, I saw that the dependent assembly was being searched using the machine.config file under C:\Windows\Microsoft.NET\Framework64 and then the binding failed; launching the project with "start without debugging", instead, the machine.config file under C:\Windows\Microsoft.NET\Framework was taken (notice the missing 64 at the end).
I thought that the problem could be due to the image format, and infact the dependent assembly was being compiled with x86 as CPU target; I changed it to "Any CPU" and now the assembly is loaded correctly.