为 ASP.NET 4 和 ASP.NET Core 1.0 创建一个 Nuget 包

Create one Nuget Package for both ASP.NET 4 & ASP.NET Core 1.0

我们有一个在 ASP.NET 4 中工作并使用 HttpContext.Current 的库。我们知道我们 但应该使用 IHttpContextAccessor

我们如何更改此库,以便我们 支持 ASP.NET 4(通过使用 HttpContext.Current)和 ASP.NET 核心(IHttpContextAccessor) 并打包为 one NuGet package?

一种可能:

创建三个库。

  1. 使用 HttpContext
  2. 使用 IHttpContextAccessor
  3. 从这些库之一加载的工厂。

1 和 2 具有相同的程序集名称,Factory 仅引用两者之一。

文件夹中一次只有两个程序集作为参考。参考文献中的工厂和其他两个中的一个。

创建包含所有三个程序集的 nuget 包。 1 和 2 放在不同的文件夹中,我们称它为 aspnet4 和 aspnet5。

包还包含 aspnet 项目使用的目标文件。目标文件根据 aspnet 项目中存在的 属性 将工厂和其中一个库复制到引用文件夹中。这个 属性 可能类似于 aspnet=aspnet5.

这可能太大了,可能存在更简单的解决方案。我会想一个更简单的解决方案。

示例代码

//4. AspNetUsageBaseClass Assembly
namespace AspNetUsage
{
    //rest of code

    public abstract AspNetUsageBaseClass
    {
        //rest of code
        public abstract void HttpContextIHttpContextAccessor();
    }
}

//1. AspNetUsage Assembly, Reference AspNetUsageBaseClass Assembly
using AspNetUsage;
public class AspNetUsage:AspNetUsageBaseClass
{
    public override void HttpContextIHttpContextAccessor()
    {
        //HttpContext based code
    }
}

//2. AspNetUsage Assembly, Reference AspNetUsageBaseClass Assembly
using AspNetUsage;
public class AspNetUsage:AspNetUsageBaseClass
{
    public override void HttpContextIHttpContextAccessor()
    {
        //IHttpContextAccessor based code
    }
}

现在共有3个程序集。一个底座 class 组件。另外两个实现特定功能。 内部 nuget 包结构应该是:

AspNetUsageBaseClass.dll - 基础 class 程序集

AspNet4\AspNetUsage.dll - HttpContext 程序集

AspNet5OrCore\AspNetUsage.dll - IHttpContextAccessor 程序集

AspNet.target - 这将导入到 asp 网络项目中,并根据 属性 的值提取两个 dll 之一。

在 AspNet 项目中,您将拥有:

AspNetUsageBaseClass context = new AspNetUsage();
context.HttpContextIHttpContextAccessor();

这不是基于 Factory 模式,但可以通过一些修改扩展到基于 Factory 模式。

我在没有VS的情况下用记事本打的逻辑可能会有些错误

如果您在 project.json 中定义了两个目标框架(如 aspnetcorenet451),那么将创建两个单独的 dll 并放入 lib/aspnetcorelib/net451 在 nuget 包里面。 Nuget 将根据使用包的项目的目标框架知道使用哪一个。

现在,您可以在库中使用 #ifdef 语句来区分代码的哪些部分应该只针对特定平台进行编译。

一个简单的例子:

using System;

namespace MyLib
{
#if NETFX
    using HttpContext = System.Web.HttpContext;
#elif NETCORE
    using HttpContext = Microsoft.AspNetCore.Http.HttpContext;
#endif
    public class MyClass
    {
        public string GetUserAgent(HttpContext ctx)
        {
            return ctx.Request.Headers["User-Agent"];
        }
        public void WriteToResponse(HttpContext ctx, string text)
        {
#if NETFX
            ctx.Response.Output.Write(text);
#elif NETCORE
            var bytes = System.Text.Encoding.UTF8.GetBytes(text);
            ctx.Response.Body.Write(bytes, 0, bytes.Length);
#endif
        }
    }
}

要使这些开关起作用,您必须在 project.json:

中定义特定于框架的常量
  "frameworks": {
    "netcoreapp1.0": {
      "buildOptions": {
        "define": [
          "NETCORE"
        ]
      },
      "dependencies": {
        "Microsoft.NETCore.App": {
          "type": "platform",
          "version": "1.0.0"
        },
        "Microsoft.AspNetCore.Http": "1.0.0"
      }
    },
    "net451": {
      "buildOptions": {
        "define": [
          "NETFX"
        ]
      },
      "dependencies": {
        "Microsoft.AspNet.WebApi": "5.2.3"
      },
      "frameworkAssemblies": {
        "System.Web": "4.0.0.0"
      }
    }
  },

请注意,这两个框架具有不同的依赖集。 HttpContext 为 netcoreapp 和 net451 编译时,这里将是不同的类型。幸运的是,这些类型具有非常相似的方法,因此通常您可以以相同的方式使用它们,而无需 #ifdefs(如 GetUserAgent)。其他时候,您将无法避免它(例如 WriteToResponse)。

现在,在 AspNet Core 项目中,您可以像这样使用这个库:

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.Use(async (ctx, next) => {
            var lib = new MyLib.MyClass();
            var msg = lib.GetUserAgent(ctx);
            lib.WriteToResponse(ctx, "user agent is: " + msg);
        });
    }

在旧的 AspNet MVC 中:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var lib = new MyLib.MyClass();
        var msg = lib.GetUserAgent(System.Web.HttpContext.Current);
        lib.WriteToResponse(System.Web.HttpContext.Current, "user agent is: " + msg);
        return new HttpStatusCodeResult(200);
    }
}

github.

上的完整源代码

答案是不可能。同样,您不能创建一个 NuGet 包来同时针对 MVC1 和 MVC2(两者都不是可用的 Nuget 包)

当然可以使用程序集绑定,但前提是没有重大更改。

Microsoft 在那里命名 ASP.NET 核心包 "AspNetCore",例如Microsoft.AspNetCore.Mvc vs Microsoft.AspNet.Mvc