如果没有框架组件,无法解决程序集引用问题
我试图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")
(但没有其他更改) - 将
duration
variables的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.Runtime
, System.Threading
等东西。当使用基于MSBUILD的项目,有一个任务运行,基本上自动添加到C#编译器的所有的System.*
引用,以避免这个混乱。 这些程序集在.NET Framework上称为Facade。 不幸的是,即使没有使用它们,也会增加它们。 对System.Runtime
的依赖性是此行为的触发器(在基于.NET Framework的csproj文件上运行时)。
添加对同一个包的引用不起作用的原因是因为这些合约程序集(如System.Runtime)的.NET Framework文件夹(net4 *)没有任何dll。 如果你看这些文件夹,你会看到一个空的_._
文件。 原因是因为当你声明一个带有对System.Runtime
的frameworkAssembly
引用的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()
对于WellKnownTypes
types(如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"
。