Невозможно решить проблему сборки сборки без фреймворков
Я пытаюсь проверить, что Буферы протоколов будут работать с новыми переносимыми сеансами работы из команды ASP.NET и, в идеале, большинства других современных сред. Недавно была создана сборка 3.0.0-alpha4 с использованием profile259, поэтому я ожидал, что некоторые изменения потребуются в некоторых случаях, но я думал, что попробую. Я знаю сообщение "Орен Новотный" о таргетинге на .NET Core и должен внести некоторые изменения в Google. Файл Protobuf nuspec, но ошибка, с которой я сталкиваюсь, меня озадачила.
Версия DNX: 1.0.0-rc1-update1
Сценарий, который я пытаюсь проверить, - это приложение для консольного приложения dnx451. У меня очень простое примерное приложение:
using Google.Protobuf.WellKnownTypes;
using System;
public class Program
{
public static void Main(string[] args)
{
Duration duration = new Duration { Seconds = 100, Nanos = 5555 };
Console.WriteLine(duration);
}
}
... и крошечный project.json
:
{
"compilationOptions": { "emitEntryPoint": true },
"dependencies": { "Google.Protobuf": "3.0.0-alpha4" },
"frameworks": {
"dnx451": { }
}
}
Обратите внимание, что я даже не использую dnxcore*
здесь - по иронии судьбы, я получил это, чтобы работать без проблем.
dnu restore
работает нормально; dnx run
не удается:
Ошибка: c:\Users\Jon\Test\Projects\protobuf-coreclr\src\ProtobufTest\Program.cs(9,9): DNX, версия = v4.5.1 ошибка CS0012: Тип "Объект" определен в сборке, на которую не ссылаются. Вы должны добавить ссылку на сборку "System.Runtime, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b03f5f7f11d50a3a".
Следующие изменения приводят к той же ошибке:
- Явное добавление зависимости
"System.Runtime": "4.0.0"
в разделе dependencies
для фреймворка
- Явное добавление зависимости
"System.Runtime": "4.0.0-beta-23109"
в разделе dependencies
для фреймворка, а также для 4.0.10-beta-*
, 4.0.20-beta-*
и 4.0.21-beta*
.
- Добавление зависимостей к
System.Runtime
в пакете NuGet (локально) и восстановление по сравнению с этим - project.lock.json
было обновлено, чтобы включить System.Runtime v4.0.0, но произошла такая же ошибка
- Ditto, включая каталог
lib\dotnet
в пакете, а также зависимости
Шаги, которые работали (независимо и без записей dependencies
), но путают меня:
В конечном счете, я не хочу, чтобы пользователи должны были это делать - по крайней мере, не для протокольных буферов. Я предполагаю, что это связано с тем, как мы создаем протокольные буферы, но поскольку я не понимаю причину правильно, ее трудно исправить.
Я ожидаю, что если бы я смог разработать способ ввода записи dependencies
, я мог бы затем добавить эту зависимость в сами буферы протоколов, что было бы неплохо, но как имеющее зависимость от System.Runtime v4.0.0 в файле project.lock, похоже, не помогает, я должен что-то пропустить: (
Ответы
Ответ 1
Итак, если вы прищурились и посмотрели на project.json, в основном это nuspec с небольшим количеством ошибок, чтобы описать, какие параметры компиляции и источники необходимы для создания проекта. Сегодня у Nuspecs есть 2 раздела, frameworkAssemblies
для "встроенных" и dependencies
для других зависимостей nuget. Здесь он имеет то же значение. Когда вы используете что-то из "рамки", его нужно указать в frameworkAssemblies
vs, являющемся зависимостью пакета nuget.
Теперь о специфике:
Когда вы используете библиотеку PCL или .NET Core на платформе .NET Framework, ссылки ссылаются на сборки (иногда называемые контрактными сборками). Вот некоторые примеры таких вещей, как System.Runtime
, System.Threading
и т.д. При использовании проектов на основе MSBUILD выполняется задание, которое в основном автоматически добавляет все ссылки System.*
к компилятору С#, чтобы избежать этого беспорядка. Эти сборки называются фасадами на .NET Framework. Несчастная часть состоит в том, что она добавляет ВСЕ, даже если они не используются. Зависимость от System.Runtime
является триггером для этого поведения (при работе в файлах csproj на платформе .NET Framework).
Причина добавления ссылки на один и тот же пакет не работает, потому что папка .NET Framework (net4 *) для этих контрактных сборок (например, System.Runtime) не имеет в ней никаких DLL. Если вы посмотрите на эти папки, вы увидите пустой файл _._
. Причиной этого является то, что когда вы объявляете пакет nuget с ссылкой frameworkAssembly
на System.Runtime
, системные проекты msbuild не могут его установить (очень сложная ошибка и проблема проектирования).
Это, вероятно, сделало вещи более сумасшедшими...
Ответ 2
Я принял ответ Дэвида Фаулера в качестве причины, почему все это произошло. Теперь с точки зрения того, что я должен сделать с этим, похоже, мне просто нужно добавить элемент frameworkAssemblies
в файл nuspec для Google.Protobuf
:
<package>
<metadata>
...
<frameworkAssemblies>
<frameworkAssembly assemblyName="System.Runtime" targetFramework="net45" />
</frameworkAssemblies>
</metadata>
...
</package>
Ссылка frameworkAssembly
затем заканчивается в project.lock.json
в проекте клиента, и все хорошо.
Однако, судя по мнению Дэвида, комментарий ( "Мы посмотрим на исправление этого" ), мне все равно ничего не нужно делать...
Ответ 3
Мне кажется, что ваша проблема существует только потому, что вы выбрали консольное приложение вместо "ASP.NET Web Application" / "ASP.NET 5 Templates" / "Empty". Я сделал простое тестовое использование Пустой шаблон, добавил "Google.Protobuf": "3.0.0-alpha4"
из NuGet и, наконец, только что изменил Startup.cs
, чтобы он использовал Google.Protobuf.WellKnownTypes
:
- добавлено
using Google.Protobuf.WellKnownTypes;
- добавлен
var duration = new Duration { Seconds = 100, Nanos = 5555 };
внутри Configure
- изменен
await context.Response.WriteAsync("Hallo World!");
на await context.Response.WriteAsync(duration.ToString());
Окончательный код Startup.cs
:
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Http;
using Microsoft.Extensions.DependencyInjection;
using Google.Protobuf.WellKnownTypes;
namespace ProtobufTest
{
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app)
{
app.UseIISPlatformHandler();
var duration = new Duration { Seconds = 100, Nanos = 5555 };
app.Run(async context =>
{
await context.Response.WriteAsync(duration.ToString());
});
}
// Entry point for the application.
public static void Main(string[] args) => WebApplication.Run<Startup>(args);
}
}
Полученное приложение ASP.NET 5 успешно отобразилось 100.5555s
в веб-браузере.
Вы можете скачать демо-проект из здесь.
ОБНОВЛЕНО: Я проанализировал проблему с помощью чистого консольного приложения DNX, которое использует код и может найти причину проблемы в методе duration.ToString()
, который работает в среде ASP.NET, но не в чистом консольном приложении. Причина проблемы интересна, и я пытаюсь расследовать, но я хотел поделиться своими текущими результатами с другими
Я мог бы сделать следующий код:
using Google.Protobuf.WellKnownTypes;
using System;
namespace ConsoleApp3
{
public class Program
{
public static void Main(string[] args)
{
var duration = new Duration { Seconds = 100, Nanos = 5555 };
Console.WriteLine("{0}.{1:D4}s", duration.Seconds, duration.Nanos);
}
}
}
Можно загрузить рабочий проект из здесь.
Я дополнительно прокомментировал строку
//[assembly: Guid("b31eb124-49f7-40bd-b39f-38db8f45def3")]
в AssemblyInfo.cs
, чтобы не иметь ненужной ссылки на "Microsoft.CSharp"
, которые содержат много других ссылок. project.json
содержится в демонстрационном проекте:
{
...
"dependencies": {
"Google.Protobuf": "3.0.0-alpha4"
},
"frameworks": {
"dnx451": { },
"dnxcore50": {
"dependencies": {
"System.Console": "4.0.0-beta-23516"
}
}
}
}
Кстати, в том числе "System.Console": "4.0.0-beta-23516"
в "dnxcore50"
требуется часть "frameworks"
, потому что Console
namespace (для Console.WriteLine
) существует в mscorlib
of DNX 4.5.1
. Если попытаться добавить "System.Console": "4.0.0-beta-23516"
на уровень общих зависимостей, то получите ошибку с запуском с текстом
Ошибка CS0433 Тип "Консоль" существует как в "System.Console", Версия = 4.0.0.0, Культура = нейтраль, PublicKeyToken = b03f5f7f11d50a3a 'и 'mscorlib, Version = 4.0.0.0, Culture = нейтральный, PublicKeyToken = b77a5c561934e089 'ConsoleApp3.DNX 4.5.1
ОБНОВЛЕНО 2: Можно заменить строку
Console.WriteLine("{0}.{1:D4}s", duration.Seconds, duration.Nanos);
к
Console.WriteLine((object)duration);
чтобы заставить его работать. Просто использование Console.WriteLine(duration);
или var str = duration.ToString();
вызывает описанную вами ошибку.
ОБНОВЛЕНО 3: Я подтвердил, что код duration.ToString()
вызывает строки, которые используют строки для форматирования. Кажется, что код duration.ToString()
действительно такой же, как ((object)duration).ToString()
для WellKnownTypes
типов (например, Duration
).
Последнее замечание, которое я считаю важным. Описанная проблема существует только для dnx451 (или dnx452 или dnx46). Если бы удалить строки
"dnx451": { },
из "frameworks"
части project.json
, тогда программа будет компилироваться только для DNX Core 5.0 ("dnxcore50"
). Можно легко убедиться, что у вас больше не будет проблем.
ОБНОВЛЕНО 4: Наконец, я нашел очень простой способ обхода проблемы: нужно просто добавить зависимость "Microsoft.AspNet.Hosting": "1.0.0-rc1-final"
к проекту:
{
"dependencies": {
"Google.Protobuf": "3.0.0-alpha4",
"Microsoft.AspNet.Hosting": "1.0.0-rc1-final"
}
}
Это приводит к загрузке многих ненужных dll, но теперь зависимости будут корректно разрешены.
Окончательный проект может быть скомпилирован без проблем как для dnx451, так и для dnxcore50. Я интерпретирую результаты следующим образом: "Google.Protobuf" работает как с dnx451, так и с dnxcore50, но автоматическое решение проблемы с RC1 по-прежнему не работает и не может правильно разрешить некоторые требуемые зависимости "Google.Protobuf".
Из-за необходимости добавления непосредственно ненужной ссылки "Microsoft.AspNet.Hosting": "1.0.0-rc1-final"
можно рассматривать только как обходной путь. Я думаю, что разрешение зависимостей, используемое в ASP.NET 5 и DNX, по-прежнему не работает. Я опубликовал некоторое время до вопрос, который все еще открыт. Проблема представляет собой пример, когда разрешение прямой включенной зависимости может предоставить другие результаты в качестве зависимостей, разрешенных dnu restore
. Именно по этой причине я начал сравнивать зависимость рабочего кода, которую я изначально выложил с зависимостями неработающего проекта. После некоторых тестов я нашел обходной путь и уменьшил его до единственной зависимости: "Microsoft.AspNet.Hosting": "1.0.0-rc1-final"
.