文章背景:對於.NET Core大家應該並不陌生, 從它被 宣布 到現在已經有1-2年的時間了,其比較重要的一個版本1.0 RC2 也即將發布。.Net Core從一個一個的測試版到現在的RC2,經歷了很多個大大小小的變化。特別是在RC1到RC2的更新之中,.NET Core命令行工具(dotnet cli)從 dnx 變為 dotnet,並且廢除了 DNVM 和 DNU,使得 .NET Core 的開發變得更為簡單,其相關工具鏈也基本成型。雖然網上關於.NET Core的示例項目不在少數,而且微軟官方也提供了不少示例項目,但大多針對的是.NET Core的不同版本,因此很多示例項目並不是能很容易的運行起來。所以我決定寫一篇針對RC2這個版本的.NET Core入門文章並提供一些能直接運行的示例項目。
下載安裝 .NET Core SDK
從 dotnet cli github項目主頁找到最新版的.Net Core SDK下載:
例如 Mac OS X的最新版的.NET Core SDK的下載地址為:
https://dotnetcli.blob.core.windows.net/dotnet/beta/Installers/Latest/dotnet-dev-osx-x64.latest.pkg
安裝前請確認當前系統是否已經安裝了老版本的.NET Core, 如果已經安裝,請先卸載。
如在Mac OS X上已安裝的話,請運行如下命令刪除:
sudo rm -rf /usr/local/share/dotnet
在Mac OS X上安裝之前請先確保 openssl 已經被安裝了:
brew install openssl
開發工具 Visual Studio Code 及其 C# 插件安裝
如不准備使用VSCode進行開發的話,請忽略此部分。我不確定最新版本的 Visual Studio 2015 Update 2 是否對.NET Core 1.0 RC2有很好的支持。
-
從官方網站下載安裝 VSCode
-
安裝VSCode C#插件
由於支持 RC2 的 C# 插件 v1.0 還未正式發布到 VS Code extension 倉庫里, 因此你只能手動從github下載並安裝:
https://github.com/OmniSharp/omnisharp-vscode/releases
Mac OS X 下通過 VSCode 打開下載下來的文件即可。
等到 VS Code C# 插件 v1.0 版本正式發布了,你就可以通過VSCode的命令窗口來安裝 C# 支持了。詳細操作如下:
運行VSCode, 然后使用快捷鍵 ⌘ + P 啟動快速打開命令窗口,然后輸入如下命令安裝C#擴展。最新版的csharp擴展已支持 RC2 的.NET程序的調試。
ext install csharp
使用.NET CLI (dotnet) 創建,編譯和運行項目
-
創建項目
首先在控制台/Terminal下進入你要創建項目的目錄,然后運行如下命令:
dotnet new
dotnet cli 創建新項目的時候支持項目類型參數-t,但當前只支持Console參數。😦
運行之后會生成兩個文件
project.json - 類似於.NET Framework里的項目文件 Program.cs - 程序啟動入口
使用restore命令下載依賴
dotnet restore
如出現網絡錯誤導致restore失敗的情況請重試幾次,貌似這種情況比較少。
如發現類似下面的Warning也請不要驚慌,這是由於CLI的版本號與下載下來的.NET Core類庫的版本號不一致導致的,這種情況不會影響編譯和運行。
warn : Dependency specified was Microsoft.NETCore.App (>= 1.0.0-rc2-3002464) but ended up with Microsoft.NETCore.App 1.0.0-rc2-3002468.
-
編譯項目
在控制台或Terminal打開項目所在目錄,運行如下命令編譯:
dotnet build
如出現如下類似編譯錯誤:
error NU1002: The dependency Microsoft.CodeAnalysis.Common 1.2.0-beta1-20160202-02 does not support framework .NETCoreApp,Version=v1.0
error NU1002: The dependency Microsoft.CodeAnalysis.CSharp 1.2.0-beta1-20160202-02 does not support framework .NETCoreApp,Version=v1.0
出現這個問題的可能原因是NuGet上通過版本號匹配到的依賴包並不能使用,你需要做如下操作之后再重新restore一下。
a. 在項目根目錄新增文件 NuGet.config, 並寫入以下內容:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<!--To inherit the global NuGet package sources remove the <clear/>line below -->
<clear/>
<add key="dotnet-core" value="https://dotnet.myget.org/F/dotnet-core/api/v3/index.json"/>
<add key="api.nuget.org" value="https://api.nuget.org/v3/index.json"/>
</packageSources>
</configuration>
b. 打開 project.json 文件將 dependencies 節點中的 Microsoft.NETCore.App 的版本好更改為 1.0.0-rc2-*:
"dependencies": {
"Microsoft.NETCore.App": {
"type": "platform",
"version": "1.0.0-rc2-*"
}
}
c. 然后再重新運行 dotnet restore 之后編譯
-
運行項目
在控制台或Terminal打開項目所在目錄,運行如下命令運行:
dotnet run
如遇如下錯誤,
Expected to load libhostpolicy.dylib from [/usr/local/share/dotnet/shared/Microsoft.NETCore.App/1.0.0-rc2-3002468] This may be because the targeted framework ["Microsoft.NETCore.App": "1.0.0-rc2-3002468"] was not found.
也不要慌張,到目錄 bin/Debug/netcoreapp1.0中 找到文件 *.runtimeconfig.json, 將其中 runtime 版本號修改為與本機 CLI 版本號一致即可。
{ "runtimeOptions": { "framework": { "name": "Microsoft.NETCore.App", "version": "1.0.0-rc2-3002485" } } }
如本機 dotnet --version 命令返回值為 “1.0.0-rc2-002485”,則應runtime config中的版本號應替換為“1.0.0-rc2-3002485”。
然后再嘗試運行 dotnet run
-
調試項目 (Visual Studio Code)
使用 VSCode 打開項目所在文件夾之后,VSCode 會問你是否添加啟用項目調試相關的文件,你選OK之后目錄下會新增文件夾“.vscode”,其中會包含兩個文件:
launch.json tasks.json
當你發現無法調試失敗的時候,你可以到 launch.json 文件,檢查啟動所指向的文件是否正確:
{ "name": ".NET Core Launch (console)", ... "program": "${workspaceRoot}/bin/Debug/netcoreapp1.0/netcore.dll", ... }
使用 .NET Core 進行 ASP.NET MVC 開發
雖然 dotnet cli 並沒有提供直接創建 web/mvc項目的選項,但是我們還是可以手動來創建 mvc 項目的。
-
首先是更新 project.json 來支持 mvc:
{ "version": "1.0.0-*", "content": [ "wwwroot", "Views" ], "compilationOptions": { "preserveCompilationContext": true, "emitEntryPoint": true, "debugType": "portable" }, "dependencies": { "Microsoft.AspNetCore.Diagnostics": "1.0.0-*", "Microsoft.AspNetCore.Mvc": "1.0.0-*", "Microsoft.AspNetCore.Mvc.TagHelpers": "1.0.0-*", "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0-*", "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-*", "Microsoft.AspNetCore.StaticFiles": "1.0.0-*", "Microsoft.Extensions.Logging.Console": "1.0.0-*", "Microsoft.NETCore.App": { "type": "platform", "version": "1.0.0-rc2-*" } }, "frameworks": { "netcoreapp1.0": { "imports": [ "portable-net45+wp80+win8+wpa81+dnxcore50" ] } }, "tools": { "Microsoft.AspNetCore.Server.IISIntegration.Tools": { "version": "1.0.0-*", "imports": "portable-net45+wp80+win8+wpa81+dnxcore50" } }, "scripts": { "postpublish": "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" } }
-
在NuGet.config 文件中增加 ASP.NET 的包的下載地址,如此文件不存在請先添加:
<?xml version="1.0" encoding="utf-8"?> <configuration> <packageSources> <!--To inherit the global NuGet package sources remove the <clear/> line below --> <clear /> <add key="dotnet-core" value="https://dotnet.myget.org/F/dotnet-core/api/v3/index.json" /> <add key="api.nuget.org" value="https://api.nuget.org/v3/index.json" /> <add key="AspNetCI" value="https://www.myget.org/F/aspnetcirelease/api/v3/index.json" /> </packageSources> </configuration>
-
增加 Startup.cs 文件 然后在 Program.cs 增加啟動代碼:
Startup.cs
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; namespace HelloMvc { public class Startup { public void ConfigureServices(IServiceCollection services) { // 注冊MVC相關服務到ASP.NET Core的反轉控制器 services.AddMvc(); } public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(LogLevel.Debug); //啟用靜態文件支持 app.UseStaticFiles(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } // 啟用 Mvc 並定義默認的路由 app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); } } }
Program.cs
using System; using System.IO; using Microsoft.AspNetCore.Hosting; namespace HelloMvc { public class Program { public static void Main(string[] args) { var host = new WebHostBuilder() .UseKestrel() .UseContentRoot(Directory.GetCurrentDirectory()) .UseDefaultHostingConfiguration(args) .UseIISIntegration() .UseStartup<Startup>() .Build(); host.Run(); } } }
-
MVC 其它
ASP.NET Core中 MVC 具體的開發方法,請參考官方文檔 https://docs.asp.net/en/latest/mvc/index.html 來學習使用,我在這里就不再累述了。
完整示例可參考我在github上的示例項目:https://github.com/kerryjiang/dotnetcore-samples/tree/master/mvcMVC項目也可通過 dotnet run 命令運行,還可以使用VSCode進行調試。
在 .NET Core 中使用 EntityFramework + Sqlite
.NET Core 中的 EntityFramework 也在 RC2 也有較大的變化。包的名字從 "EntityFramework." 變化為 "Microsoft.EntityFrameworkCore."。
如需使用Sqlite的話,project.json的包依賴應該為:
"dependencies": {
...
...
"Microsoft.EntityFrameworkCore": "1.0.0-*",
"Microsoft.EntityFrameworkCore.Sqlite": "1.0.0-*",
"Microsoft.NETCore.App": {
"type": "platform",
"version": "1.0.0-rc2-*"
}
}
另外,frameworks 節點對 netcoreapp1.0 也需增加新的imports (portable-net45+win8+wp8+wpa81 和 portable-net45+win8+wp8):
"frameworks": {
"netcoreapp1.0": {
"imports": [
"portable-net45+wp80+win8+wpa81+dnxcore50",
"portable-net45+win8+wp8+wpa81",
"portable-net45+win8+wp8"
]
}
}
然后在Startup.cs中注冊EF相關的服務和DbContext:
public void ConfigureServices(IServiceCollection services)
{
services.AddEntityFramework()
.AddEntityFrameworkSqlite()
.AddDbContext<WebsiteDbContext>(
options => options.UseSqlite("Data Source=./mvcefsample.sqlite")); //設置鏈接字符串
services.AddMvc();
}
再到Configure里面初始化數據庫或者啟用DbMigration:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
...
using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
var db = serviceScope.ServiceProvider.GetService<WebsiteDbContext>();
// do db migrate automatically
// db.Database.Migrate();
if (db.Database.EnsureCreated())
{
for (int i = 0; i < 10; i++)
{
var article = new Article {
Title = string.Format("Article {0}", i + 1),
Content = string.Format("Article {0} content blabla blabla", i + 1),
CreatedTime = DateTime.Now,
UpdatedTime = DateTime.Now
};
db.Articles.Add(article);
}
db.SaveChanges();
}
}
}
完整示例可參考我在github上的示例項目:https://github.com/kerryjiang/dotnetcore-samples/tree/master/mvc-ef
在 ASP.NET MVC Core 中使用 ASP.NET Identity
-
ASP.NET 中身份驗證是免不了的事情,首先第一步在 project.json 中添加包依賴:
"dependencies": { ... ... "Microsoft.AspNetCore.Identity.EntityFrameworkCore": "1.0.0-*", ... "Microsoft.EntityFrameworkCore": "1.0.0-*", "Microsoft.EntityFrameworkCore.Sqlite": "1.0.0-*", "Microsoft.NETCore.App": { "type": "platform", "version": "1.0.0-rc2-*" } }
-
實現帶有 Identity 支持的 DbContext:
using Microsoft.EntityFrameworkCore; using Microsoft.AspNetCore.Identity.EntityFrameworkCore; namespace MvcIdentitySample { public class ApplicationUser : IdentityUser { } public class WebsiteDbContext : IdentityDbContext<ApplicationUser> { public WebsiteDbContext(DbContextOptions<WebsiteDbContext> options) : base(options) { } //public DbSet<Article> Articles { get; set; } } }
-
然后在 Startup 中的 ConfigureSerivces 方法中注冊服務:
public void ConfigureServices(IServiceCollection services) { // register services about EF services.AddEntityFramework() .AddEntityFrameworkSqlite() .AddDbContext<WebsiteDbContext>( options => options.UseSqlite("Data Source=./mvcidentitysample.sqlite")); // register services about ASP.NET Identity services.AddIdentity<ApplicationUser, IdentityRole>() .AddEntityFrameworkStores<WebsiteDbContext>() .AddDefaultTokenProviders(); services.AddMvc(); }
-
再到 Startup 中的 Configure 方法中啟用 Identity:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { ... // the authentication must be configured before mvc app.UseIdentity(); // To configure external authentication please see http://go.microsoft.com/fwlink/?LinkID=532715 /* app.UseFacebookAuthentication(new FacebookOptions { AppId = "901611409868059", AppSecret = "4aa3c530297b1dcebc8860334b39668b" }); */ app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); }
注意 app.UseIdentity() 這句必須放到啟用 MVC 之前,否則 Identity 無法生效,這個問題折騰了我幾個小時。😦
-
由於 ASP.NET MVC 6 和 最新的 ASP.NET Identity 的變化,其使用方法與老版本的模版代碼略有不同。
a. 頁面頭部登陸狀態部分頁面(/Views/Shared/_LoginPartial.cshtml),由於 taghelper 的引入和 模版引擎的變化,這個頁面的代碼看起來會和以前有明顯的不同:
@using Microsoft.AspNetCore.Identity @using MvcIdentitySample @using MvcIdentitySample.Models @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers @inject SignInManager<ApplicationUser> SignInManager @inject UserManager<ApplicationUser> UserManager @if (SignInManager.IsSignedIn(User)) { <form asp-controller="Account" asp-action="LogOff" method="post" id="logoutForm" class="navbar-right"> <ul class="nav navbar-nav navbar-right"> <li> <a asp-controller="Manage" asp-action="Index" title="Manage">Hello @UserManager.GetUserName(User)!</a> </li> <li> <button type="submit" class="btn btn-link navbar-btn navbar-link">Log off</button> </li> </ul> </form> } else { <ul class="nav navbar-nav navbar-right"> <li><a asp-controller="Account" asp-action="Register">Register</a></li> <li><a asp-controller="Account" asp-action="Login">Log in</a></li> </ul> }
b. 新增 _ViewImports.cshtml (/Views/_ViewImports.cshtml) 的使用避免了重復在多個view里面增加相同的using和其它定義:
@using Microsoft.AspNetCore.Identity @using MvcIdentitySample @using MvcIdentitySample.Models @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
這樣就不用在剛才的_LoginPartial.cshtml頁面里增加同樣的代碼了。
總結
大家通過以上介紹和示例應該可以了解到,當前使用.NET Core 來進行簡單的應用開發是可行的,dot cli(dotnet) 這個工具已經比上個版本(RC1)的工具簡單方便了很多,而且統一的Web開發和Console開發,CLI工具本身以后應該不會有太大的變化。因為.NET Core 1.0 RC2還在開發測試階段,有的包可能還沒有發布到NuGet上,因此而造成的找不到合適包的情況屬於常見問題之一,不過只要在NuGet.config中增加了合適的Package Source,這個問題就很好解決了。所以大家如果想要把自己的項目,公司的項目遷移到.NET Core, 現在就可以開始動手了,不用再等到時間不確定的 1.0 release。
另外,本文所展示的示例代碼限於篇幅與排版,無法做到十分詳細,例如代碼中所需要的using並未提及,還需要讀者來自行添加(VS里ALT+SHIFT+F10, VSC里面好像只能手動點感嘆號?)。
而且此文旨在嘗試.NET Core的可用性,因此並未對如ASP.NET MVC 6和 EF7相關技術做深入探討,如需了解請查看相關技術文檔:
最后再提醒大家一次,本文中所涉及的代碼的完整示例項目已放到 github 上,歡迎大家fork/star/send pr: