Assembly names and versions - c#

What is considered as best practice when it comes to assemblies and releases?
I would like to be able to reference multiple versions of the same library - solution contains multiple projects that depend on different versions of a commonutils.dll library we build ourselves.
As all dependencies are copied to the bin/debug or bin/release, only a single copy of commonutils.dll can exist there despite each of the DLL files having different assembly version numbers.
Should I include version numbers in the assembly name to be able to reference multiple versions of a library or is there another way?

Assemblies can coexist in the GAC (Global Assembly Cache) even if they have the same name given that the version is different. This is how .NET Framework shipped assemblies work. A requirement that must be meet in order for an assembly to be able to be GAC registered is to be signed.
Adding version numbers to the name of the Assembly just defeats the whole purpose of the assembly ecosystem and is cumbersome IMHO. To know which version of a given assembly I have just open the Properties window and check the version.

Here's what I've been living by --
It depends on what you are planning to use the DLL files for. I categorize them in two main groups:
Dead-end Assemblies. These are EXE files and DLL files you really aren't planning on referencing from anywhere. Just weakly name these and make sure you have the version numbers you release tagged in source-control, so you can rollback whenever.
Referenced Assemblies. Strong name these so you can have multiple versions of it being referenced by other assemblies. Use the full name to reference them (Assembly.Load). Keep a copy of the latest-and-greatest version of it in a place where other code can reference it.
Next, you have a choice of whether to copy local or not your references. Basically, the tradeoff boils down to -- do you want to take in patches/upgrades from your references? There can be positive value in that from getting new functionality, but on the other hand, there could be breaking changes. The decision here, I believe, should be made on a case-by-case basis.
While developing in Visual Studio, by default you will take the latest version to compile with, but once compiled the referencing assembly will require the specific version it was compiled with.
Your last decision is to Copy Local or not. Basically, if you already have a mechanism in place to deploy the referenced assembly, set this to false.
If you are planning a big release management system, you'll probably have to put a lot more thought and care into this. For me (small shop -- two people), this works fine. We know what's going on, and don't feel restrained from having to do things in a way that doesn't make sense.
Once you reach runtime, you Assembly.Load whatever you want into the application domain. Then, you can use Assembly.GetType to reach the type you want. If you have a type that is present in multiple loaded assemblies (such as in multiple versions of the same project), you may get an AmbiguousMatchException exception. In order to resolve that, you will need to get the type out of an instance of an assembly variable, not the static Assembly.GetType method.

Giving different names to different assembly versions is the easiest way and surely works.
If your assembly (commonutils.dll) is strong-named (i.e. signed), you can think about installing it in the GAC (Global Assembly Cache - you can install different versions of the same assembly side-by-side in the GAC), therefore the calling application automatically gets the proper version from there because .NET Types include assembly version information.
In your VS project you reference the correct version of the library, but you don't deploy it in the application folder; you install it in the GAC instead (during application setup).

Related

Ref folder within .NET 5.0 bin folder

