参考路径和Nuget

时间:2019-05-09 13:39:57

标签: path reference nuget

我想使用Visual Studio中的“引用路径”设置覆盖对dll的nuget包引用。这似乎不起作用。

因此,到目前为止,我删除了nuget包,并将引用添加为dll。但这恰好在您可以使用“引用路径”设置覆盖DLL的时候。

“引用路径”设置是否也应该覆盖nuget包引用?还是我错过了什么?

1 个答案:

答案 0 :(得分:0)

“为我工作”

这就是我的测试方式。请注意,正如我在对该问题的评论中所写的那样,项目属性页“参考路径”仅适用于传统项目,而不适用于SDK样式的项目。

我创建了一个控制台应用,使用Dapper添加了Newtonsoft.Jsonpackages.config软件包,并将我的program.cs更改为:

using Newtonsoft.Json;
using System;
using System.Collections.Generic;

namespace ReferencePathTest
{
    class Program
    {
        static void Main(string[] args)
        {
            var data = new List<int>() { Dapper.DbString.DefaultLength };
            Console.WriteLine(JsonConvert.SerializeObject(data));
        }
    }
}

运行它时,我的程序输出[4000]

接下来,我创建了一个名为Dapper的类库,将AssemblyReference.cs文件更改为将两个版本号都设置为1.60.0.0,然后将c#文件更改为:

namespace Dapper
{
    public class DbString
    {
        public static int DefaultLength => -1;
    }
}

我还创建了另一个名为Newtonsoft.Json的类库,将程序集版本更改为12.0.0.0,并将c#文件内容更改为:

namespace Newtonsoft.Json
{
    public class JsonConvert
    {
        public string SerializeObject(object o)
        {
            return "i'm a hacker";
        }
    }
}

编译两个类库,将程序集复制到目录,然后将该目录添加到引用路径列表中。重建控制台应用程序并运行它,现在我看到[-1]。那么,为什么要使用我的自定义dapper.dll而不使用我的自定义newtonsoft.json?

打开“开发人员命令提示符”,cd到控制台应用程序目录并运行msbuild -bl -t:rebuild,然后在MSBuild Structured Log Viewer中打开msbuild.binlog。我在参考路径中搜索了一个dll的完整路径,并在ResolveAssemblyReference任务的结果中找到了它。扩展树中一些有趣的节点,这是我看到的:

screenshot showing dapper.dll was selected from reference path, but newtonsoft.json was considered and rejected, before selecting the nuget package version of the DLL

因此,我们可以看到它选择了我的dapper.dll,并考虑了我的newtonsoft.json.dll,但是完整的消息被删减了。将其复制到剪贴板并粘贴到文本编辑器中,我可以看到完整的消息:

Considered "C:\Users\zivkan\source\repos\ReferencePathTest\ReferencePathTest\..\ReferencePath\Newtonsoft.Json.dll",
            but its name "Newtonsoft.Json, Version = 12.0.0.0, Culture=neutral, PublicKeyToken=null"
            didn't match the expected name "Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed".

好,因此NuGet包中的Newtonsoft.Json.dll是强名称签名的,而Dapper.dll没有强符号签名,但是编译器如何知道?好吧,看看您的csproj:

    <Reference Include="Dapper, Version=1.60.0.0, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\packages\Dapper.1.60.6\lib\net451\Dapper.dll</HintPath>
      <Private>True</Private>
    </Reference>
    <Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
      <HintPath>..\packages\Newtonsoft.Json.12.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
    </Reference>

因此,当您安装软件包时,NuGet进行资产选择,然后告诉项目系统使用程序集全名为csproj添加引用。由于Dapper.dll不是强名称签名,因此我们可以简单地创建一个自定义Dapper.dll,编译器或运行时将使用该自定义Dapper.dll,而不是软件包中的那个。但是,由于Newtonsoft.Json.dll是强名称签名的,因此,我可以欺骗编译器或运行时加载自定义版本的唯一方法是,如果我可以创建一个公钥与Newtonsoft.Json的真实公钥匹配的证书,然后进行签名我带有该证书的自定义dll。

在回答的顶部,您可能已经注意到我写了使用packages.config向我的控制台应用添加程序包引用的信息。这很重要,因为如果您改用PackageReference,则.NET构建目标和任务不会以相同的方式进行程序集解析,并且不会使用引用路径。