«У меня работает»
Вот как я тестировал.Обратите внимание, что, как я написал в комментарии к вопросу, страница свойств проекта «Пути ссылки» существует только для традиционных проектов, но не для проектов в стиле SDK.
Я создал консольное приложение, добавил Dapper
и Newtonsoft.Json
пакетов, использующих packages.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]
.Итак, почему мой custom dapper.dll использовался, а не мой newtonsoft.json?
Откройте Командную строку разработчика, перейдите в каталог консоли приложения и запустите msbuild -bl -t:rebuild
, затем откройте msbuild.binlog
в MSBuild Структурированный Просмотр журнала .Я искал полный путь к одному из dll в моем эталонном пути и нашел его в результатах задачи ResolveAssemblyReference
.Расширяя некоторые интересные узлы в дереве, вот что я вижу:
Итак, мы можем видеть, что он выбрал мой 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".
Хорошо, поэтому Newtonsoft.Json.dll из пакета NuGet имеет строгое имя, а 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, который будет использоваться компилятором или средой выполнения вместо того, который указан в пакете.Однако, поскольку Newtonsoft.Json.dll имеет строгое подписанное имя, единственный способ, которым я могу обмануть компилятор или среду выполнения для загрузки своей пользовательской версии, - это если я могу создать сертификат, в котором открытый ключ совпадает с реальным открытым ключом Newtonsoft.Json, и затем подписатьмой пользовательский dll с этим сертификатом.
Наверху моего ответа вы могли заметить, что я написал, что я добавил ссылки на пакеты в свое консольное приложение, используя packages.config
.Это важно, потому что если вместо этого вы используете PackageReference
, цели и задачи сборки .NET не выполняют разрешение сборок одинаково и не используют ссылочные пути.