Below is a multifile assembly consisting of two managed modules, one with a manifest:
so RUT.netmodule(RUT stands for rare used types) is a file(.netmodule) that's part of the assembly.
Let's say my client application references a type from RUT.netmodule and MultiFileLibrary.dll is a strong name assembly and it is installed in GAC.
Because RUT.netmodule doesn't physically reside in MultiFileLibrary.dll, so GAC won't have RUT.netmodule.
so my question is, maybe CLR is configured to check application's base directory to look for RUT.netmodule after it knows that the referenced type is in a different module file. But it also means that RUT.netmodule have to always in application's base directory, which sounds strange to me as if I have mutiple applications then I need to have multiple RUT.netmodule in their base directory. Is a way to "install" RUT.netmodule in GAC or when MultiFileLibrary.dll is installed in GAC, any .netmodule files are also copied into GAC?
I have never working with multi-file assemblies but as far as I can tell you should be able to sign the .netmodule by using the assembly linker tool (al.exe).
The documentation contains a small quote which might be relevant:
How to: Sign an assembly with a strong name
...
By using the Assembly Linker (Al.exe) to link a .NET Framework code module (a .netmodule file) with a key file.
My guess is that even when you place the assembly in GAC it will still reference the .netmodule and it should work if the .netmodule is signed.
Hope this information helps you.
Related
How can I use different dll's (other Version) with the same name in one directory?
For Example, LibA (ExternalLib.dll) has Version 1 and LibB (ExternalLib.dll) has Version 2.
I'm deploying all my programs to the same directory (this is our companys standard and I can't change this fact). The problem is if ProgramB which is using the LibB is deployed in the directory where ProgramA is using the LibA then ProgrammA would not longer work.
For my own Libs I use a Major-Version-Number (.01, .02) if there are big changes. But the Lib I'm using is an external Lib and each version of it requires different licensing-keys (which are handled by the programs itself).
I tried to rename the external libs from "ExternalLib.dll" to "ExternalLib.v1.dll" and "ExternalLib.v2.dll", but when I run my fresh compiled programm it throws an exception that says "ExternalLib.dll could not be found". The reference in my project is set to "ExternalLib.v1.dll" and compilation works fine.
Any ideas / suggestions to handle different assembly versions in the same directory?
Unfortunately, the filename of the DLL file has very little do do with how .Net is loading these types. The actual name is written into the meta data of the assembly as part of the compilation process. So at runtime, it will be probing for ExternalLib.dll regardless of what you renamed the file to. The usual way to fix this is to install to the GAC and use Strong Naming to reference the specific version.
Given you may not be able to do this, there are 4 things you could try:
Ask the vendor to produce version specific DLL's for you. They could compile such that the version name is part of the filename and included in the assembly manifest. This would be the simplest solution for you.
Handle the AssemblyResolve event and manually try and use Assembly.Load to point at the file you want such that you can specify specifically which dll to use. See http://support.microsoft.com/kb/837908 for more information, but effectively you'll be using Assembly.LoadFrom(specific_path) to choose the file where the code will load from.
If possible, you might also be able to use ildasm.exe to decompile the dll's to Intermediate Language (IL), then use ilasm.exe to recompile it to a new dll name. You would then reference this new DLL name in your project.
If the assembly is not signed, then you may be able to edit the manifest yourself; you can either use a compatible binary editor or possibly MT.exe.
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.
I'm having a similar problem to what Paul had a year ago (see How to add manifest to a .NET DLL?). That is, I have a C# class library project in Visual Studio 2008, which outputs a dll. The dll references some private assemblies, so I want to add an assembly manifest to the dll that specifies those other referenced assemblies.
I know how to do this for an executable, it's just appName.exe.manifest, and when the file is included in the project, you can then just select it as the manifest in the project properties.
According to the answer that Ruben gave Paul (in the above Stack Overflow thread), a manifest only applies to exes. However, the Microsoft documentation on manifests seems to suggest otherwise (correct me if I'm wrong), MSDN Assembly Manifests:
An assembly manifest is an XML file
that describes a side-by-side
assembly. Assembly manifests describe
the names and versions of side-by-side
assemblies, files, and resources of
the assembly, as well as the
dependence of the assembly on other
side-by-side assemblies. Correct
installation, activation, and
execution of side-by-side assemblies
requires that the assembly manifest
always accompany an assembly on the
system.
Because of the way side-by-side
searches for private assemblies, the
following naming restrictions apply
when packaging a DLL as a private
assembly. A recommended way of doing
this is to put the assembly manifest
in the DLL as a resource. In this
case, the resource ID must equal 1 and
the name of the private assembly may
be the same as the name of the DLL.
For example, if the name of the DLL is
Microsoft.Windows.mysample.dll, the
value of the name attribute used in
the assemblyIdentity element of the
manifest may also be
Microsoft.Windows.mysample.
An alternate way is to put the
assembly manifest in a separate file.
In this case, the name of the assembly
and its manifest must be different
than the name of the DLL. For example,
Microsoft.Windows.mysampleAsm,
Microsoft.Windows.mysampleAsm.manifest,
and Microsoft.Windows.Mysample.dll
So I created an assembly manifest assemblyName.manifest as a separate file, and included it in the class library project. But when I go to the properties for the project, I get the same result that Paul did, the option to use your own manifest is disabled.
Am I doing something wrong? How do I add my manifest to the assembly?
What you quoted is quite inappropriate for .NET assemblies. The Windows side-by-side cache is for unmanaged DLLs, the exact equivalent in .NET is the GAC. Furthermore, the compiler already embeds references to the dependent assemblies in the assembly manifest. You can see it if you run Ildasm.exe on your assembly. Double-click the manifest, you'll see the .assembly directives listed.
Fwiw, embedding your own Windows manifest in a class library is not a problem. Just use Project + Add New Item and select the Application Manifest File template item. The auto-generated content is completely wrong for a DLL of course but it does get embedded in the DLL. You can see that by using File + Open + File and selecting your assembly. You'll see the RT_MANIFEST with resource ID 2. Just to reiterate: don't do this for a managed DLL unless you want to enter reg-free COM directives.
Consider the following scenario:
I have two assemblies:
Assembly named A.dll located in folder Fold_A
Assembly named B.dll located in folder Fold_B
A.dll depends on B.dll and A is COM visible
when I'm performing command:
regasm A.dll /codebase
It fails, but when B was copied into fold_a - the command succeeded.
Is there some way to perform without copying assemblies on which depends assembly to be registered (by regasm)?
There is already question related to the issue: Multiple search paths for assemblies not in the GAC when using REGASM & COM
Well, yes, it is a problem when you register it but it will be a much larger problem when a client actually uses your COM server. A typical COM client will be unmanaged code, it isn't very practical to give it, say, a .config file to tell the CLR where to look for assembly B.
If you want this to work for any client without config then you ought to put B in the GAC. Which in general is the proper place for COM servers, DLL Hell is nothing to mess with when you use COM. Using the Assembly.AssemblyResolve event is probably not going to be practical but you could try by using a static class constructor to register the event handler. Hard coding the path to dependencies is questionable unless those folders are always related.
Can I configure a .NET application in a way (settings in Visual Studio) that it references a "local" assembly (not in GAC) instead of an assembly within the GAC, although both assemblies have the same name and the same version?
If both assemblies are strong-named (signed), the CLR will always load from the GAC.
Here are the steps the runtime uses to resolve assembly references (from How the Runtime Locates Assemblies):
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.
If a previous request to load the
assembly failed, the request fails
immediately without attempting to load
the assembly.
Checks the global assembly cache. If the assembly is found there, the
runtime uses this assembly.
Probes for the assembly (... some material omitted ...)
As stated later in that same article:
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.
So if you can afford to remove signing from the local assembly, the application will use it instead of the one in the GAC.
For more detail than you could probably ever want about the runtime-binding mechanisms, see Suzanne Cook's blog.
This blog entry from Scott Hanselman also provides a great overview of the binding process.
If you can change the version number of the local dll, you can use a dll version redirect using the oldVersion attribute. You can use a strong name for the local assembly:
Please look this page:
http://msdn.microsoft.com/en-us/library/7wd6ex19.aspx
Also you should consider that it is possible to modify the version number of a compiled assembly like it is described here:
Change Assembly Version in a compiled .NET assembly
You can use ilmerge and merged the assemblies into a single library to get around it.
To successfully deploy your .NET Framework application, you must understand how the common language runtime locates and binds to the assemblies that make up your application. By default, the runtime attempts to bind with the exact version of an assembly that the application was built with. This default behavior can be overridden by configuration file settings.
You can view binding information in the log file using the Assembly Binding Log Viewer (Fuslogvw.exe), which is included in the Windows Software Development Kit (SDK).