.NET Core assembly search order - c#

In .NET Framework, the loader searches dependencies in current folder and then in GAC.
But in .NET Core there is no GAC, so does .NET Core assembly loader only search assemblies in current folder or in global nuget cache(someuser/.nuget/packages folder) also?
Also I found a /usr/local/share/dotnet/shared folder in my Mac(C:\Program Files\dotnet\shared in Windows) where all base libraries are located, like System.Runtime.dll, System.Collections.dll.
Does assembly loader looks there too?
Also I found that these base libraries are duplicated also in in global nuget cache.
Why?

The directories used by the PackageCompilationAssemblyResolver will be largely dependent on your environment. However, they may include:
C:\Program Files\dotnet\store\x64\netcoreapp2.0 (or equivalent path for your machine)
C:\Users\{user}\.nuget\packages
C:\Program Files\dotnet\sdk\NuGetFallbackFolder
Note that this is just for packages (i.e NuGet). Other assembly resolvers exist for references and application assemblies...
Note that if you are using an assembly resolver directly in your code, you can specify the paths used for resolution as follows:
ICompilationAssemblyResolver assemblyResolver = new CompositeCompilationAssemblyResolver
(new ICompilationAssemblyResolver[]
{
new AppBaseCompilationAssemblyResolver(basePath), //e.g. project path
new ReferenceAssemblyPathResolver(defaultReferenceAssembliesPath, fallbackSearchPaths),
new PackageCompilationAssemblyResolver(nugetPackageDirectory) //e.g. C:\Users\\{user}\\.nuget\packages
});
For more details on managing the resolution of assemblies within you code, see this article - Resolving Assemblies in .NET Core

.Net core is based on Nuget packages being cross platform. NET Core applications rely heavily on NuGet to resolve their dependencies, which simplifies development.
You can check link Is there any GAC equivalent for .NET Core?

Related

Microsoft libraries missing when compiling .NET5 project

I'm trying to decompile ASP.NET Core WebApi project and gather all methods from all controllers. When my project targeted .NETCore3.1 it worked by running this code:
Assembly assembly = Assembly.LoadFrom(assemblyPath); // assemblyPath pointed to .dll
var types = assembly.GetExportedTypes();
But after updating to .NET5, the second line (assembly.GetExportedTypes()) from above throws an exception that file Microsoft.AspNetCore.Mvc.Core.dll is missing. When I copied that file manually from an old project (compiled as .NETCore3.1), it worked!
On the top of that, when project is more complicated, has EFCore dependency and more... more files are missing when compiling the project under .NET5. These are:
Microsoft.Extensions.Hosting.Abstractions.dll
Microsoft.AspNetCore.Mvc.Abstractions.dll
Microsoft.AspNetCore.Authentication.Abstractions.dll
I have two questions:
Why these files are not copied to the output folder?
How can I properly read all endpoints/methods in Controllers having complied binaries of the ASP.NET WebApi? Am I doing something wrong?
Steps to reproduce:
Create ASP.NET Core WebApi project targeting .NET5.
Create other project that targets .NET5 and implement these two lines:
var assemblyPath = "C:\\Projects\\Other\\DotNet5Test\\DotNet5Test\\DotNet5Test.WebApi\\bin\\Debug\\net5.0\\DotNet5Test.WebApi.dll";
Assembly assembly = Assembly.LoadFrom(assemblyPath);
var types = assembly.GetExportedTypes();
Run it
EDIT:
I tried adding Microsoft.AspNetCore.Mvc.Core from nuget, but Microsoft.AspNetCore.Mvc.Core.dll is not being added to the output folder
I've had similar issues sporadically with various projects in the past. The most reliable solution for me has been to install any problematic libraries through the nuget packet manager. Remove any dependency files you manually added before doing this.
I think the issue is that Microsoft.AspNetCore.Mvc.Core.dll ships as part of the framework-dependent deployment (FDD) rather than self-contained deployment (SCD) see the accepted answer Is there any GAC equivalent for .NET Core?.
Given I saw this question of yours posted earlier, How to retrieve Controller methods from WebApi binaries? I have a feeling you are trying to execute the code from a wpf application targeting .net 5 but the app is not able to use FDD to resolve the assembly.
The answer may be that you need to change your webapi app to use an SCD deployment model, but not having used SCD for web apps perhaps google will help.

NuGet dependencies in MEF loaded assemblies

I am trying to code an application in C#.NET Core that can be extended using MEF. Currently, I am able to do that without any issues with libraries, that have no dependencies or have the same dependencies as the host app (so dependencies are already loaded). But, if I want to use a library with a NuGet reference, that is not used by the main app, the loading of this library fails on that reference.
How can I force the main app to load the missing NuGet dependency, if it tries to load an assembly with such reference? It seems to me as a pretty common use case, but I am lost here and cannot find a way out. Thanks.
For reference, I am posting the portion of the code.
[ImportMany]
private IEnumerable<Lazy<IService, IServiceMetadata>> _asrServices;
...
var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new DirectoryCatalog(Path.Combine(Directory.GetCurrentDirectory(), "Services")));
CompositionContainer _container = new CompositionContainer(catalog);
...
foreach (Lazy<IService, IServiceMetadata> _service in _asrServices)
{
var _serviceInstance = _service.Value // here the loading fails
}
Jiri
.NET currently has two build "systems". One is the original project files, that import Microsoft.Common.props and Microsoft.CSharp.targets (assuming it's a c# project) and lots of XML in between, that has been around ever since .NET was first released, apparently in 2002. Since .NET Core was made generally available in 2016 there has been a new project system generally called SDK projects because the way a *proj file references the build system is though an Sdk element or attribute in the msbuild xml. Although it's off-topic, because there's a common bad assumption, I want to point out that although SDK projects were created for .NET Core, you can target the .NET Framework from SDK projects.
With the original project files, when you build, all the projects references get copied to the output directory. However, with SDK projects, only the project's assembly is copied to output (I'm not sure, but I think even content set to copy to output doesn't actually get copied on build). In order to get everything in a single directory, you should use the dotnet cli's publish command.
So, if you have a build script that builds your project and copies all the plugins somewhere, you should add a dotnet publish step to the script for each plugin using the SDK style project file.

How .NET applications compiled with old .NET Framework Assemblies still be able resolve newer .NET Framework assemblies

I have been looking for an answer to that but so far I have not been able to. For those who are not familiar with the basis of my question, here is some explanation to that.
Context
You can have two types of assembly in .NET when it comes to naming your assemblies:
Strong-named Assemblies
Simple-named Assemblies (aka Weakly-named Assemblies as coined by Jeffrey Richter in his CLR via C# book).
Unlike Simple-named Assemblies, the Strong-named assemblies are signed with a public/private key. Related to my question, one of the benefits of signing the assembly is the following:
Now the version number of your assembly becomes important. Assemblies
contain a static reference to other assemblies that they use the types of. When they reference a strong-named assembly, you must give them
that same exact assembly with the exact signature (name, version,
culture, and public key token). Otherwise, the fusion assembly loader
will fail at resolving it.
Also, strong-named assemblies can only reference other strong-named assemblies but not simple-named assemblies.
Question
Based on what I have described, I also expect the same rules to be applied to referencing .NET Framework assemblies. Meaning that my assemblies will search for exact versions of the referenced assemblies that are shipped with a .NET Framework that I originally used the assemblies of in my compiled application. However, when you upgrade from .NET 4.5 to 4.7, without re-compiling your application, your application is still working and supposed to be working. How is that possible and how does Microsoft manages that? Do they apply an exception to their assemblies in the fusion loader so that it always loads the latest .NET Framework assemblies for user-developed applications? Does it use a bindingRedirect internally for each possible old version to new version? Do they use publishers policies?
I feel like the answer is hidden in this text:
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.
... -- Microsoft Doc
Other notes:
Specific Version
For some, there is a misconception about Specific Version = true flag, which can be changed in Visual Studio when referencing an assembly. This flag is for compile-time checking only and has nothing to do with the runtime assembly resolution. In fact, the assembly will still have the strong name including assembly name, version, and public key token (if exists).
An Extra Quick Question: By Default?
By default, the runtime attempts to bind with the exact version of an
assembly that the application was built with.
says, Microsoft. It confuses me a little bit. Does it mean that version number is important for both weakly-named and strong-named assemblies to get resolved? For instance, if I drop a weakly-named assembly with an incremented version number, then will it not be resolved by other assemblies that are referencing the older version of it?

Where assemblies are loaded from?

We have an azure service. The solution for it includes several projects. Some of projects references azure.storage ver. 4.2.1. Based on nugget.org the dependencies for azure.storage are odata, edm etc >= 5.6.0. We want to use the latest one 5.6.3. So we added to the projects references references to all dependent assemblies from version 5.6.3 (despite that ILSPY shows that the dependencies are for ver 5.6.0). But unfortunately the loaded dlls are from gac with version 5.6.0. (not from the path we referenced with the latest version)
How the dlls are loaded ?:
Based on Force load an assembly from the /bin and not the GAC? and http://msdn.microsoft.com/en-us/library/yx7xezcf.aspx - it loads assemblies from GAC firstable
Based on http://blogs.msdn.com/b/manishagarwal/archive/2005/09/28/474769.aspx and Microsoft.Common.CurrentVersion.targets it should look first in bin directory - not gac.
What is correct? And how (it at all) can I achieve what I try to do?
You are comparing the resolving of an assembly for compilation to the resolving of assemblies on execution.
Both your points and their references are true, but only for their specific situation. Your #2 references explains the compilation process assembly resolving, your #1 references talk about the execution process.

How to prevent a .NET application from loading/referencing an assembly from the GAC?

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).

Categories

Resources