Подтвердить что ты не робот

Невозможно решить проблему сборки сборки без фреймворков

Я пытаюсь проверить, что Буферы протоколов будут работать с новыми переносимыми сеансами работы из команды 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), но путают меня:

  • Изменение вызова Console.WriteLine только Console.WriteLine("foo") (но никаких других изменений)
  • Изменение типа переменной duration на object вместо duration
  • Полностью удалить все намеки на буферы протокола и вместо этого использовать TimeSpan или аналогичные
  • Добавление следующего в project.json в разделе dnx451:

    "frameworkAssemblies": {
      "System.Runtime": ""
    }
    

В конечном счете, я не хочу, чтобы пользователи должны были это делать - по крайней мере, не для протокольных буферов. Я предполагаю, что это связано с тем, как мы создаем протокольные буферы, но поскольку я не понимаю причину правильно, ее трудно исправить.

Я ожидаю, что если бы я смог разработать способ ввода записи dependencies, я мог бы затем добавить эту зависимость в сами буферы протоколов, что было бы неплохо, но как имеющее зависимость от System.Runtime v4.0.0 в файле project.lock, похоже, не помогает, я должен что-то пропустить: (

4b9b3361

Ответ 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".