.NET跨平臺之旅:將示例站點從 ASP.NET 5 RC1 升級至 ASP.NET Core 1.0

終於將「.NET跨平臺之旅」的示例站點 about.cnblogs.com 從 ASP.NET 5 RC1 升級至 ASP.NET Core 1.0 ,經歷了很多周折,在這篇博文中記錄一下。git

從 ASP.NET 5 到 ASP.NET Core 最大的變化,除了更名以外,就是用 dotnet cli(命令名是dotnet)取代了dnx。因此運行 ASP.NET Core 程序,首先要安裝 dotnet cli,咱們是在 Ubuntu 服務器上用 apt-get install dotnet 命令安裝的。github

運行 ASP.NET 5 程序的命令是 dnx restore + dnx web,運行 ASP.NET Core 程序的命令則變爲 dotnet restore + dotnet run。dotnet 運行 ASP.NET 程序 與 dnx 有一個很大的不一樣,除了 project.json 與 Startup.cs 職位,還須要一個 Program.cs 。web

用 dnx 運行 ASP.NET 5 程序,須要在 project.json 中配置相應的 command ,好比:json

"commands":{
    "web": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.Kestrel --server.urls http://*:8001"
}

而在 ASP.NET Core 中,再也不須要這個 command ,而是交由 Program.cs 負責,好比咱們這個示例項目中所用的 Program.cs 代碼以下:api

using System.IO;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Builder;

namespace CNBlogs.AboutUs.Web
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var host = new WebHostBuilder()
                        .UseServer("Microsoft.AspNetCore.Server.Kestrel")
                        .UseUrls("http://*:8001")
                        .UseApplicationBasePath(Directory.GetCurrentDirectory())
                        .UseDefaultConfiguration(args)
                        .UseIISPlatformHandlerUrl()
                        .UseStartup<Startup>()
                        .Build();
            host.Run();
        }
    }
}

從上面的代碼能夠看出,ASP.NET Core 應用的啓動工做是由 WebHostBuilder(源碼)起頭的,但它不是主角,只是助手,準備一些啓動參數,最終把啓動工做交給了真正的主角 —— WebHost,若是你對 WebHost 怎麼幹活的感興趣,能夠看它的 源碼服務器

弄好 Program.cs 以後,接下來就是體力活 —— 更名。app

  • EntityFrameworkCore.MicrosoftSqlServer 改成 Microsoft.EntityFrameworkCore.SqlServer
  • Microsoft.AspNet.Builder 改成 Microsoft.AspNetCore.Builder
  • Microsoft.Data.Entity 改成 Microsoft.EntityFrameworkCore
  • Microsoft.AspNet.Mvc 改成 Microsoft.AspNetCore.Mvc
  • Microsoft.AspNet.Html.Abstractions 改成 Microsoft.AspNetCore.Html
  • 移除 Microsoft.Dnx.Runtime 命名空間
  • 等等

完成「更名」體力活以後,接下來的工做最費周折最累人 —— 配置 project.json , 並且如今的 project.json 不支持註釋,調測配置變得更麻煩。ide

首先要在 project.json 中添加以下 emitEntryPoint 的配置,dnx 時期不加是能夠的,如今可不行。ui

"compilationOptions": {
        "emitEntryPoint": true
}

遇到的第一問題是 dotnet restore 時出現 not compatible with DNXCore,Version=v5.0 錯誤。。。後來經過在 project.json 中添加以下的配置解決了,但至今未能弄明白爲何加上看似這個不相關的配置能解決問題(或者只是表面地解決)。url

"tools": {
      "dotnet-publish-iis": "1.0.0-*"
}

遇到的第二個問題是 The dependency Ix-Async 1.2.5 does not support framework DNXCore,Version=v5.0 。這個問題與 Entity Framework 有關,只要在 project.json 的 dependencies 中去掉 "Microsoft.EntityFrameworkCore.SqlServer",問題就消失。後來參考 Entity Framework 的源代碼,在 project.json 中添加以下的配置才解決問題:

"netstandard1.3": {
      "imports": [
        "dotnet5.4",
        "portable-net452+win81"
      ]
}

