Windows下構建ASP.NET Core+Code First+Docker


背景介紹

本文將會示范如何在Windows系統下基於ASP.NET Core構建跨平台服務,並通過Docker容器運行發布。 首先說一下為什么選擇這一套組合: 我本人和我們Code4Thought團隊關注一切具備生產力的技術和工具,話說有所了解才有所選擇,DotNet技術發展趨勢也值得我們關注和支持。基於DotNot Core我們可以構建跨平台服務,結合Entity Framework Core(微軟強大的ORM),MYSQL(免費),Docker(方便移植),Visual Studio 2015(宇宙最強IDE)這一系列技術和工具,不管從商業成本,可移植性,還是生產效率上,都具備很強的誘惑力。

開發環境
創建項目

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獲取依賴項

通過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如下:

 

Code First嘗試

下面我們使用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 }
View Code
 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 }
View Code
 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 }
View Code

 

構建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 }
View Code

 

通過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 }
View Code

測試跟蹤SQL語句執行過程

到此項目所有代碼已經開發完成,我相信在效率上還是有一定誘惑力,能快速構建和實現中小型項目。

數據遷移

微軟還給我們提供了一套數據遷移方案,打開Nuget 命令行,

執行命令 Add-Migration ,生成數據遷移代碼和歷史文件

執行命令:Update-Database ,更新和創建數據庫(如果數據庫不存在則創建,測試過程中,發現需要先創建一個空數據庫)

查看Mysql數據庫,數據表已經自動生成如下:

 

通過Docker部署

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM