2015-12-07 2 views
53

Я пытаюсь проверить, что Protocol Buffers будет работать с новыми портативными средами выполнения из команды ASP.NET и в идеале в большинстве других современных сред. Недавно была создана сборка 3.0.0-alpha4 с использованием profile259, поэтому я ожидал, что некоторые изменения потребуются в некоторых случаях, но я думал, что попробую. Я знаю Oren Novotny's post about targeting .NET Core и ожидаю, что вам нужно внести некоторые изменения в Google.Protobuf nuspec file, но ошибка, с которой я столкнулся, сильно захлебнулась.Невозможно решить проблему с ссылкой на сборку без фреймворков

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 терпит неудачу с:

Error: c:\Users\Jon\Test\Projects\protobuf-coreclr\src\ProtobufTest\Program.cs(9,9): DNX,Version=v4.5.1 error CS0012: The type 'Object' is defined in an assembly that is not referenced. You must add a reference to assembly '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, похоже, не помогает, мне должно быть что-то не хватает :(

+1

я ударил очень похожую ошибку для простой библиотеки классов. Найдено два способа изменения файла project.json, чтобы исправить проблему - http://nodogmablog.bryanhogan.net/2016/01/the-type-is-defined-in-an-assembly-that-is-not-referenced -system-runtime/ – Bryan

ответ

21

Итак, если вы косоглазие и посмотрите на project.json, это в основном nuspec с небольшим количеством ошибок, чтобы описать, какие параметры компиляции и источники необходимы для создания проекта. Сегодня у Nuspecs есть 2 раздела, frameworkAssemblies для «встроенных» вещей и dependencies для других зависимостей nuget. Здесь он имеет то же значение.Когда вы используете что-то из «рамки», его необходимо указать в frameworkAssemblies, а не в зависимости от пакета.

Теперь на специфику:

При использовании PCL или библиотеки на основе .NET Core, на платформе .NET Framework, ссылки должны ссылаться на узлы (иногда называемые контрактные узлы). Вот некоторые примеры таких вещей, как System.Runtime, System.Threading и т. Д. При использовании проектов на основе MSBUILD выполняется задание, которое в основном автоматически добавляет из System.* ссылок на компилятор C#, чтобы избежать этого беспорядка. Эти сборки называются фасадами на .NET Framework. К несчастью, он добавляет ВСЕХ из них, даже если они не используются. Зависимость от System.Runtime является триггером для этого поведения (при работе на файлах csproj на платформе .NET Framework).

Причина, по которой добавление ссылки на один и тот же пакет не работает, заключается в том, что папка .NET Framework (net4 *) для этих контрактных сборок (например, System.Runtime) не имеет в ней никаких DLL. Если вы посмотрите на эти папки, вы увидите пустой файл _._. Причиной этому является то, что когда вы объявляете пакет nuget с ссылкой frameworkAssembly на System.Runtime, системы проекта msbuild не могут его установить (очень сложная ошибка и проблема проектирования).

Это, вероятно, сделали вещи нечеткой ...

+0

Итак, просто для пояснения, является ли решение добавить ссылку «frameworkAssembly» в пакете Google.Protobuf, привязанного к конкретной целевой платформе? –

+0

@JonSkeet вы можете добавить его как '" frameworkAssemblies ": {" System.Runtime ": {" type ":" build "," version ":" "}}' поэтому он не попадает в окончательный файл nuspec, который должен быть более чистым решением. –

+0

@AxelHeer: Я только использовал '' type ":" build "' для включения источника до сих пор ... что это означает для сборки фреймов? И вы предлагаете положить это в файл Protobuf nuspec или в project.json моего консольного приложения? –

5

Мне кажется, что ваша проблема существует только потому, что вы выбрали консольное приложение вместо «ASP.NET Web Application»/ASP.NET 5 Шаблоны "/" Пустой ". Я сделал простое использование теста Пустой шаблон, добавили "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 в веб-браузере.

Вы можете скачать демонстрационный проект с here.

ОБНОВЛЕНО: Я проанализировал проблему с чисто консольное приложение 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); 
     } 
    } 
} 

можно загрузить рабочий проект от here.

Я заметил, кроме того, линия