接下來遇到的問題是 ASP.NET Core MVC 路由匹配問題 ,用 dotnet run 將站點運行起來後,訪問任何URL都出現404錯誤。這是一個讓人無從下手的問題,由於從 Startup.cs 中的代碼看,MVC的配置無任何問題。後來仍是懷疑到多是 project.json 的問題,因而與 dotnet-cli 的示例項目 cli-samples 中的 project.json 進行對比,試了試添加以下的配置,問題居然奇蹟般地解決了(這個配置當時沒有去進一步研究)。

{
    "compilationOptions": {
        "preserveCompilationContext": true
    }
}

最後一個問題最讓人無語,問題是 訪問ASP.NET Core MVC站點出錯:Could not load file or assembly 'Microsoft.Win32.Registry' 。不只咱們的項目有這個問題,並且 cli-samples 中的 HelloMvc 項目也有這個問題。問題發生在 Microsoft.AspNetCore.DataProtection 中,並且 DataProtectionServices.cs 中的確引用了 Microsoft.Win32.Registry,可是咱們是在 Linux 上運行的,難道 Microsoft.AspNetCore.DataProtection 目前還不支持跨平臺?

整個升級進程就在這裏卡住了,當咱們正準備暫時放棄升級至 ASP.NET Core 1.0 的時候,昨天發現 cli-samples 中的 prject.json 更新了,而後試着運行了一下 HelloMvc 項目,問題居然神奇地解決了。立馬看一下對應的 git commit

原來在 dependecies 中刪除了 NETStandard.Library ,在 frameworks 中添加了 netstandardapp1.3 的配置。因而,照着這個修改了咱們項目中的 project.json ,問題立馬解決,咱們的.NET跨平臺之旅的示例站點 about.cnblogs.com 也就成功運行了起來,升級總算成功完成了。

分享一下這個示例項目中的三個文件:

project.json:

{
    "compilationOptions": {
        "preserveCompilationContext": true,
        "emitEntryPoint": true
    },
    "dependencies" : {
        "Microsoft.Extensions.Logging.Console": "1.0.0-*",
        "Microsoft.AspNetCore.IISPlatformHandler": "1.0.0-*",
        "Microsoft.AspNetCore.HttpOverrides": "1.0.0-*",
        "Microsoft.AspNetCore.Mvc": "1.0.0-*",
        "Microsoft.AspNetCore.StaticFiles": "1.0.0-*",
        "Microsoft.AspNetCore.Diagnostics": "1.0.0-*",
        "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-*",
        "System.Runtime.Serialization.Primitives": "4.1.0-*",
        "Microsoft.EntityFrameworkCore.SqlServer": "1.0.0-*"
    },
    "frameworks": {
      "netstandardapp1.3": {
        "dependencies": {
          "NETStandard.Library": "1.0.0-*"
        },
        "imports": [
          "dnxcore50",
          "portable-net45+win8"
        ]
      }
    },
    "tools": {
      "dotnet-publish-iis": "1.0.0-*"
    }
}

Startup.cs:

namespace CNBlogs.AboutUs.Web
{
    public class Startup
    {
        public Startup(IApplicationEnvironment appEnv)
        {
            IConfigurationBuilder builder = new ConfigurationBuilder()
                .SetBasePath(appEnv.ApplicationBasePath)
                .AddJsonFile("config.json", false);
            Configuration = builder.Build();
        }

        public IConfiguration Configuration { get; set; }

        public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
        {
            loggerFactory.AddConsole(LogLevel.Debug);
            app.UseDeveloperExceptionPage();
            app.UseMvcWithDefaultRoute();
            app.UseStaticFiles();
            app.UseRuntimeInfoPage();
        }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();

            services.AddEntityFramework()
                .AddSqlServer()
                .AddDbContext<EfDbContext>(options =>
                {
                    options.UseSqlServer(Configuration["data:ConnectionString"]);
                });

            services.AddTransient<ITabNavRepository, TabNavRepository>();
            services.AddTransient<ITabNavService, TabNavService>();
        }
    }
}

NuGet.Config:

<configuration>
  <packageSources>
    <clear />
    <add key="AspNetCI" value="https://www.myget.org/F/aspnetcidev/api/v3/index.json" />
    <add key="NuGet.org" value="https://api.nuget.org/v3/index.json" />
  </packageSources>
</configuration>
相關文章
相關標籤/搜索