I have a server executable that talks to Active Directory to retrieve user information. In addition to AD, this exe allows customers to write their own plugins to talk to custom user directories.
This executable is strongly named.
Is the following a true statement:
In order for a strongly named
assembly to load another assembly, the
loaded assembly must also be signed
with the same key.
The following code returns null, if the assembly is not strongly signed, with no error indicating the assembly was not properly signed. Note, that if I do sign the assembly, I get an instance of IService. Which leads me to believe that loaded assemblies must be strongly signed.
Assembly assembly = Assembly.LoadFrom(path);
foreach (Type t in assembly.GetTypes())
{
if (t.GetInterface(typeof(IService).FullName) != null)
{
return (Activator.CreateInstance(t) as IService);
}
}
So, does this mean if you have a strongly signed assembly, and support assembly plugins, they must also be signed--plugin writers must sign them with the same key? That doesn't sound right.
Finally, Say I have an assembly that implements the IService interface, but also references an assembly, that references yet another assembly, each signed with a different key. What happens when I try to load? Should they all be signed by the same key?
The following statement is correct:
In order for a strongly named assembly
to load another assembly, the loaded
assembly must also be signed with the same key.
From MSDN:
If the strong-named assembly then
references an assembly with a simple
name, which does not have these
benefits, you lose the benefits you
would derive from using a strong-named
assembly and revert to DLL conflicts.
Therefore, strong-named assemblies can
only reference other strong-named
assemblies.
Edit: D'oh! Though my answer is true, as P Daddy points out, it's irrelevant!
Using reflection to Load a weakly-named assembly is not the same thing as referencing one, and is not restricted the same way.
I recreated your code (or at least a close approximation), with the following assemblies:
Interface.dll (signed, contains IService)
Loader.exe (signed, a console app that takes a path, uses your code to load and return the first IService it finds in the assembly specified by that path, then calls an IService method)
Plugin.dll (not signed, contains an IService implementation)
Next I added a Plugin.dll reference to Loaded.exe and tried to access its IService implementation, which failed as expected with the following message: "Assembly generation failed -- Referenced assembly 'Plugin' does not have a strong name."
Finally, I ran the console app, passed it the name of the weakly-named Plugin.dll, and it worked just fine.
There seems to be something else afoot. Scott Hanselman has blogged about the vagaries of
dynamic assembly loading on several occasions, and he points to Suzanne Cook's blog for authoritative details about the topic.
If your assembly is strongly typed signed, I think any assembly you load must also be strongly typed signed...but not necessarily signed with the same key.
The statement is wrong - referenced assemblies must be signed, but not necessarily with the same key.
When you reference a strong-named assembly, you expect to get certain benefits, such as versioning and naming protection. If the strong-named assembly then references an assembly with a simple name, which does not have these benefits, you lose the benefits you would derive from using a strong-named assembly and revert to DLL conflicts. Therefore, strong-named assemblies can only reference other strong-named assemblies.
(Taken from MSDN Library)
Related
according to https://learn.microsoft.com/en-us/dotnet/framework/app-domains/create-and-use-strong-named-assemblies
A strong-named assembly can only use types from other strong-named assemblies. Otherwise, the integrity of the strong-named assembly would be compromised.
This is an issue because I would need to change all my thousands of assemblies, from weakly-named to strongly-named. This would take a long time, is there any way around this.
My use case:
I am building an application which will allow users to write C#, and execute it. I am doing this through an application domain. The application domain will compile the user code, in a partially trusted assembly. The user will be able to call a utilities assembly library. This utilities library, will be fully-trusted, and hence must be strongly named. This utilities library must be able to access the thousands of assemblies. The only way to do that now, is by changing all the assemblies to be strongly-named. which means I would need to add a AssemblyKeyFile attribute to each one.
Thanks
Dan
Yes, you are right strongly typed assembly can not have weakly-named assemblies in the reference.
There is a cool nuget package which signs unsigned libraries in the references:
https://www.nuget.org/packages/strongnamer
EDIT: I haven't mentioned one important thing - application which loads my assemblies are actually not in same directory (as other dlls). After fiddling with Fusion log, I noticed that loading of dll are behaving differently than I previously thought. (Yup, I should first RTFM, shame on me)
C:\Test\appLoadingStuff.exe
C:\Lib\Acme.Application.dll
C:\Lib\Acme.Data.dll
...
.NET is probing application base (besides GAC and stuff; directory where loading app is - C:\Test\), and does not care about location where loaded dll are stored (other directory).
While using the .NET framework I found myself getting a ReflectionTypeLoadException exception:
System.TypeLoadException
Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.
Could not load type 'Acme.Data.Foo' from assembly 'Acme.Data.Dao, Version=1.1.0.4, Culture=neutral, PublicKeyToken=null'.":"Acme.Data.Foo
I have, for simplicity, 3 assemblies:
Acme.Application my main assembly
Acme.Data my data objects (referenced by 1st one)
Acme.Data.Dao my data access objects (referenced by 1st one)
And there's another application, which actually loads my main assembly. All .dll files are in same directory.
As you could expect, type Acme.Data.Foo is living in assembly Acme.Data. Despite this, .NET is trying to find it in another assembly Acme.Data.Dao - which fails, as the type is not there.
I can't figure out what is making .NET looking for that particular type in wrong assembly. Exception is thrown immediately when accessing types on assembly:
System.Reflection.RuntimeAssembly assembly = Assembly.LoadFile("C:\Lib\Acme.Application.dll")
var types = assembly.GetTypes(); // -> explodes
When I tried to check referenced assemblies using:
assembly.GetReferencedAssemblies()
I can clearly see my desired assembly in list.
There's no assembly redirect (and as far I know, this affects only version). Versions of assemblies are correct.
What else should I look for?
As I stated on edited question, I missed to mention very important property of what I was trying to do. My assembly was loaded by another application which was not in same path as loaded assemblies.
.NET is probing directory of running application, not directories where loaded dlls are. If one needs to handle such case, it is necessary to implement event handler AppDomain.AssemblyResolve to take care of dependencies of loaded dll.
More reading:
How the Runtime Locates Assemblies (notice section Locating the Assembly through Probing)
AppDomain.AssemblyResolve Event
Thanks to anyone who participated on this question and sorry I didn't share such crucial detail (tbh, I didn't expect this little detail matters - now i know).
I have a plugin structure which all is compiled using weak assemblies. I want to change this now but running into some difficulties.
interface.dll contains my interface for my plugins (IPlugin)
Load.exe will load all the plugin implementations which implements IPlugin
pluginA.dll contains a implementation of IPlugin
All assemblies is original weak assemblies.
I now want to change the assemblies to strong name assemblies.
After I have made the interface.dll and load.exe strong name assemblies I am unable to create an instance of the pluginA.dll IPlugin implementation, unless I have recompiled pluginA.dll to reference the new strong name interface.dll
Is there a way for me to set strong name on interface.dll and load.exe without being forced to recompile all plugins implementing IPlugin?
The reason I ask this, is that I have a lot of plugins and I don't have control of all of them. So I want to avoid breaking the plugin functionallity when I updated the interface.dll with a strong name.
I hope you can help me, and please do not hesitate to ask for further details if something is unclear.
Thanks
Giving an assembly a strong name is a hard breaking change. You cannot patch it up with a config file or publisher policy. So rebuilding the plug-ins is a hard requirement you cannot skip.
You didn't otherwise state the reason for deciding to do so. There is no compelling one in a plug-in scenario. A strong name provides a way to verify that an assembly is an exact match with the reference assembly that your program was built with. But, by design, you don't have a reference assembly for a plug-in. So there's nothing to verify.
There is no way around this, unfortunately. The benefits you derive from strong-naming an assembly (most likely the reasons you are converting yours) are lost if you can reference simple named assemblies.
From Microsoft's documentation:
When you reference a strong-named assembly, you expect to get certain benefits, such as versioning and naming protection. If the strong-named assembly then references an assembly with a simple name, which does not have these benefits, you lose the benefits you would derive from using a strong-named assembly and revert to DLL conflicts. Therefore, strong-named assemblies can only reference other strong-named assemblies.
I've a project which references to a 3th party library. The manufacturer of the library releases new versions on a regular basis. My ultimate goal is to be able to choose at runtime which version must be used during execution.
For now, I'm trying to load an assembly at runtime that has a higher version number than the one that was used during compilation. I compile my project, replace the 3th party library with a newer version and try to run the application. This is were I come into problems. I get an error saying:
"The located assembly's manifest definition does not match the assembly reference"
I was not supprised to see this error, since the assembly is strongly signed. I looked for ways to bypass this, but without any luck so far.
I thought that Binding Redirection could help me, but it has the disadvantage that you can't specify a range of "newversions". Any combination should work, older with newer version and vice versa.
<bindingRedirect oldVersion="1.2.7.0" newVersion="1.2.8.0" />
http://msdn.microsoft.com/en-us/library/eftw1fys.aspx
I've also looked at dynamic invocation, but then I loose type safety (my code extensively uses the types defined in the 3th party assembly). --> removing reference is difficult.
Removing the public key in the reference of the project definition didn't helped either. Any other assembly version then the one used during compilation fails.
<Reference Include="<assemblyname>">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\Dependencies\<manufacturer>\1.2.7.0\<assemblyname>.dll</HintPath>
</Reference>
Note:
The logic to load and unload assemblies at runtime already exists.
There's no interface available for the 3th party library
You can 'fix' this issue (work around is probably a better description) by handling the AssemblyResolve event on the AppDomain. Handling this event gives your code a chance to provide the assembly that needs to be loaded when all the normal methods of finding an assembly have failed to locate a matching version.
Inside the event handler you will need to check the ResolveEventArgs.Name property to see if the assembly is the one you need to load. The Name property will be the long name of the assembly being loaded - i.e. 'Widget.Net, Version=1.2.3.4, Culture=neutral, PublicKeyToken=xxxxxxxxxxx'.
Once the correct load request has been identified, simply load the correct version of the assembly (Assembly.LoadFrom, Assembly.Load, Assembly.LoadWithPartialName) and return it from the event handler. Note that Assembly.LoadWithPartialName is marked as obsolete, but seems to be the only way to handle this issue if the target assembly is in the GAC.
// application initialization
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
if (args.Name.StartsWith("Widget.Net, Version="))
{
Assembly result = Assembly.LoadFrom("Widget.Net.dll");
return result;
}
return null;
}
It's important to be aware that while this 'solves' the problem, it's not a good solution in any sense. It completely subverts the normal version and strong name checking of assemblies used by the .Net framework. It's something that you do when you have no other option because (as in the question) a vendor has messed up versioning their assembly. You are also relying on their being no breaking changes to the classes defined in the assembly between the referenced version and the loaded version - i.e. that all the classes, properties, methods etc that you use still exist and have the same signatures.
To maintain at least a pretence of security, it would be a very good idea to at least check in the AssemblyResolve event handler that:
The assembly version loaded is newer than the version requested
The public key tokens of the loaded and requested assemblies match
I have a project, i.e. library.exe. In this I have referenced an assembly (logging.dll ver 1.0.3.0) and I have given this assembly a strong name.
Now suppose I changed a method in logging.dll and made version 1.0.4.0.
Now when I copy/replaced the old DLL with this new one I got an exception.
I know that exception is because I have changed version number of the DLL. As it was a strong name DLL it's not allowed unless I rebuilt library.exe.
What I want to say with above story is
Use strong name with assembly only when we have to add it to GAC.
If we have an application where individual assemblies requires updating do not use strong named assemblies.
Am I correct with point 1 and 2?
When should strong named assemblies not be used?
What are the disadvantages of "strong named assembly"?
It is only really needed if you want to place your assemblies in the GAC, but it also helps against tampering. It is fairly easy to change the code in an assembly so this gives bad people an advantage. When you are using strong named assemblies you are signing it with a private key only you have. People could still change your assembly, but they can't give it the same strong name, because they do not have your private key. In that case .Net refuses the assemly tamperd with. When they sign your assembly with a new private key the .Net still refuses to load it since the identity of the assembly has changed.
There are several ways to solve the versioning problem. When your application wants to load a v1 assembly you could tell it to look voor a v2 anyway. See here for more information. The other option would be not to change the Assembly Version at all, but to change the File Version of the assembly only. For .Net the assemblies are the same, but you and your installer can still see which one is newer. See the AssemblyFileVersion attribute.
Both correct.
You don't need a StrongName if your signing the assembly afterwards, like with a real certificate.
In my oppinion strong naming is not realy worth anything, see this link for example. Well you need it for placing an assembly into the GAC but that's it.