没有frameworkAssemblies,无法解决程序集引用问题

时间:2015-12-07 14:42:44

标签: .net nuget dnx nuspec

我试图验证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失败了:

  

错误:c:\ Users \ Jon \ Test \ Projects \ protobuf-coreclr \ src \ ProtobufTest \ Program.cs(9,9):DNX,Version = v4.5.1 error CS0012:Type' Object& #39;在未引用的程序集中定义。您必须添加对程序集的引用,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*添加依赖关系。
  • 在NuGet包中向System.Runtime添加依赖项(本地)并重新构建 - 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条目工作的方法,那么我可以将该依赖项添加到Protocol Buffers本身,这很好 - 但是因为它依赖于System.Runtime v4 project.lock文件中的.0.0似乎没有帮助,我必须遗漏一些东西:(

3 个答案:

答案 0 :(得分:21)

因此,如果你眯着眼睛看看project.json,它基本上是一个带有一点goop的nuspec来描述构建项目所需的编译选项和源代码。 Nuspecs今天有2个部分,frameworkAssemblies表示“内置”内容,dependencies代表其他nuget依赖项。它具有相同的含义。当您使用“框架”中的内容时,需要在frameworkAssemblies中指定vs作为nuget包依赖项。

现在详细说明:

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

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

这可能会让事情更加模糊......

答案 1 :(得分: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中,一切都很顺利。

然而,根据大卫的其他评论判断(&#34;我们将考虑修复此问题&#34;)我可能不需要做任何事情......

答案 2 :(得分:5)

在我看来,您的问题的存在只是因为您选择了控制台应用程序而不是&#34; ASP.NET Web应用程序&#34; /&#34; ASP.NET 5模板&#34; /&#34;空&#34;。我制作了简单的测试用法空模板,从NuGet添加了"Google.Protobuf": "3.0.0-alpha4",最后修改了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应用程序在Web浏览器中成功显示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的{​​{1}}中DNX 4.5.1。如果有人试图在常见依赖关系的级别上添加"System.Console": "4.0.0-beta-23516",则会在文本开头时出现错误

  

错误CS0433类型&#39;控制台&#39;存在于&#39; System.Console中,   Version = 4.0.0.0,Culture = neutral,PublicKeyToken = b03f5f7f11d50a3a&#39;和   &#39; mscorlib,版本= 4.0.0.0,文化=中立,   公钥= b77a5c561934e089&#39; 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"的{​​{1}}部分,然后该程序将仅针对DNX Core 5.0进行编译(project.json)。人们可以很容易地确认一个人不会有任何问题。

更新4:最后,我发现了一个非常简单的问题解决方法:只需要为项目添加"dnxcore50"依赖项:

"Microsoft.AspNet.Hosting": "1.0.0-rc1-final"

接下来加载许多不需要的dll,但现在依赖关系将被正确解析。

对于dnx451和dnxcore50,可以编译

The final project而不会出现任何问题。我将结果解释如下:&#34; Google.Protobuf&#34;同时使用dnx451和dnxcore50,但是RC1的自动依赖性解析仍然存在问题,并且它无法正确解析某些必需的依赖关系&#34; Google.Protobuf&#34;。

原因是直接添加不需要的{ "dependencies": { "Google.Protobuf": "3.0.0-alpha4", "Microsoft.AspNet.Hosting": "1.0.0-rc1-final" } } 引用只能被视为一种解决方法。我认为ASP.NET 5和DNX中使用的依赖项解析仍然存在问题。我在the issue之前发布了一段时间,但仍然打开了。当直接包含依赖的解析可以提供另一个结果作为"Microsoft.AspNet.Hosting": "1.0.0-rc1-final"解析的依赖关系时,该问题提供了一个示例。这就是为什么我开始比较工作代码的依赖性,我最初发布的是与非工作项目的依赖关系。经过一些测试后,我找到了解决方法,并将其减少为唯一的依赖项:dnu restore