這邊使用 .Net Core 5 版本,Net Core 6 會不太一樣,大致原理都是一致的。這邊我觀看學習教學影片邊紀錄,我覺得動手做比較容易了解問題與忽略問題地方,我那個影片有操作一些錯誤地方,不是他忘記步驟,而是當我們忘記那些步驟可以快速從那個地方找出問題解決。
專案選擇
這邊要選擇 Web API 選項。
Startup.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "WebApplication6", Version = "v1" });
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "WebApplication6 v1"));
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
|
程式上面重點:
- Configure 註冊容器服務,會在這邊配置訊息。
- ConfigureServices 依賴注入服務都會在這邊設定。
Tip
這邊可以看到 Startup()
注入了 IConfiguration,這邊我後續讀完覺得很奇怪,ConfigureServices()
這邊不是才註冊容器嗎?為什麼建構子就能注入,剛好查看官方文件原來能注入東西很少。
使用泛型主機 () IHostBuilder 時,只能將下列服務類型插入 Startup 建構函式:
IWebHostEnvironment
IHostEnvironment
IConfiguration
相關連結: 點我
.NET Core 加入 Net Core MVC 中間件
這邊提一下中間件英文是MIddleware
。
Tip
這邊我在學習 Middleware 我發現跟 Laravel Middleware 很像,回想我當初學的 Spring Boot 沒有這一層東西,但一樣還是可以做到這一層事情。沒錯,是 AOP。所以Spring Boot 不需要有 Middleware 這一個東西。
相關連結: Spring Boot AOP 小記
MVC 加入到 asp.net core 依賴注入容器中
1
2
3
4
|
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}
|
但是新版,上面可能要做變更,參考從 ASP.NET Core 2.2 移轉至 3.0 | Microsoft Docs文章。
這邊我用 .Net Core 5
1
2
3
4
|
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options => options.EnableEndpointRouting = false);
}
|
設定中間件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseMvcWithDefaultRoute();
app.Run(async (context) =>
{
await context.Response.WriteAsync("Hello world");
});
|
從 ASP.NET Core 2.2 移轉至 3.0 | Microsoft Docs
addMvc 和 addMvcCore
addMvcCore: 只包含MVC功能。所以Controller 用到JSON 回傳會錯誤。
1
2
3
4
|
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}
|
addMvc: 包含MVC Core和相關第三方常用服務方法。
1
2
3
4
|
public void ConfigureServices(IServiceCollection services)
{
services.AddMvcCore();
}
|
簡單說,addMvc
中間件比addMvcCore
中間件功能還多,這邊剛入門的可以先不用太在意這邊。我後面有篇筆記有紀錄這兩種不太一樣東西。
建立 Controller
在專案建立 Controllers
,建立HomeController
1
2
3
4
5
6
7
8
9
10
11
12
|
using Microsoft.AspNetCore.Mvc;
namespace WebApplication3.Controllers
{
public class HomeController : Controller
{
public IActionResult Index()
{
return Json(new { a = "1", b = "2" });
}
}
}
|
所有 API 可以回傳 IActionResult
,這邊其實有很多物件繼承這個。他可以針對不同類型去做回傳。我網路上有找到繼承圖片。
參考:Action results in ASP.NET CORE APIs
Tip
我目前工作常用到的有IActionResult
、IJSONResult
、FileResult
等等。這邊你可以寫的很死,也可以放你新增的類別也可以,我目前我的專案是這樣用,當人也可以這樣寫ActionResult<你的Class>
,但我目前不知道直接這樣寫的好處?跟強制直接寫你的Class
這樣的好處在哪?
Question
這樣編譯不會錯,這讓我很好奇。有空再整理筆記
新增 Model
新增Dog.cs。
在public class
上面打///
按 Enter,這邊可以得到下面結果。
1
2
3
4
5
6
7
8
9
|
namespace WebApplication3.Models
{
/// <summary>
/// 狗的測試模型
/// </summary>
public class Dog
{
}
}
|
在public class Dog
裡面打上prop
按下兩下Tab
,可以快速設定屬性setter,getter
。
建立 Repository
這邊選擇介面。
1
2
3
4
5
6
7
|
namespace WebApplication3.Models
{
public interface IDogRepository
{
public Dog getDog(int id);
}
}
|
建立 MockRepository
可用 ctor
按下 tab 快速建立MockDogRepository
建構函示,可以參考:C# 程式碼片段 - Visual Studio (Windows) | Microsoft Docs文章。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
using System.Collections.Generic;
namespace WebApplication3.Models
{
public class MockDogRepository : IDogRepository
{
private List<Dog> _dogList;
public MockDogRepository()
{
}
public Dog getDog(int id)
{
throw new System.NotImplementedException();
}
}
}
|
最後再補上 Mock 資料。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
using System.Collections.Generic;
namespace WebApplication3.Models
{
public class MockDogRepository : IDogRepository
{
private List<Dog> _dogList;
public MockDogRepository()
{
_dogList = new List<Dog>()
{
new Dog(){Id=1,Name ="dog1",Address="tw"},
new Dog(){Id=2,Name ="dog2",Address="tw"},
new Dog(){Id=3,Name ="dog3",Address="tw"},
};
}
public Dog getDog()
{
throw new System.NotImplementedException();
}
}
}
|
Controller 依賴注入 DogRepository
依賴注入這邊跟 Laravel 很像,要完成下面動作做注入。
1
2
3
4
5
6
|
private readonly IDogRepository _dogRepostory;
public HomeController(IDogRepository dogRepository)
{
_dogRepostory = dogRepository;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
using Microsoft.AspNetCore.Mvc;
using WebApplication3.Models;
namespace WebApplication3.Controllers
{
public class HomeController : Controller
{
private readonly IDogRepository _dogRepostory;
public HomeController(IDogRepository dogRepository)
{
_dogRepostory = dogRepository;
}
public string Index()
{
return _dogRepostory.getDog(1).Name;
// return Json(new { a = "1", b = "2" });
}
}
}
|
http://localhost:46201/home/index
程式運行發生錯誤
這邊不用太擔心,這邊是註冊容器,沒辦法入住DI。
依賴注入
Tip
假如你有學過 Spring Boot 和 Laravel 的話應該對這個算滿熟悉。想當初我學 Laravel 第一次碰注入(DI)這個玩意也是看不太懂。這個有點跟類別static
有點像,不需要再new
出來。
首先你可能要知道依賴注入是要如何註冊的,Spring 依賴注入可以看我之前寫過這篇,因為Laravel 注入還沒學會,所以就沒深入他怎麼註冊的。回到重點,Net Core 依賴注入只有一種方法,都要去手動註冊,內鍵沒有自動注入,但使用第三方套件也能做到。
Warning
這個有點跟類別static
有點像,不需要再new
出來。
在使用上可能要了解注入物件的生命週期,通常 Scope 有分幾類,這個有時候會影響程式結果,比較常都用單例模式
。這邊我工作上面很多都把這個當全域變數用,我覺得Helper
相關類的可以用 static
,但其實有些可以做到 static
,像是 JWT 加密就可以直接用。
但有些會吃IConfiguration
可以考慮用一個 Service 出來,把設定用上去,再把 Service
注入IConfiguration
再引用static Helper
執行,這樣做程式分層架構可以更好去模組化。但這樣要寫很多類別,很多人都不會這樣做樣子…
startup.cs
1
2
3
4
5
6
|
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options => options.EnableEndpointRouting = false);
services.AddSingleton<IDogRepository, MockDogRepository>();
}
|
實作單例模式,才能正常運作。
http://localhost:46201/home/index
依賴注入種類
- AddSingleton()
- AddTransient()
- AddScoped()
優點
Controller JSON 範例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
using Microsoft.AspNetCore.Mvc;
using WebApplication3.Models;
namespace WebApplication3.Controllers
{
public class HomeController : Controller
{
private readonly IDogRepository _dogRepostory;
public HomeController(IDogRepository dogRepository)
{
_dogRepostory = dogRepository;
}
public string Index()
{
return _dogRepostory.getDog(1).Name;
// return Json(new { a = "1", b = "2" });
}
public JsonResult Details()
{
Dog dog = _dogRepostory.getDog(1);
return Json(dog);
}
}
}
|
看 HTTP 協議傳回格式
ObjectResult
startup.cs
1
2
3
4
5
6
|
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options => options.EnableEndpointRouting = false).AddXmlSerializerFormatters();
services.AddSingleton<IDogRepository, MockDogRepository>();
}
|
HomeControler.cs
1
2
3
4
5
|
public ObjectResult Details()
{
Dog dog = _dogRepostory.getDog(1);
return new ObjectResult(dog);
}
|
View
1
2
3
4
5
|
public IActionResult Details()
{
Dog dog = _dogRepostory.getDog(1);
return View(dog);
}
|
這個錯誤會顯示默認 VIEW 三個路徑
- /Views/Home/Details.cshtml
- /Views/Shared/Details.cshtml
- /Pages/Shared/Details.cshtml
除了一個一個加資料夾
也可以再 View 方法右鍵新增 View,按下新增檢視,
Views/Home/Details(View)
1
2
3
4
|
@{
ViewData["Title"] = "Details";
}
<h1>Details</h1>
|
.Net Core 5 建立檢視失敗可以參考(參考)
c# - How to create MVC5 web project in visual studio 2022 - Stack Overflow
自訂義 View 發現
可以自訂View頁面,有下面三種方式。
View("Test")
=> /Views/Home/Test
View("~/Test/xxx.cshtml");
=> 絕對路徑
View("../../xxx");
=> 相對路徑,不用加 cshtml
推薦使用絕對路徑
。
1
2
3
4
|
public virtual ViewResult View();
public virtual ViewResult View(string viewName, object model);
public virtual ViewResult View(object model);
public virtual ViewResult View(string viewName);
|
Controller 傳遞資料到 View
- 使用 ViewData
- 使用 ViewBag
- 強型別View
ViewData
- 是弱型別的字典(Dictonary)物件。
- 使用 string 型別的Key值,儲存和查詢 ViewData 字典中的資料
- 執行時動態解析
- 沒有智能感知,編譯時也沒有型別檢查
Controllers\HomeController.cs
1
2
3
4
5
6
7
8
9
10
|
public IActionResult Details()
{
Dog dog = _dogRepostory.getDog(1);
ViewData["PageTitle"] = "Dog Details";
ViewData["Dog"] = dog;
return View(dog);
}
|
Views\Home\Details.cshtml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
@using WebApplication3.Models
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>@ViewData["PageTitle"]</title>
</head>
<body>
<h3>@ViewData["PageTitle"]</h3>
@{
var dog = ViewData["Dog"] as Dog;
}
<div>
名稱:@dog.Name
</div>
<div>
地址:@dog.Address
</div>
</body>
</html>
|
ViewBag
- ViewBag是ViewData的包裝器
- 它們都建立了一個弱型別的View
- ViewData使用字串Key來儲存和查詢資料
- ViewBag使用動態屬性來儲存和查詢資料
- 均是在運釆時動態解析
- 均不是供編譯時型別檢查,沒有智能提示。
- 首選方法是使用強類別模型物件,將資料從控制器傳遞到View。
Views\Home\Details.cshtml
1
2
3
4
5
6
7
8
9
10
|
public IActionResult Details()
{
Dog dog = _dogRepostory.getDog(1);
ViewBag.PageTitle = "Dog Details";
ViewBag.Dog = dog;
return View(dog);
}
|
Views\Home\Details.cshtml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
@using WebApplication3.Models
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>@ViewBag.PageTitle</title>
</head>
<body>
<h3>@ViewBag.PageTitle</h3>
<div>
名稱:@ViewBag.Dog.Name
</div>
<div>
地址:@ViewBag.Dog.Address
</div>
</body>
</html>
|
強型別View
- 使用
@model
指另指定型別
- 使用
@Model
抓出物件屬性
- 強行別類型View提供編譯時類型檢查和智能提示
1
2
3
4
5
6
|
public IActionResult Details()
{
Dog dog = _dogRepostory.getDog(1);
return View(dog);
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
@model WebApplication3.Models.Dog
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div>
名稱:@Model.Name
</div>
<div>
地址:@Model.Address
</div>
@Model
</body>
</html>
|
ViewModel 視圖模型
模型物件無法滿足視圖所需的所有資料時,就需要使用 ViewModel了。
建立ViewModels
資料夾,檔案以 *ViewModel.cs
做結尾`。
HomeDetailsViewModel.cs
1
2
3
4
5
6
7
8
9
10
11
|
using WebApplication3.Models;
namespace WebApplication3.ViewModels
{
public class HomeDetailsViewModel
{
public string PageTitle { get; set; }
public Dog Dog { get; set; }
}
}
|
WebApplication3\WebApplication3\Controllers\HomeController.cs
1
2
3
4
5
6
7
8
9
10
11
|
public IActionResult Details()
{
HomeDetailsViewModel homeDetailsViewModel = new HomeDetailsViewModel()
{
Dog = _dogRepostory.getDog(1),
PageTitle = "狗的詳情"
};
return View(homeDetailsViewModel);
}
|
WebApplication3\WebApplication3\Views\Home\Details.cshtml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
@model WebApplication3.ViewModels.HomeDetailsViewModel
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>@Model.PageTitle</title>
</head>
<body>
<div>
名稱:@Model.Dog.Name
</div>
<div>
地址:@Model.Dog.Address
</div>
@Model
</body>
</html>
|
總結小記:
- 新增 ViewModel 物件,設定好屬性。
- Controler新增ViewModel,把這個物件傳到 View上面
- View 使用 ViewModel物件。
實現 List 視圖
WebApplication3\WebApplication3\Models\IDogRepository.cs
1
2
3
4
5
6
7
8
9
10
11
|
using System.Collections.Generic;
namespace WebApplication3.Models
{
public interface IDogRepository
{
public Dog getDog(int id);
// 新增 GetAllDogs
public IEnumerable<Dog> GetAllDogs();
}
}
|
WebApplication3\WebApplication3\Models\MockDogRepository.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
using System.Collections.Generic;
using System.Linq;
namespace WebApplication3.Models
{
public class MockDogRepository : IDogRepository
{
private List<Dog> _dogList;
public MockDogRepository()
{
_dogList = new List<Dog>()
{
new Dog(){Id=1,Name ="dog1",Address="tw"},
new Dog(){Id=2,Name ="dog2",Address="tw"},
new Dog(){Id=3,Name ="dog2",Address="tw"},
};
}
// 新增這個方法
public IEnumerable<Dog> GetAllDogs()
{
return _dogList;
}
public Dog getDog(int id)
{
return _dogList.FirstOrDefault(a => a.Id == id);
}
}
}
|
WebApplication3\WebApplication3\Controllers\HomeController.cs
1
2
3
4
5
6
|
public IActionResult Index()
{
var model = _dogRepostory.GetAllDogs();
return View(model);
}
|
WebApplication3\WebApplication3\Views\Home\Index.cshtml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
@model IEnumerable<WebApplication3.Models.Dog>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>狗的清單</title>
</head>
<body>
<table>
<tr>
<th>序號</th>
<th>名稱</th>
<th>地址</th>
</tr>
@foreach (var dog in Model)
{
<tr>
<td>
@dog.Id
</td>
<td>
@dog.Name
</td>
<td>
@dog.Address
</td>
</tr>
}
</table>
</body>
</html>
|
.NET Core MVC 部局視圖
讓web應用程式中讓所有的視圖保持外觀一致性。布局檔案默認為_Layout.cshtml
。通常放在(Views/Pages)/Shared
資料夾。
在View或Page 建立 Shared
資料夾。
建立 Shared/_Layout.cshtml
。
Shared/_Layout.cshtml
1
2
3
4
5
6
7
8
9
10
11
12
|
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>@ViewBag.Title</title>
</head>
<body>
@RenderBody()
</body>
</html>
|
F:\source\repos\WebApplication3\WebApplication3\Views\Home\Details.cshtml
1
2
3
4
5
6
7
8
9
10
11
12
13
|
@model WebApplication3.ViewModels.HomeDetailsViewModel
@{
Layout = "~/Views/Shared/_Layout.cshtml";
ViewBag.Title = @Model.PageTitle;
}
<div>
名稱:@Model.Dog.Name
</div>
<div>
地址:@Model.Dog.Address
</div>
@Model
|
WebApplication3\WebApplication3\Views\Home\Index.cshtml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
@model IEnumerable<WebApplication3.Models.Dog>
@{
Layout = "~/Views/Shared/_Layout.cshtml";
ViewBag.Title = "狗的清單";
}
<table>
<tr>
<th>序號</th>
<th>名稱</th>
<th>地址</th>
</tr>
@foreach (var dog in Model)
{
<tr>
<td>
@dog.Id
</td>
<td>
@dog.Name
</td>
<td>
@dog.Address
</td>
</tr>
}
</table>
|
布局頁面的結點(Sections)
提了一種方法讓某些頁面元素放在一起。可以強制性使用或者可選擇性使用。使用RenderSection()
來呼叫
WebApplication3\WebApplication3\Views\Shared_Layout.cshtml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>@ViewBag.Title</title>
</head>
<body>
<div>
@RenderBody()
</div>
@RenderSection("Scripts",required: false)
</body>
</html>
|
中間那一段@RenderSection("Scripts",required: false)
可以改寫
1
2
3
4
|
@if (IsSectionDefined("Scripts"))
{
@RenderSection("Scripts",required: false)
}
|
WebApplication3\WebApplication3\Views\Home\Details.cshtml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
@model WebApplication3.ViewModels.HomeDetailsViewModel
@{
Layout = "~/Views/Shared/_Layout.cshtml";
ViewBag.Title = @Model.PageTitle;
}
<div>
名稱:@Model.Dog.Name
</div>
<div>
地址:@Model.Dog.Address
</div>
@Model
@section Scripts{
<script src="~/js/site.js"></script>
}
|
重點
1
2
3
|
@section Scripts{
<script src="~/js/site.js"></script>
}
|
結果會顯示
_ViewStart.cshtml
_ViewStart.cshtml
程式碼會先在單個是途中先執行程式碼。減少了程式碼重複性。
新增時候選擇
建立在View資料夾
1
2
3
|
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
|
其他View屬性就不須指定_Layout
。
也可以簡略寫成如下
1
2
3
|
@{
Layout = "_Layout2";
}
|
執行_ViewStart.cshtml順序如下圖,裡面的Home資料夾,依序先執行1,在執行2,依序後蓋前設定。
_ViewImport.cshtml
上面我們寫的專案需要寫很長文字去讀取物件出來,如@model WebApplication3.ViewModels.HomeDetailsViewModel
,_ViewImport.cshtml
就是很好解決這個問題。
新增檔案建立到Views資料夾,參考下圖
WebApplication3\WebApplication3\Views_ViewImports.cshtml
1
|
@using WebApplication3.Models;
|
我們在原有的View就可以不用寫前面的 namespace
簡單整理:
- 需使用
@using
指令包含公共命局空間
- _ViewImports 文件還支持以下指令
- @addTagHelper
- @removeTagHelper
- @tagHelperPrefix
- @model
- @inherits
- @inject
- ViewImports 文件支持分層讀取,這邊跟
_ViewStart.cshtml
一樣。1先讀2後讀,後蓋前設定。
路由(Route)
預設路由
WebApplication3\WebApplication3\Startup.cs
1
2
3
4
5
6
|
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
app.UseMvcWithDefaultRoute();
...
}
|
我們這邊可以看到使用 app.UseMvcWithDefaultRoute()
做預設路由。從下面註解可以看到預設規則。
這邊使用原本需要手動建立 router 規則。參考如下。
1
2
3
4
5
6
|
//app.UseMvcWithDefaultRoute();
app.UseMvc(routes =>
{
routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}");
});
|
預設 Router 規則參照如下。
下面直接操作看看。
修改 HomeController.cs
details 補上傳入 id 參數
1
2
3
4
5
6
7
8
9
10
11
|
public IActionResult Details(int id)
{
HomeDetailsViewModel homeDetailsViewModel = new HomeDetailsViewModel()
{
Dog = _dogRepostory.getDog(id),
PageTitle = "狗的詳情"
};
return View(homeDetailsViewModel);
}
|
WebApplication3\WebApplication3\Controllers\HomeController.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
using Microsoft.AspNetCore.Mvc;
using WebApplication3.Models;
using WebApplication3.ViewModels;
namespace WebApplication3.Controllers
{
public class HomeController : Controller
{
private readonly IDogRepository _dogRepostory;
public HomeController(IDogRepository dogRepository)
{
_dogRepostory = dogRepository;
}
public IActionResult Index()
{
var model = _dogRepostory.GetAllDogs();
return View(model);
}
public IActionResult Details(int id)
{
HomeDetailsViewModel homeDetailsViewModel = new HomeDetailsViewModel()
{
Dog = _dogRepostory.getDog(id),
PageTitle = "狗的詳情"
};
return View(homeDetailsViewModel);
}
}
}
|
屬性路由
使用屬性路由,我們使用Route()
屬性定義路由。
屬性路由通常定義在Controller
或Controller的方法
上面
強制上層路由呼叫以/
和~/
來做設定。
這邊我們在Startup.cs
先取消預設路由做測試。
這邊注意,我.NET Core 5 版本預設有 Page 資料夾,這邊建議先重新命名資料夾名稱,這樣就不會跟你的 Router 衝突到。
Startup.cs
WebApplication3\WebApplication3\Controllers\HomeController.cs
1
2
3
4
5
6
7
8
9
|
[Route("")]
[Route("Home")]
[Route("Home/Index")]
public IActionResult Index()
{
var model = _dogRepostory.GetAllDogs();
return View(model);
}
|
查看結果:
1
2
3
4
5
6
7
8
9
10
11
12
|
[Route("Home/Details/{id?}")]
public IActionResult Details(int id)
{
HomeDetailsViewModel homeDetailsViewModel = new HomeDetailsViewModel()
{
Dog = _dogRepostory.getDog(id),
PageTitle = "狗的詳情"
};
return View(homeDetailsViewModel);
}
|
id
空值會報錯!
1
2
3
4
5
6
7
8
9
10
11
12
|
[Route("Home/Details/{id?}")]
public IActionResult Details(int? id)
{
HomeDetailsViewModel homeDetailsViewModel = new HomeDetailsViewModel()
{
Dog = _dogRepostory.getDog(id??1),
PageTitle = "狗的詳情"
};
return View(homeDetailsViewModel);
}
|
解決問題。
Controller 跟 Router 命名不一樣
這邊看這兩張圖,發現他找View會找不到。
這邊就需要決斷路徑指定View,上面View有提到。
1
2
3
4
5
6
7
8
9
|
[Route("")]
[Route("Home")]
[Route("Home/Index")]
public IActionResult Index()
{
var model = _dogRepostory.GetAllDogs();
return View("~/Views/Home/Index.cshtml",model);
}
|
Route 放置 Controller 上面
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
using Microsoft.AspNetCore.Mvc;
using WebApplication3.Models;
using WebApplication3.ViewModels;
namespace WebApplication3.Controllers
{
[Route("Home")]
public class HomeController : Controller
{
private readonly IDogRepository _dogRepostory;
public HomeController(IDogRepository dogRepository)
{
_dogRepostory = dogRepository;
}
[Route("~/")]
[Route("")]
[Route("Index")]
public IActionResult Index()
{
var model = _dogRepostory.GetAllDogs();
return View(model);
}
[Route("Details/{id?}")]
public IActionResult Details(int? id)
{
HomeDetailsViewModel homeDetailsViewModel = new HomeDetailsViewModel()
{
Dog = _dogRepostory.getDog(id??1),
PageTitle = "狗的詳情"
};
return View(homeDetailsViewModel);
}
}
}
|
在自動調整方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
using Microsoft.AspNetCore.Mvc;
using WebApplication3.Models;
using WebApplication3.ViewModels;
namespace WebApplication3.Controllers
{
[Route("[controller]")]
public class HomeController : Controller
{
private readonly IDogRepository _dogRepostory;
public HomeController(IDogRepository dogRepository)
{
_dogRepostory = dogRepository;
}
[Route("~/")]
[Route("")]
[Route("[action]")]
public IActionResult Index()
{
var model = _dogRepostory.GetAllDogs();
return View(model);
}
[Route("[action]/{id?}")]
public IActionResult Details(int? id)
{
HomeDetailsViewModel homeDetailsViewModel = new HomeDetailsViewModel()
{
Dog = _dogRepostory.getDog(id??1),
PageTitle = "狗的詳情"
};
return View(homeDetailsViewModel);
}
}
}
|
在更精簡方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
using Microsoft.AspNetCore.Mvc;
using WebApplication3.Models;
using WebApplication3.ViewModels;
namespace WebApplication3.Controllers
{
[Route("[controller]/[action]")]
public class HomeController : Controller
{
private readonly IDogRepository _dogRepostory;
public HomeController(IDogRepository dogRepository)
{
_dogRepostory = dogRepository;
}
[Route("~/")]
[Route("~/Home")]
public IActionResult Index()
{
var model = _dogRepostory.GetAllDogs();
return View(model);
}
[Route("{id?}")]
public IActionResult Details(int? id)
{
HomeDetailsViewModel homeDetailsViewModel = new HomeDetailsViewModel()
{
Dog = _dogRepostory.getDog(id??1),
PageTitle = "狗的詳情"
};
return View(homeDetailsViewModel);
}
}
}
|
實戰中還是用…
Startup.cs
1
2
3
4
|
app.UseMvc(routes =>
{
routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}");
});
|
總結
仔細再回來看這篇,這邊已經把剛入手要會的東西。再有相關程式經驗學習 Net Core 也是可以很快上手,再搭配 Visual Studio 智慧提示,你可以很快撰寫程式碼,也可以知道程式哪裡錯。
Net Core的 View 真的讓我滿經驗,在我學 Laravel 和 Spring Boot 的 View 時候,編譯器無法判別哪邊有寫錯誤(也可能我不會設定🤣),Visual Studio 就可以做到。在寫 View 時候有些沒有判斷到都可以早點發現。後面我工作是做純後端,所以平常是不寫 View,但我會建議去了解它怎麼使用。