終於將「.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
完成「更名」體力活以後,接下來的工做最費周折最累人 —— 配置 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>