What is the ref folder when compiling .NET 5.0 application?
I mean this one:
[project_path]\bin\Debug\net5.0\ref\
These are so called Reference Assemblies (assemblies that only contain the public interface of an assembly), these help speed up the build process, since projects that depend on this one will be able to see that there is no reason to recompile, even if the innards of the assembly have changed, because outwardly it's still the same.
These Reference Assemblies need to look the same as the real thing from the outside. Hence, they have the same filename, assembly name, assembly identity and everything. This allows the build system to use them as a substitute for the real thing. And since these assemblies don't have any of the implementation details, they only change when the interface of the contents changes. Due to these facts, they can't live in the same folder as the actual build output, and this is the reason for the extra ref folder. MsBuild will use these reference assemblies automatically to speed up the build process (at the expense of generating and comparing the reference assembly each time the compiled code results in a new project output and a few files in the output directory).
If your project isn't referenced by other projects, you don't get any benefits from these reference assemblies (if you don't hand them out to 3rd parties that is). And you can turn off this feature by adding this property to the project file:
<PropertyGroup>
<!--
Turns off reference assembly generation
See: https://learn.microsoft.com/en-us/dotnet/standard/assembly/reference-assemblies
-->
<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
</PropertyGroup>
After changing the setting, make sure you clean your build outputs.
These reference assemblies can also be used to allow people to compile projects to work with your system, without having to install/redistribute the actual compiled assemblies that run on your server. This way people can develop extensions, plugins, or clients for your application without having to give them access to actual implementation. This can help protect your intellectual property, since .NET assemblies are easy to decompile.
See also:
https://stackoverflow.com/a/58911152/736079

How to force visual studio to check for broken file references at compile time

This question is specifically about file references
My project has a reference to library A. Library A has a reference to library B.
If I don't add a direct reference to library B, the project will compile fine, but then throw a "could not load file or assembly B" exception at runtime when it tries to load library A.
So, how do I force visual studio to check for all broken file references at compile time? Alternatively, is there any other way to find these broken references (a tool, VS extension, etc.)
Here's an example project that reproduces the behavior.
https://github.com/RaikolAmaro/BrokenDependencies
This isn't a compile-time problem, as, at compile time, all required references were present and accounted for. Otherwise, it wouldn't have compiled in the first place.
It's a runtime problem and Visual Studio doesn't care much about what you want to have in the output directory or not. This is why you have total control over which elements you want copied from NuGet packages as well as other projects. Why? Because you may be using a installer or packaging solution or have some magic assembly resolving code to find your dependencies. You may be relying on plugins or configuration based dependency injection. Too many things which will thwart a scan like this.
There is another problem. While an assembly may depend on a certain other assembly, your code may not require it. It that's she case, if your code never loads a codepath that requires this other assembly, then you don't need it in your output directory to run.
There are tools that scan all the codepaths in your projects, the assemblies they depend on and so forth. These can be used to see whether you have all the required binaries to run the code.
http://www.dependencywalker.com/
There is problem with these tools. The same problems mentioned above. If you use dependency injection through configuration or convention (e.g. based on reflection) or do your own reflection, or depend on the dynamic keyword, then these tools may not be able to find all codepaths you depend on and may require some configuration or in-source annotation to figure that out while scanning.

How to use my DLL when it is not in the GAC

If I have a Project which uses my own made .dll and this .dll is not registered with the GAC but simply in the same folder as my projects App. eg C:\Program Files (x86)\MyApp Folder.
Can I, and more importantly how do I properly reference this .dll if I want to for example build a second project which also uses this .dll. It is possible that I build a few small apps that will use this .dll.
In this case must I have it in the GAC or if it is not there what must I do?
If I have a Project...
You should never put yourself in a situation where you have just a project. You first and foremost have a solution. A collection of projects that, together, build an app. Projects of course have a dependency on each other, you use a project dependency to tell the compiler about. Which automatically takes care of reference assemblies, the output of one project becomes the reference of another. And any changes you make to the source code of such a project automatically propagate to the others.
This is usually as far as teams take it.
This however tends to not work so well on very large solutions with dozens of projects, Visual Studio tends to get sluggish and building can take a long time. An important step to take in such a case is to freeze a root project. A programmer needs to get an explicit permission to make changes to such a core project. Because such a change tends to be very destabilizing, requiring many changes in dependent projects. And effectively destroys many hours of testing and validation time.
You do this by explicitly removing a project from a solution. Which now automatically makes it difficult to make changes to it. The dependent projects need to be updated to use an explicit reference assembly instead of the project dependency. Picking a well-known location for the assembly is important. Either source control or (preferrably) a build server is instrumental to be the source of the assembly. A tool like Nuget can be very useful.

Compile .net dll without specific verstion

I have 2 selfmade DLLs in my .net application. The first DLL is a general one, the second DLL also uses the first DLL. Now whenever I update the first DLL (new version number), I need to recompile also the second DLL. Is it possible to update the first DLL without the need to recompile the second DLL?
Thanks!
When you add the reference to the library, make sure you set the "Specific Version" property on the reference to "False". As long as you aren't referencing a specific version, it won't matter. You will be able to recompile the dependencies without having to recompile the projects that are dependent upon them. However, Visual Studio will automatically recompile your project, even if nothing changed except a version number of a dependency. Technically it's not necessary, though, so you could still run the old exe against the new libraries, etc.
If you reference an assembly, and that assembly's interface changes, then yes, you have to recompile the calling code. If, however, you have a common assembly containing the interfaces, then you can change the server assembly all you want because the calling code will still only reference the assembly with the interfaces in it.
And like SteveDog said, set the Specific Version property (of your reference) to False.

DLL Not found: referencing dependent DLLs

I'm attempting to implement a C++ DLL (of my own creation) that uses the Intel Performance Primitives in a C# forms application. I'm getting a "DLL Not Found Exception" when I attempt to run the program. One possible reason put forward in other posts on this site is that there are dependent DLLs that must be referenced and in fact after downloading DpendencyWalker I found that my DLL uses "IPPS-7.0.DLL".
My problem is that it is unclear to me how to reference these dependent DLLs. I've added the IPPS-7.0.DLL containing folder to referenced paths as well as added references to the "IntelCppOptPkg" and "IntelLibOptPgk" assemblies but this has not solved the problem.
So, am I correct in believing this is the problem? And if so, how does one reference a depedent DLL in managed code?
Thank you.
You don't reference them, they are not .NET assemblies. You just need to make sure that the DLL(s) get copied to your build directory. Easiest way to do that is with Project + Add Existing Item, select the DLL from wherever it was copied. Then select the added file and in the Properties window set Build Action = Content, Copy to Output Directory = Copy if newer. Checking-in the DLL(s) in source control is generally a good idea btw.
Managed code can not reference unmanaged dll the same way it references managed assemblies. Managed references actually change the meta data of your assembly:
The compiler records static
references in the assembly manifest's metadata at build time.
...
The preferred way to reference an assembly is to use a full reference,
including the assembly name, version, culture, and public key token
(if one exists).
Native dlls simply don't have this .NET meta data associated with them. They have to be copied manually in the Post Build step or during deployment. There is a workaround but I don't think it will work if your managed app is platform independent (Any CPU) and you have x86 and x64 versions of unmanaged dlls.

Categories