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
Related
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.
Our project has a lot of external DLLs, most but not all of which are 3rd party DLLs.
Currently we do not have these DLLs included in our project. They are included in SVN and given a path to our build output directory. So, after building our project the neccessary files are there, because of SVN, but the project itself has no knowledge of them.
My feeling is that we should have a folder under the root of our project named something like Dependancies or ThirdParty with all of the DLLs included there and set their build event to copy to the output directory. They would exist in SVN as well, but in the same structure as the project, not in the build output directory.
The project itself only references one of these DLLs called CommunicationProc.DLL. The CommunicationProc.DLL then references all of the other DLLs. We have numerous DLLs to support different types of radio. So not all DLLs will be used, but any one of them may be used depending on the radio type.
As to whether or not the DLLs should be included in the project we have differing opinions internally, some of the team beleives they should only be in SVN and not part of the project itself.
Of note is that this are not .NET DLLs, most are old C DLLs.
What is the accepted practice? Can someone please provide me with a compelling arguement one way or the other as to whether to include them in the project or just SVN?
Its better to have them in a folder on source control and then copy them over to the debug folder on build event. This way you can manage their versions. If a newer version of some dll comes then you can replace the old one and put some comments with check in. Also if you are working in a team, then instead of copying files from debug folder to each team member, you can let each team member to use the same set of dlls from source control. If you are developing some control and want your customers to use that control then its easier for you to have a set of dependent dlls some where so that you can give those to your customer along with your .Net dlls.
I had the same issue with some un-managed dlls and ended up putting them in a folder so that all the team members have the same version of the dlls. Hope this helps.
I include a project that has no code but contains a folder where all the external assemblies and their dependencies are kepts. For each file set the Build Action to None and Copy to Output as Do Not Copyp. The project then references the binaries from this location. In your other projects, reference this special project. When you build, because the special project is referenced and it references all the needed dependencies, the binaries are copied as needed.
If you do not want a special project, still create the folder in your main project, added the assemblies, set their properties, then reference the assemblies as needed.
This gives you complete control over the versions and output, and more importantly, it is simple.
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.
So I'm adding a "d" extension to my assembly name when building in debug mode. As far as I can tell the standard way to do this in C# is to edit the .csproj file and put in the following:
<PropertyGroup>
<AssemblyName Condition="'$(Configuration)' == 'V90 Debug'">$(AssemblyName)d</AssemblyName>
</PropertyGroup>
That has the desired effect, but now the darn project always rebuilds the output .dll, causing other projects that depend on it to relink, etc.. Without this change, I don't have any such problem.
So far increasing the verbosity of the project output hasn't helped.
Edit: An additional, important detail is that we're using names like "V90 Release", "V90 Debug", "V100 Release" etc.. for our configurations, so that we can target different versions of the Visual Studio runtime. I wrote a test app with the standard configuration names and found my problem doesn't happen in that case.
You are using an old standard in C/C++ development. The Big Difference with managed code is the absence of a linker. You used to configure the linker to use the "d" version of the library in the Debug build, the non-d version of the library in the Release build. That mechanism is completely absent in .NET, code in libraries are dynamically linked at runtime. Making the practically of having different names for different builds dramatically less.
One of the problems you'll encounter if you pursue this old strategy is that you'll have additional problems with the reference assemblies of a project. There is no decent way to use different names in different configurations. Dependent assemblies are listed in the Reference node of the project, this is a property of a project that is not configuration dependent. It is not impossible, you'll need a lot more Condition hacks to rename the reference assemblies. Build dependency checking is likely to be affected by this as well.
This is not actually necessary, the debug and release build of the assemblies will have the same metadata. But if you skip that, you'll now have a problem at runtime. The CLR will be told to use the wrong assembly name. Hacking around that is technically possible by hiding the assemblies in a sub-directory and using the AppDomain.AssemblyResolve event to load the correct one. You'll need a post-build event to rename and copy the assembly into this directory. This all gets ugly in a hurry when those assemblies have dependencies on other assemblies.
Long story short, your previous standard just isn't a good one for managed code.
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).