幾乎學習所有Web開發程式語言後的第一個綜合練習課題就是如何建立一個 Blog ,這也是因為 Blog 的功能剛好滿足了使用程式語言與資料庫連接的基本操作,而在 Asp.Net 5 之後,由於跨平台支援的特性,也代表著我們不需要開 Windows 就可以撰寫 Asp.Net 的應用程式,但離開 Windows 之後,也意味著沒有了 Visual Studio 來幫助我們進行建立專案和開發,所有的開發方法和步驟都是新的嘗試,所以再度拿出這個練習題來熟悉一下再好不過了,以下範例的進行主要是以在 Mac 上使用 Visual Studio Code 和 Console,搭配 Asp.Net 5 和 Entity Framework 7 的 RC1 版來進行操作,練習如何從無到有撰寫一個 Blog 的網站。
Asp.Net 版本確認
在開始進行開發之前,必須要先確認 Asp.Net 5 的版本是否已確實安裝至 Coreclr 的 RC1 版,由於目前版本變動的幅度還比較大,如果之前就已經有在 Mac 上安裝好 Asp.Net 5 環境的話,可能必須要再確認是否有升級到最新版本,特別需要注意不要使用到 Mono 版的 Runtime ,必須要使用 Coreclr 版的 Runtime。
-
打開 Terminal ,使用以下指令升級 dnvm
dnvm update-self
-
升級 dnx coreclr 版本的 runtime 至 Rc1
dnvm upgrade -r coreclr
-
確認使用的版本為 1.0.0-rc1-final , Runtime 是 Coreclr
dnvm list
建立 Blog 網站框架
在 Mac 環境上,由於沒有 Visual Studio ,所以微軟基於 yoeman 開發了一套使用 Command 產生開發範本的工具 generator-aspnet ,所有建立網站或是新增 Class 的工作都可以在 Terminal 透過 Command 來進行新增,這一點也會跟原本的操作習慣比較不一樣,但是與其他語言(例如 Ror )的使用方式更貼近,目前 Visual Studio Code 還沒有將新增程式範本的功能整合進去,或許未來會加到 Visual Studio Code 之中,不過如果想要在其他平台上開發或使用 .Net 應用程式的話,還是盡早的熟悉一下 Command 的操作會更好一些。
-
打開 Terminal ,使用指令產生 Asp.Net 5的專案程式碼,選擇 Web Application Basic [without Membership and Authorization]
yo aspnet
-
輸入網站名稱 Blogging
-
切換至網站目錄,還原套件並執行網站
cd Blogging dnu restore #還原套件 dnx web
-
打開瀏覽器,開啟 http://localhost:5000 ,可以看到網站成功執行
安裝 EntityFramework 7
在 Windows 上使用 EntityFramework 進行網站開發時,我們通常會選擇使用 Localdb 來搭配作為資料庫的測試環境,而在 Mac 上是沒有 SqlServer 可以使用的,所以在這次的範例中,我會像大家介紹如何使用 EntityFramework 與 Sqlite 進行搭配,作為開發環境使用測試。
-
打開 Terminal ,安裝 EntityFramework 與 Sqlite 所需要的 Nuget 套件
dnu install EntityFramework.Commands dnu install EntityFramework.Sqlite
-
安裝成功之後,可以在 project.json 中,看到這兩項出現在 dependencies
-
為了方便之後進行資料庫操作,在 project.json 建立 EntityFramework 操作的捷徑,在 project.json 的 commands 區段新增以下指令
"ef": "EntityFramework.Commands"
-
在 Terminal 測試指令是否正確
dnx ef
建立 Blog 資料庫與欄位
-
打開 Terminal ,建立 Models 資料夾,以及建立 BlogDbContext 作為操作資料庫的媒介
mkdir Models cd Models yo aspnet:Class BlogDbContext
這邊我們也使用了 generator-aspnet 來幫助我們建立 Class ,建立的 Class 會像這樣
-
修改 BlogDbContext 繼承 DbContext ,新增 Post Property,記得 using Microsoft.Data.Entity
using Microsoft.Data.Entity; public class BlogDbContext: DbContext { public DbSet<Post> Posts { get; set; } }
-
新增 Post Class,設定所需要的欄位
yo aspnet:Class Post
Post 的資料欄位
using System.ComponentModel.DataAnnotations; public class Post { [Key] public int Id { get; set; } [Required] public string Title { get; set; } public string Body { get; set; } public DateTime CreatedAt { get; set; } }
-
打開網站根目錄的 Startup.cs ,修改 ConfigureServices 方法,將 BlogDbContext 註冊到 Asp.Net 5 所內建的 DI Framework 中,並設定使用 Sqlite
using System.IO; using Microsoft.Data.Entity; using Microsoft.Extensions.PlatformAbstractions; public void ConfigureServices(IServiceCollection services) { // Add Entity Framework var path = PlatformServices.Default.Application.ApplicationBasePath; services.AddEntityFramework() .AddSqlite() .AddDbContext<BlogDbContext>( option => option.UseSqlite("Filename=" + Path.Combine(path, "blog.db"))); // Add framework services. services.AddMvc(); }
-
在網站根目錄打開 Terminal ,建立新的 Migration 並更新資料庫
dnx ef migrations add InitialDatabase dnx ef database update
操作畫面
-
我們可以在網站根目錄下發現建立了 blog.db ,如果在 Mac 上想要瀏覽 sqlite 資料庫的話,也可以使用這套 Open Source 的 sqlite 瀏覽工具 sqlitebrowser
新增及瀏覽 Blog 功能
準備完資料庫以及資料表之後,接下來我們要繼續把 Blog 的新刪修查功能完成,這部分與原本的 Asp.Net Mvc 使用方式幾乎是一模一樣。
-
在根目錄打開 Terminal ,新增 PostController
yo aspnet:MvcController PostController
-
打開 PostController ,增加新刪修查的程式碼
public class PostController : Controller { private BlogDbContext blogDbContext; public PostController(BlogDbContext dbContext){ this.blogDbContext = dbContext; } // GET: /<controller>/ public IActionResult Index() { var posts = this.blogDbContext.Posts.ToList(); return View(posts); } // GET: Posts/Details/5 public ActionResult Details(int? id) { if (id == null) { return new BadRequestResult(); } Post post = this.blogDbContext.Posts.Where(i=> i.Id == id).FirstOrDefault(); if (post == null) { return HttpNotFound(); } return View(post); } // GET: Posts/Create public IActionResult Create() { return View(); } // POST: Posts/Create // 若要免於過量張貼攻擊,請啟用想要繫結的特定屬性,如需 // 詳細資訊,請參閱 http://go.microsoft.com/fwlink/?LinkId=317598。 [HttpPost] [ValidateAntiForgeryToken] public IActionResult Create([Bind("Id,Title,Body,CreatedAt")] Post post) { if (ModelState.IsValid) { this.blogDbContext.Posts.Add(post); this.blogDbContext.SaveChanges(); return RedirectToAction("Index"); } return View(post); } // GET: Posts/Edit/5 public ActionResult Edit(int? id) { if (id == null) { return new BadRequestResult(); } Post post = this.blogDbContext.Posts.Where(i=> i.Id == id).FirstOrDefault(); if (post == null) { return HttpNotFound(); } return View(post); } // POST: Posts/Edit/5 // 若要免於過量張貼攻擊,請啟用想要繫結的特定屬性,如需 // 詳細資訊,請參閱 http://go.microsoft.com/fwlink/?LinkId=317598。 [HttpPost] [ValidateAntiForgeryToken] public ActionResult Edit([Bind("Id,Title,Body,CreatedAt")] Post post) { if (ModelState.IsValid) { this.blogDbContext.Entry(post).State = EntityState.Modified; this.blogDbContext.SaveChanges(); return RedirectToAction("Index"); } return View(post); } // GET: Posts/Delete/5 public ActionResult Delete(int? id) { if (id == null) { return new BadRequestResult(); } Post post = this.blogDbContext.Posts.Where(i=> i.Id == id).FirstOrDefault(); if (post == null) { return HttpNotFound(); } return View(post); } // POST: Posts/Delete/5 [HttpPost, ActionName("Delete")] [ValidateAntiForgeryToken] public ActionResult DeleteConfirmed(int id) { Post post = this.blogDbContext.Posts.Where(i=> i.Id == id).FirstOrDefault(); this.blogDbContext.Posts.Remove(post); this.blogDbContext.SaveChanges(); return RedirectToAction("Index"); } protected override void Dispose(bool disposing) { if (disposing) { this.blogDbContext.Dispose(); } base.Dispose(disposing); } }
-
建立新增頁面
yo aspnet:MvcView Post/Create
Create.cshtml
@model Blogging.Models.Post @{ ViewBag.Title = "Create"; } <h2>Create</h2> @using (Html.BeginForm()) { @Html.AntiForgeryToken() <div class="form-horizontal"> @Html.ValidationSummary(true, "", new { @class = "text-danger" }) <div class="form-group"> @Html.LabelFor(model => model.Title, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Title, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Title, "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.Body, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Body, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Body, "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.CreatedAt, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.CreatedAt, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.CreatedAt, "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> <div class="col-md-offset-2 col-md-10"> <input type="submit" value="Create" class="btn btn-default" /> </div> </div> </div> }
-
建立查詢頁面
yo aspnet:MvcView Post/Details
Details.cshtml
@model Blogging.Models.Post @{ ViewBag.Title = "Details"; } <h2>Details</h2> <div> <h4>Post</h4> <hr /> <dl class="dl-horizontal"> <dt> @Html.DisplayNameFor(model => model.Title) </dt> <dd> @Html.DisplayFor(model => model.Title) </dd> <dt> @Html.DisplayNameFor(model => model.Body) </dt> <dd> @Html.DisplayFor(model => model.Body) </dd> <dt> @Html.DisplayNameFor(model => model.CreatedAt) </dt> <dd> @Html.DisplayFor(model => model.CreatedAt) </dd> </dl> </div> <p> @Html.ActionLink("Edit", "Edit", new { id = Model.Id }) | @Html.ActionLink("Back to List", "Index") </p>
-
建立修改頁面
yo aspnet:MvcView Post/Edit
Edit.cshtml
@model Blogging.Models.Post @{ ViewBag.Title = "Edit"; } <h2>Edit</h2> @using (Html.BeginForm()) { @Html.AntiForgeryToken() <div class="form-horizontal"> <h4>Post</h4> <hr /> @Html.ValidationSummary(true, "", new { @class = "text-danger" }) @Html.HiddenFor(model => model.Id) <div class="form-group"> @Html.LabelFor(model => model.Title, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Title, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Title, "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.Body, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Body, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Body, "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.CreatedAt, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.CreatedAt, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.CreatedAt, "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> <div class="col-md-offset-2 col-md-10"> <input type="submit" value="Save" class="btn btn-default" /> </div> </div> </div> } <div> @Html.ActionLink("Back to List", "Index") </div>
-
建立刪除頁面
yo aspnet:MvcView Post/Delete
Delete.cshtml
@model Blogging.Models.Post @{ ViewBag.Title = "Delete"; } <h2>Delete</h2> <h3>Are you sure you want to delete this?</h3> <div> <h4>Post</h4> <hr /> <dl class="dl-horizontal"> <dt> @Html.DisplayNameFor(model => model.Title) </dt> <dd> @Html.DisplayFor(model => model.Title) </dd> <dt> @Html.DisplayNameFor(model => model.Body) </dt> <dd> @Html.DisplayFor(model => model.Body) </dd> <dt> @Html.DisplayNameFor(model => model.CreatedAt) </dt> <dd> @Html.DisplayFor(model => model.CreatedAt) </dd> </dl> @using (Html.BeginForm()) { @Html.AntiForgeryToken() <div class="form-actions no-color"> <input type="submit" value="Delete" class="btn btn-default" /> | @Html.ActionLink("Back to List", "Index") </div> } </div>
-
執行程式,可以成功的操作 Blog 的新刪修查功能
小結
新版本的 Asp.Net 5 開放了在 Windows 之外的平台也能進行開發的新功能,也因為不同作業系統和平台的關係,在開發上的習慣和操作方式也不一樣,但這也讓我們看到未來 Asp.Net 5 可能在更多不同環境的操作下產生更多應用與發展的可能性,如果對於在非 Windows 平台上開發 Asp.Net 5 的朋友,可以趁早熟悉並習慣一下這些新的開發嘗試與體驗喔!關於今天的內容,歡迎大家一起討論!