如果没有框架组件,无法解决程序集引用问题

我试图validation协议缓冲区将从ASP.NET团队和理想的大多数其他现代环境的新便携式运行时工作。 3.0.0-alpha4版本是在前一段时间使用profile259创build的,因此我希望在某些情况下需要进行一些更改,但是我认为我会试一试。 我知道Oren Novotny关于.NET Core的文章 ,并期望对Google.Protobuf nuspec文件进行一些更改,但是我遇到的错误让我难以理解 。

DNX版本:1.0.0-rc1-update1

我目前正在testing的场景是一个面向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:types'Object'没有被引用。 您必须添加对程序集“System.Runtime,Version = 4.0.0.0,Culture = neutral,PublicKeyToken = b03f5f7f11d50a3a”的引用。

以下更改导致相同的错误:

  • 在框架的dependencies部分显式地添加一个依赖到"System.Runtime": "4.0.0"
  • 在框架的dependencies部分显式地添加一个依赖到"System.Runtime": "4.0.0-beta-23109" ,同样对于4.0.10-beta-*4.0.20-beta-*4.0.21-beta*
  • 在NuGet包(本地)中添加对System.Runtime依赖关系,并根据此重build – project.lock.json已更新为包含System.Runtime v4.0.0,但发生了相同的错误
  • 同上包括一个lib\dotnet目录,以及依赖关系

确实有效的步骤(独立,没有dependencies条目),但让我困惑:

  • Console.WriteLine调用更改为Console.WriteLine Console.WriteLine("foo") (但没有其他更改)
  • durationvariables的types更改为object而不是Duration
  • 完全删除所有的协议缓冲提示,而是使用TimeSpan或类似的
  • 将以下内容添加到dnx451部分的project.json中:

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

最终,我不希望用户必须这样做 – 至less,不是为了Protocol Buffers。 我假设这与我们如何构build协议缓冲区有关,但是由于我不能正确理解原因,所以很难解决。

我期望如果我可以find一种方法来创build一个dependencies条目,那么我可以将这个依赖关系添加到Protocol Buffers本身中,这很好 – 但是在project.lock中具有对System.Runtime v4.0.0的依赖文件似乎没有帮助,我必须缺less的东西:(

所以,如果你眯着眼睛看project.json,它基本上是一个nuspec,用一点点goop来描述构build项目所需的编译选项和源代码。 今天的Nuspecs有2个部分, frameworkAssemblies用于“内置”的东西以及其他nuget依赖关系的依赖关系。 这里有相同的意思。 当你使用“框架”中的某些东西时,需要在frameworkAssemblies指定它作为nuget包的依赖关系。

现在到具体:

在.NET Framework上使用基于PCL或.NET Core的库时,引用将引用程序集(有时称为合约程序集)。 这些例子是像System.RuntimeSystem.Threading等东西。当使用基于MSBUILD的项目,有一个任务运行,基本上自动添加到C#编译器的所有System.*引用,以避免这个混乱。 这些程序集在.NET Framework上称为Facade。 不幸的是,即使没有使用它们,也会增加它们。 对System.Runtime的依赖性是此行为的触发器(在基于.NET Framework的csproj文件上运行时)。

添加对同一个包的引用不起作用的原因是因为这些合约程序集(如System.Runtime)的.NET Framework文件夹(net4 *)没有任何dll。 如果你看这些文件夹,你会看到一个空的_._文件。 原因是因为当你声明一个带有对System.RuntimeframeworkAssembly引用的nuget包时,msbuild项目系统无法安装它(非常复杂的错误和devise问题)。

这可能会让事情变得更模糊

我已经接受了大卫·福勒的回答 , 因为所有这一切都发生了。 现在就我应该做的事情来说,看起来我只需要在Google.Protobuf的nuspec文件中添加一个frameworkAssemblies元素:

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

frameworkAssembly引用然后在客户端项目的project.lock.json结束,一切都很好。

然而,根据大卫的另外一个评论(“我们将考虑修正这个问题”),我可能不需要做任何事情。

在我看来,你的问题的存在只是因为你select了Console应用程序而不是“ASP.NET Web Application”/“ASP.NET 5 Templates”/“Empty”。 我做了一个简单的testing用法Empty模板,在NuGet中添加了"Google.Protobuf": "3.0.0-alpha4" ,最后修改了Startup.cs以便使用Google.Protobuf.WellKnownTypes

  • using 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应用程序在Web浏览器中显示为100.5555s

您可以从这里下载演示项目。

更新:我用纯控制台DNX应用程序分析了这个问题,它使用了代码,可以duration.ToString()方法中find问题的原因, 该方法在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"部分中的"System.Console": "4.0.0-beta-23516" "frameworks"是必需的,因为Console命名空间(用于Console.WriteLine )存在于DNX 4.5.1 mscorlib中。 如果有人试图在公共依赖关系的层面上添加"System.Console": "4.0.0-beta-23516" ,就会得到文本开头的错误

错误CS0433“System.Console,Version = 4.0.0.0,Culture = neutral,PublicKeyToken = b03f5f7f11d50a3a”和“mscorlib,Version = 4.0.0.0,Culture = neutral,PublicKeyToken = b77a5c561934e089”ConsoleApp3.DNX中存在types“控制台” 4.5.1

更新2:可以replace线路

 Console.WriteLine("{0}.{1:D4}s", duration.Seconds, duration.Nanos); 

 Console.WriteLine((object)duration); 

使其工作。 只需使用Console.WriteLine(duration); 或者var str = duration.ToString(); 产生你所描述的错误。

更新3:我validation了该代码duration.ToString()调用使用行格式化的行 。 看起来代码duration.ToString() ((object)duration).ToString()对于WellKnownTypestypes(如Duration )确实与((object)duration).ToString()相同。

我觉得最重要的一点是重要的。 所描述的问题仅适用于dnx451(或dnx452或dnx46)。 如果有人会删除线路

 "dnx451": { }, 

project.json "frameworks"部分,程序将仅编译为DNX Core 5.0( "dnxcore50" )。 人们可以很容易地validation一个将不会有任何问题更多。

更新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的自动依赖关系parsing仍然有问题,并且无法正确parsing“Google.Protobuf”所需的一些依赖关系。

因为直接添加不需要的"Microsoft.AspNet.Hosting": "1.0.0-rc1-final"引用只能被看作是一个解决方法。 我认为在ASP.NET 5和DNX中使用依赖解决scheme仍然是越野车。 我在问题发布之前发布了一段时间, 这个问题还在开放。 这个问题提供了一个例子,当parsing直接包含的依赖关系可以提供另一个结果作为dnu restore解决的依赖关系。 这就是为什么我开始比较工作代码的依赖性的原因,我最初发布的工作代码与不工作的项目的依赖关系。 经过一些testing,我find了解决方法,并将其减less到唯一的依赖项: "Microsoft.AspNet.Hosting": "1.0.0-rc1-final"