55

我正在尝试验证Protocol Buffers是否可以与 ASP.NET 团队的新可移植运行时以及理想情况下的大多数其他现代环境一起使用。3.0.0-alpha4 版本是不久前使用 profile259 创建的,所以我预计在某些情况下需要进行一些更改,但我想我会试一试。我知道Oren Novotny 关于定位 .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,Version=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.RuntimeNuGet 包(本地)并对其进行重建 -project.lock.json已更新为包括 System.Runtime v4.0.0,但发生了相同的错误
  • 同上包括lib\dotnet包中的目录以及依赖项

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

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

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

最终,我不希望用户必须这样做——至少,不是为了协议缓冲区。我假设这与我们如何构建协议缓冲区有关,但由于我不正确理解原因,因此很难修复。

我希望如果我能找到一种使dependencies条目工作的方法,然后我可以将该依赖项添加到协议缓冲区本身中,这很好 - 但在 project.lock 文件中依赖于 System.Runtime v4.0.0似乎没有帮助,我一定错过了一些东西:(

4

3 回答 3

22

因此,如果你眯着眼睛看 project.json,它基本上是一个带有一点点 goop 的 nuspec,用于描述构建项目所需的编译选项和源代码。今天的 Nuspecs 有 2 个部分,frameworkAssemblies用于“内置”内容和dependencies其他 nuget 依赖项。这里的意思是一样的。当您使用“框架”中的某些内容时,需要在frameworkAssembliesvs 中将其指定为 nuget 包依赖项。

现在进入细节:

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

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

这可能让事情变得更加模糊......

于 2015-12-07T17:26:04.293 回答
9

我已经接受大卫福勒的回答作为所有这一切发生的原因。现在就我应该做什么而言,看起来我只需要frameworkAssemblies在 nuspec 文件中添加一个元素Google.Protobuf

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

然后该frameworkAssembly引用最终出现在project.lock.json客户端项目中,一切都很好。

但是,从大卫的其他评论(“我们将考虑解决这个问题”)来看,我可能不需要做任何事情......

于 2015-12-09T10:21:40.087 回答
5

在我看来,您的问题存在只是因为您选择了控制台应用程序而不是“ASP.NET Web 应用程序”/“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在 Web 浏览器中。

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

更新:我分析了纯控制台 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命名空间(for Console.WriteLine)存在于mscorlibof 中DNX 4.5.1。如果尝试添加常见"System.Console": "4.0.0-beta-23516"依赖项的级别,则会收到以文本开头的错误

错误 CS0433 类型“Console”存在于“System.Console,Version=4.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a”和“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()调用使用这些行进行格式化的行。似乎代码duration.ToString()确实与类型(如)相同((object)duration).ToString()WellKnownTypesDuration

我认为重要的最新评论。所描述的问题仅存在于 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".

于 2015-12-07T15:24:07.360 回答