本文將會示范如何在Windows系統下基於ASP.NET Core構建跨平台服務,並通過Docker容器運行發布。 首先說一下為什么選擇這一套組合: 我本人和我們Code4Thought團隊關注一切具備生產力的技術和工具,話說有所了解才有所選擇,DotNet技術發展趨勢也值得我們關注和支持。基於DotNot Core我們可以構建跨平台服務,結合Entity Framework Core(微軟強大的ORM),MYSQL(免費),Docker(方便移植),Visual Studio 2015(宇宙最強IDE)這一系列技術和工具,不管從商業成本,可移植性,還是生產效率上,都具備很強的誘惑力。
- Windows 10 Professional or Enterprise 64-bit CPU 開啟虛擬化
- Docker for Windows 安裝包。https://download.docker.com/win/stable/InstallDocker.msi
- DotNet Core 開發環境
- MySQL 數據庫
1,創建ASP.NET Core,可以通過.Net Core SDK提供的命令創建,當然在Windows環境下最佳選擇還是宇宙最強IDE:Visual Studio,本文使用2015 Update3 版本:
選擇Web 應用程序,創建成功后,VS會自動執行 dotnet restore 自動還原project.json 中的依賴項,項目結構如下:
介紹幾個變化項:
project.json:類似JAVA世界的Maven,管理了程序的依賴項,包括程序集,工具,配置等。
Program.cs:跟JAVA世界還是很像,程序會找到其中的Main方法做為啟動入口,模板代碼是通過微軟Microsoft.AspNetCore.Hosting 自托管當前Web程序。
Startup.cs:初始化應用程序服務,全局配置,服務注入等。
wwwroot:前端項目文件。
通過Nuget命令行或管理工具,獲取項目所需依賴程序集和工具:
- Microsoft.EntityFrameworkCore
- Microsoft.EntityFrameworkCore.Tools (還需要添加到tools內,后續需要使用Migrations命令)
- SapientGuardian.EntityFrameworkCore.MySql 或者 MySql.Data.EntityFrameworkCore(官方推薦的尚未發布正式版,https://docs.efproject.net/en/latest/providers/index.html)
Get成功之后,project.json如下:
下面我們使用Entity Framework Core試用Code First模式,結合領域驅動設計,快速構建領域模型,假設建模后的模型包含 “用戶“”和“物品“兩個實體,當然這種開發模式可以充分利用面向對象的設計理念,比如領域模型通過繼承獲取一些系統屬性:BaseEntity

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Threading.Tasks; 5 6 namespace WebApplication2.Domain.Model 7 { 8 public class BaseEntity 9 { 10 11 public int Id { get; set; } 12 13 public DateTime CreateTime { get; set; } 14 15 public DateTime UpdateTime { get; set; } 16 17 } 18 }

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Threading.Tasks; 5 6 namespace WebApplication2.Domain.Model 7 { 8 public class UserEntity: BaseEntity 9 { 10 11 public string Name { get; set; } 12 13 public long Age { get; set; } 14 15 //其它屬性... 16 17 public virtual ICollection<ProductEntity> Products { get; set; } 18 19 20 } 21 }

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Threading.Tasks; 5 6 namespace WebApplication2.Domain.Model 7 { 8 public class ProductEntity: BaseEntity 9 { 10 public String Name { get; set; } 11 12 public virtual UserEntity Owner { get; set; } 13 14 //其它屬性... 15 16 } 17 }
構建DbContext:

1 using System; 2 using System.Linq; 3 using Microsoft.EntityFrameworkCore; 4 using WebApplication2.Domain.Model; 5 6 namespace WebApplication2.Domain 7 { 8 public class MyDbContext: DbContext 9 { 10 11 public MyDbContext(DbContextOptions<MyDbContext> options) 12 : base(options) 13 { } 14 public DbSet<UserEntity> UserEntity { get; set; } 15 public DbSet<ProductEntity> ProductEntity { get; set; } 16 //protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 17 //{ 18 //} 19 20 /// <summary> 21 /// 配置屬性和模型關系等操作 22 /// </summary> 23 /// <param name="modelBuilder"></param> 24 protected override void OnModelCreating(ModelBuilder modelBuilder) 25 { 26 modelBuilder.Entity<UserEntity>().HasMany(a => a.Products).WithOne(a => a.Owner); 27 28 } 29 30 /// <summary> 31 /// 重寫SaveChanges 方法,添加一些自定義操作 32 /// </summary> 33 /// <returns></returns> 34 public override int SaveChanges() 35 { 36 ChangeTracker.DetectChanges(); 37 38 SetSystemProperty(); 39 40 return base.SaveChanges(); 41 } 42 43 private void SetSystemProperty() 44 { 45 //查詢模型添加和變更 46 var modifiedSourceInfo = ChangeTracker.Entries() 47 .Where(e => e.State == EntityState.Added || e.State == EntityState.Modified).ToList(); 48 49 DateTime currentTime = DateTime.Now; 50 51 //設置系統屬性 52 foreach (var entry in modifiedSourceInfo) 53 { 54 entry.Property("CreateTime").CurrentValue = currentTime; 55 entry.Property("UpdateTime").CurrentValue = currentTime; 56 } 57 58 59 } 60 61 } 62 }
通過Startup.cs 注冊MyDbContext,ASP.NET Core 默認設計了IOC容器管理服務對象
MySqlConnectionString 配置數據庫連接:
編寫業務邏輯實現(本文只是簡單示例所以直接寫到Controller),測試EF Core基本的增刪改查,基本都能用,但還有一些不完善,比如導航屬性還沒有實現。

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Threading.Tasks; 5 using Microsoft.AspNetCore.Mvc; 6 using Microsoft.EntityFrameworkCore; 7 using WebApplication2.Domain; 8 using WebApplication2.Domain.Model; 9 10 namespace WebApplication2.Controllers 11 { 12 public class HomeController : Controller 13 { 14 private MyDbContext _dbContext; 15 //注入MyDbContext 16 public HomeController(MyDbContext dbContext) 17 { 18 _dbContext = dbContext; 19 } 20 21 public IActionResult Index() 22 { 23 //查詢用戶 24 var checkUser = _dbContext.UserEntity.FirstOrDefault(a => a.Name.Equals("flynn")); 25 26 if (checkUser == null) 27 { 28 //測試創建用戶 29 _dbContext.UserEntity.Add(new UserEntity() 30 { 31 Age = 111, 32 Name = "flynn", 33 Products = new List<ProductEntity>() //用戶包含的物品 34 { 35 new ProductEntity() 36 { 37 Name = "prduct Name1", 38 }, 39 new ProductEntity() 40 { 41 Name = "prduct Name2", 42 } 43 } 44 }); 45 //持久化模型 46 _dbContext.SaveChanges(); 47 } 48 49 //再次查詢用戶,我們可以看到目前Entity Framework Core尚未支持Lazy Loading. 50 //通過提供Include 和 ThenInclude嵌套獲取導航屬性 51 var reCheckUser = _dbContext.UserEntity 52 .Include(a=>a.Products) 53 .FirstOrDefault(a => a.Name.Equals("flynn")); 54 55 56 var myProduct = reCheckUser.Products.ToList(); 57 58 return View(); 59 } 60 61 public IActionResult About() 62 { 63 ViewData["Message"] = "Your application description page."; 64 65 return View(); 66 } 67 68 public IActionResult Contact() 69 { 70 ViewData["Message"] = "Your contact page."; 71 72 73 74 return View(); 75 } 76 77 public IActionResult Error() 78 { 79 return View(); 80 } 81 } 82 }
測試跟蹤SQL語句執行過程
到此項目所有代碼已經開發完成,我相信在效率上還是有一定誘惑力,能快速構建和實現中小型項目。
微軟還給我們提供了一套數據遷移方案,打開Nuget 命令行,
執行命令 Add-Migration ,生成數據遷移代碼和歷史文件
執行命令:Update-Database ,更新和創建數據庫(如果數據庫不存在則創建,測試過程中,發現需要先創建一個空數據庫)
查看Mysql數據庫,數據表已經自動生成如下:
Docker的優勢本人不重復贅述,在Windows 下安裝Docker后,通過Windows Power Shell執行命令:
Docker --version
正常顯示如下:
在項目文件目錄,為項目創建Dockerfile,Dockerfile 內寫入Docker鏡像的創建過程和命令,注意Dockerfile不需要包含后綴名,文件內容如下:
FROM microsoft/dotnet:latest
COPY . /app
WORKDIR /app
RUN ["dotnet", "restore"]
RUN ["dotnet", "build"]
EXPOSE 5000/tcp
ENV ASPNETCORE_URLS http://*:5000
ENTRYPOINT ["dotnet", "run"]
文件邏輯: 獲取微軟提供的DotNet Core程序運行的官方鏡像,可直接運行到Linux,將當前文件夾文件拷貝並設置工作目錄到/app 文件夾,也就是會將剛才項目所有文件拷貝過去。
執行 dotnet 的restore 和 build 命令,最后執行dotnet run 命令啟動程序。
創建Docker鏡像,執行命令:
docker build -t test:codefirst .
會首先下載微軟官方鏡像,然后按Dockerfile 進行構建:
稍等下載和鏡像構建完成,通過命令運行鏡像:
docker run -d -p 8888:5000 -t test:codefirst
運行成功,可以直接訪問端口8888,訪問Docker運行的服務了。
本文簡單介紹和嘗試了微軟一系列技術的可行性和真實開發效率,試用過程中,能明顯感受到微軟前所未有的開放度,希望大家多多指導,共同分享,共同改變。
作者:Code4Thought 成員 Flynn Shu