What process does .NET use to locate a referenced assembly at runtime and is it different than the process used to locate a referenced assembly during compilation? I am specifically interested in the locations that are searched and their search order and any parameters/configuration settings that might affect the outcome.
While value types are stored generally in the stack, reference types are stored in the managed heap.
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.
The Find All References command is available on the context (right-click) menu of the element you want to find references to. Or, if you are a keyboard user, press Shift + F12.
There are three types of references that can be made in a .NET application. This answer will only cover the first two in the list below.
Every reference must be resolved. Reference resolution is the process of locating a concrete instance of a reference in the form of a file. Project references are resolved in the same way that file references are resolved. A project reference just allows you to reference assemblies that do not yet exist (because it is an output of the build process.)
It is important to understand that reference resolution occurs at both compile time and at runtime and the process for each is totally different. Failing to understand this point can lead to endless headache. Believe me, I know.
Runtime Reference Resolution (aka binding)
When an application in invoked, it must be loaded into memory. If an application uses objects in another assembly, that assembly must also be loaded into memory. The .NET framework uses the following process to do this.
For more information see http://msdn.microsoft.com/en-us/library/yx7xezcf%28v=vs.110%29.aspx.
Compile Time Reference Resolution
Compile time resolution occurs in MSBuild during the build process. MSBuild is the build engine used by both Visual Studio and TFS. Note that for ASP.NET applications, there is an extra compile step that occurs for dynamic components (aspx, asc, asax, cshtml, etc) when they are first accessed. Reference resolution for these two scenarios is described below.
MSBuild
Assembly resolution occurs in the ResolveAssemblyReferences MSBuild target. This target invokes the ResolveAssemblyReference task passing the value of the AssemblySearchPaths to the SearchPaths parameter which is assigned a value as follows.
<PropertyGroup>
<!--
The SearchPaths property is set to find assemblies in the following order:
(1) Files from current project - indicated by {CandidateAssemblyFiles}
(2) $(ReferencePath) - the reference path property, which comes from the .USER file.
(3) The hintpath from the referenced item itself, indicated by {HintPathFromItem}.
(4) The directory of MSBuild's "target" runtime from GetFrameworkPath.
The "target" runtime folder is the folder of the runtime that MSBuild is a part of.
(5) Registered assembly folders, indicated by {Registry:*,*,*}
(6) Legacy registered assembly folders, indicated by {AssemblyFolders}
(7) Resolve to the GAC.
(8) Treat the reference's Include as if it were a real file name.
(9) Look in the application's output folder (like bin\debug)
-->
<AssemblySearchPaths Condition=" '$(AssemblySearchPaths)' == ''">
{CandidateAssemblyFiles};
$(ReferencePath);
{HintPathFromItem};
{TargetFrameworkDirectory};
{Registry:$(FrameworkRegistryBase),$(TargetFrameworkVersion),$(AssemblyFoldersSuffix)$(AssemblyFoldersExConditions)};
{AssemblyFolders};
{GAC};
{RawFileName};
$(OutDir)
</AssemblySearchPaths>
There is a lot going on here and I don't claim to understand all of it, but I will try to point out the important parts.
<private>
element in the project file.ASP.NET Runtime Compiler
Unless previously compiled into the project output folder using the pre-compile option at build time, all dynamic content (aspx, asc, asax, cshtml, etc.) is compiled once at runtime when the application is first accessed. This dynamic content can also have dependencies on other assemblies. The system.web > compilation > assemblies element is used to tell the ASP.NET runtime compiler about these dependencies so that it can reference them.
The ASP.NET runtime compiler will search the following locations in order for these references.
Note that by default, the root web.config references a few system assemblies and all assemblies in the PAC using the wildcard syntax. This means that you will rarely ever be required to explicitly add references manually to the system.web > compilation > assemblies element. In many cases you can and should delete the element entirely. It should only contain references to assemblies stored in the GAC. Using Copy Local = true is the recommended approach to include non-GAC references required by the ASP.NET Runtime Compiler.
Also note that many subtle errors can occur if you use the system.web > compilation > assemblies element to specify a specific version number using the assembly's strong name. The ASP.NET runtime compiler will attempt to compile using the exact version you specify. This can cause problems if the non-dynamic components of the application were compiled against a different version of the assembly during the MSBuild compilation phase. This is often the case because MSBuild will use the latest version it can find and only the exact version if you set specific version = true.
Additional Resources:
http://jack.ukleja.com/diagnosing-asp-net-page-compilation-errors/ http://blog.fredrikhaglund.se/blog/2008/02/23/get-control-over-your-assembly-dependencies/ https://dhakshinamoorthy.wordpress.com/2011/10/01/msbuild-assembly-resolve-order/ http://www.beefycode.com/post/resolving-binary-references-in-msbuild.aspx
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With