//[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 пространства имен (для Console.WriteLine) существуют в mscorlib из DNX 4.5.1.Если один попытается добавить "System.Console": "4.0.0-beta-23516" на уровне общих зависимостей один получаю ошибку при стартах с текстом

Error CS0433 The type 'Console' exists in both 'System.Console, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' and 'mscorlib, Version=4.0.0.0, Culture=neutral, 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() вызовы the lines, которые используют the lines для форматирования. Похоже, что код duration.ToString() действительно соответствует ((object)duration).ToString() для WellKnownTypes типов (например, Duration).

Последнее замечание, которое я нахожу важным. Описанная проблема существует только для dnx451 (или dnx452 или dnx46). Если бы удалить линии

"dnx451": { }, 

из "frameworks" части project.json тогда программа будет компилирует для DNX Ядро 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, но теперь зависимости будет правильно решена.

The final project может быть скомпилирован без проблем как для dnx451, так и для dnxcore50. Я интерпретирую результаты следующим образом: «Google.Protobuf» работает как с dnx451, так и с dnxcore50, но автоматическое решение проблемы RC1 по-прежнему не работает и не может правильно разрешить некоторые требуемые зависимости «Google.Protobuf».

Причина, связанная с добавлением непосредственно ненужных "Microsoft.AspNet.Hosting": "1.0.0-rc1-final" Ссылка может рассматриваться как обходное решение. Я думаю, что разрешение зависимостей, используемое в ASP.NET 5 и DNX, по-прежнему не работает. Я отправил некоторое время до the issue, который все еще открыт. Эта проблема представляет собой пример, когда разрешение прямого включения зависимостей может предоставить еще результатов в зависимости от разрешений, разрешенных dnu restore. Именно по этой причине я начал сравнивать зависимость рабочего кода , которую я изначально выложил с зависимостями неработающего проекта. После некоторых тестов я нашел обходное решение и уменьшил его до единственной зависимости: "Microsoft.AspNet.Hosting": "1.0.0-rc1-final".

+0

Но я хочу, чтобы библиотека работала из консольных приложений, а также из веб-приложений. Дело в том, что он предназначен для переносимости ... когда я сказал «ASP.NET v5», я имел в виду, что во всех отношениях ... ASP.NET, похоже, означает больше, чем веб-приложения в эти дни ... прояснит вопрос , –

+0

Вы писали про "ASP.NET v5". Вы хотите протестировать его с помощью DNX Core 5.0? Если вам нужно приложение «ASP.NET v5», и вы не хотите запускать внутри консоли, что вы должны изменить начало приложения. Project.json имеют '' Microsoft.AspNet.Server.Kestrel '' как зависимость и 'web' как' command'. Это позволяет запускать приложение как самостоятельный хостинг в консольном приложении. Нужно использовать еще одно приложение ASP.NET, как и раньше. Результаты будут отображаться не на консоли, а в браузере вместо этого (на стороне клиента). – Oleg

+0

Я хочу протестировать его с помощью различных сред выполнения, используя новые среды выполнения, созданные командой ASP.NET v5. dnxcore50 уже работает, поэтому это не в моем вопросе. На данный момент меня не интересует веб-приложение. Я пытаюсь получить консольное приложение, работающее с целью dnx451, согласно project.json. –

8

Я принял David Fowler's answer в качестве причины, почему все это произошло. Теперь с точки зрения того, что я должен делать об этом, похоже, мне просто нужно добавить frameworkAssemblies элемент в nuspec файл для Google.Protobuf:

<package> 
    <metadata> 
    ... 
    <frameworkAssemblies> 
     <frameworkAssembly assemblyName="System.Runtime" targetFramework="net45" /> 
    </frameworkAssemblies> 
    </metadata> 
    ... 
</package> 

Это frameworkAssembly ссылка затем попадает в project.lock.json в клиенте проекта, и все хорошо.

Однако, судя по другому комментарию Давида («Мы будем смотреть на фиксируя это») Я не нужно ничего делать в любом случае ...

+0

Эта информация, по-видимому, интересна разработчикам пакетов NuGet. Было бы неплохо добавить к вашему тегу больше тегов (nuget, nuspec и т. Д.), Чтобы информация была проиндексирована и была найдена. – Oleg

+0

@Oleg: Кажется разумным. Готово. –

 Смежные вопросы

  • Нет связанных вопросов^_^