.NET 应用程序中可以进行三种类型的引用。此答案仅涵盖下面列表中的前两个。
- 文件参考。
- 项目参考
- 服务参考。
每个引用都必须得到解决。引用解析是以文件的形式定位引用的具体实例的过程。项目引用的解析方式与文件引用的解析方式相同。项目引用仅允许您引用尚不存在的程序集(因为它是构建过程的输出。)
重要的是要理解引用解析发生在编译时和运行时,并且每个过程都完全不同。如果不理解这一点,就会导致无尽的头痛。相信我,我知道。
运行时参考分辨率(又名绑定)
当一个应用程序被调用时,它必须被加载到内存中。如果应用程序使用另一个程序集中的对象,则该程序集也必须加载到内存中。 .NET 框架使用以下过程来执行此操作。
- Determine version of referenced assembly.
- The version of the referenced assembly is written to the applications manifest at compile time. This version will be used unless overridden in configuration.
- 应用程序/web.config
- 发布策略(覆盖 application/web.config)
- machine.config(覆盖发布策略和 application/web.config)
- 如果程序集之前已加载,则从缓存中重新使用。
- 如果提供了强名称,请搜索 GAC。
- Probe
- If codebase element specified, then use.
- 如果没有找到则绑定失败。
- 如果版本、区域性或公钥不匹配,则绑定失败。
- Search application base path. Matches by simple name and fails if first match is wrong version.
- 如果未提供区域性,则搜索 root,然后搜索 root/[程序集名称]
- 如果提供了区域性,则搜索 root/[culture],然后搜索 root/[culture]/[程序集名称]。
- 如果 web/app.config 指定探测元素,则在 privatePath 中搜索路径。路径必须相对于应用程序根目录。
欲了解更多信息,请参阅http://msdn.microsoft.com/en-us/library/yx7xezcf%28v=vs.110%29.aspx.
编译时参考分辨率
编译时解析发生在 MSBuild 的生成过程中。 MSBuild 是 Visual Studio 和 TFS 使用的构建引擎。请注意,对于 ASP.NET 应用程序,首次访问动态组件(aspx、asc、asax、cshtml 等)时会发生一个额外的编译步骤。下面描述了这两种情况的参考分辨率。
MSBuild
程序集解析发生在 ResolveAssemblyReferences MSBuild 目标中。此目标调用 ResolveAssemblyReference 任务,将 AssemblySearchPaths 的值传递给 SearchPaths 参数,该参数的值分配如下。
<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>
这里发生了很多事情,我并不声称理解了所有内容,但我会尽力指出重要的部分。
- The most common locations to find a reference are (in search order)
- 手动添加到项目的文件(例如/lib/coollib.dll>
- 由提示路径指定的位置。
- GAC
- 应用程序输出路径。
- 使用 Copy Local = true 标记的引用将复制到应用程序输出路径after汇编。这意味着此设置的值对 MSBuild 的参考解析过程没有影响。请注意,复制本地 UI 设置映射到
<private>
项目文件中的元素。
- MSBuild 将始终尝试使用给定程序集可用的最新版本,除非指定了特定版本 = true。此设置的默认值为 false,这意味着在搜索 GAC 时,无论项目定义中指定的版本如何,都将始终使用最新版本的 DLL。
ASP.NET 运行时编译器
除非在构建时使用预编译选项将其编译到项目输出文件夹中,否则所有动态内容(aspx、asc、asax、cshtml 等)都会在首次访问应用程序时在运行时编译一次。此动态内容还可以依赖于其他程序集。 system.web >compilation>assemblies 元素用于告诉 ASP.NET 运行时编译器这些依赖项,以便它可以引用它们。
ASP.NET 运行时编译器将搜索以下位置以查找这些引用。
- 应用程序私有程序集缓存(又名 PAC),即 /bin 文件夹。
- GAC(如果使用强名称指定引用)。
请注意,默认情况下,根 web.config 使用通配符语法引用一些系统程序集和 PAC 中的所有程序集。这意味着您很少需要手动显式添加对 system.web >compilation >assemblies 元素的引用。在许多情况下,您可以而且应该完全删除该元素。它应该只包含对存储在 GAC 中的程序集的引用。建议使用 Copy Local = true 方法来包含 ASP.NET 运行时编译器所需的非 GAC 引用。
另请注意,如果您使用 system.web >compilation >assemblies 元素通过程序集的强名称指定特定版本号,则可能会发生许多细微错误。 ASP.NET 运行时编译器将尝试使用exact您指定的版本。如果在 MSBuild 编译阶段针对不同版本的程序集编译应用程序的非动态组件,这可能会导致问题。这种情况经常发生,因为 MSBuild 将使用它可以找到的最新版本,并且如果您设置特定版本 = true,则仅使用确切的版本。
其他资源:
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