2.3.4 Web API -- MVC終結點
- MVC與MVVM
- 模型綁定
- 自定義模型綁定器
- 模型驗證
- 返回數據處理
MVC與MVVM
MVC
ASP.NET Core MVC 概述:https://docs.microsoft.com/zh-cn/aspnet/core/mvc/overview?view=aspnetcore-5.0
MVVM
ASP.NET Core 中的 Razor Pages 介紹:https://docs.microsoft.com/zh-cn/aspnet/core/razor-pages/?view=aspnetcore-5.0&tabs=visual-studio
Razor Pages 沒有 Controller,Model 中可以包含方法
ASP.NET Core MVC 注入
services.AddControllers();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
MVC Endpoint
模型綁定
- 什麼是模型綁定
- 來源有哪些
- 複雜的數據綁定
ASP.NET Core 中的模型綁定:https://docs.microsoft.com/zh-cn/aspnet/core/mvc/models/model-binding?view=aspnetcore-5.0
什麼是模型綁定
控制器和 Razor 頁面處理來自 HTTP 請求的數據。 例如,路由數據可以提供一個記錄鍵,而發佈的表單域可以為模型的屬性提供一個值。 編寫代碼以檢索這些值,並將其從字符串轉換為 .NET 類型不僅繁瑣,而且還容易出錯。
模型綁定會自動化該過程。 模型綁定系統:
- 從各種源(如路由數據、表單域和查詢字符串)中檢索數據。
- Razor在方法參數和公共屬性中向控制器和頁面提供數據。
- 將字符串數據轉換為 .NET 類型。
- 更新複雜類型的屬性。
來源有哪些
- [FromQuery] -從查詢字符串獲取值。
- [FromRoute] -從路由數據中獲取值。
- [FromForm] -從已發佈的表單字段中獲取值。
- [FromBody] -從請求正文中獲取值。
- [FromHeader] -從 HTTP 標頭中獲取值。
從路由數據中獲取值
[HttpGet]
[Route("option/{id}")]
public IActionResult GetOption([FromRoute] int id)
{
return Ok(new {id});
}
從查詢字符串獲取值
[HttpGet]
[Route("option/{id}")]
public IActionResult GetOption([FromRoute] int id, [FromQuery] string name)
{
return Ok(new {id, name});
}
從 HTTP 標頭中獲取值
[HttpGet]
[Route("option/{id}")]
public IActionResult GetOption([FromRoute] int id, [FromQuery] string name,[FromHeader] string termId)
{
return Ok(new {id, name, termId});
}
從已發佈的表單字段中獲取值
[HttpPost]
[Route("option/from")]
public IActionResult CreateOption([FromForm] string name, [FromForm] string id)
{
return Ok(new {name, id});
}
從請求正文中獲取值
[HttpPost]
[Route("option/body")]
public IActionResult CreateOption([FromBody] string name)
{
return Ok(name);
}
複雜的數據綁定
- 對象
- 集合
- 字典
對象
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
}
[HttpPost]
[Route("option/body")]
public IActionResult CreateOption([FromBody] Student student)
{
return Ok(student);
}
字典
[HttpGet]
[Route("option")]
public IActionResult GetOption([FromQuery] Dictionary<int, string> dic)
{
var students = new List<Student>();
foreach (var item in dic)
{
students.Add(new Student {Id = item.Key, Name = item.Value});
}
return Ok(students);
}
啟動程序,訪問:https://localhost:5001/config/option?dic[1001]=ming$dic[1002]=rank&dic[1003]=abc
輸出:
[{"id":1001,"name":"ming$dic[1002]=rank"},{"id":1003,"name":"abc"}]
自定義模型綁定器
ASP.NET Core 中的自定義模型綁定:https://docs.microsoft.com/zh-cn/aspnet/core/mvc/advanced/custom-model-binding?view=aspnetcore-5.0
ModelBinder
[ModelBinder(BinderType = typeof(AuthorEntityBinder))]
public class Author
{
public int Id { get; set; }
public string Name { get; set; }
public string GitHub { get; set; }
public string Twitter { get; set; }
public string BlogUrl { get; set; }
}
public class AuthorEntityBinder : IModelBinder
ModelBinderProvider
public class AuthorEntityBinderProvider : IModelBinderProvider
services.AddControllers(options =>
{
options.ModelBinderProviders.Insert(0, new AuthorEntityBinderProvider());
});
模型驗證
- 什麼是模型驗證
- 模型驗證的特性與消息
- FluentValidation
什麼是模型驗證
ASP.NET Core MVC 和頁面中的模型驗證 Razor:https://docs.microsoft.com/zh-cn/aspnet/core/mvc/models/validation?view=aspnetcore-5.0
Web 應用負責檢查 ModelState.IsValid 並做出相應響應
if (!ModelState.IsValid)
{
return Page();
}
模型驗證的特性與消息
- [CreditCard]:驗證屬性是否具有信用卡格式。
- [Compare]:驗證模型中的兩個屬性是否匹配。
- [EmailAddress]:驗證屬性是否具有電子郵件格式。
- [Phone]:驗證屬性是否具有電話號碼格式。
- [Range]:驗證屬性值是否在指定的範圍內。
- [RegularExpression]:驗證屬性值是否與指定的正則表達式匹配。
- [Required]:驗證字段是否不為 null。
- [StringLength]:驗證字符串屬性值是否不超過指定長度限制。
- [Url]:驗證屬性是否具有 URL 格式。
- [Remote]:通過在服務器上調用操作方法來驗證客戶端上的輸入。
[Required] [Range]
public class Student
{
[Required]
[Range(1,10,ErrorMessage = "id 為 1-10 之間的數字")]
public int Id { get; set; }
public string Name { get; set; }
}
ModelState
[HttpPost]
[Route("option/body")]
public IActionResult CreateOption([FromBody] Student student)
{
if (!ModelState.IsValid)
{
return ValidationProblem();
}
return Ok(student);
}
FluentValidation
不同場景下同一個模型有不同的驗證規則,最好將模型與驗證分開
表達式寫法:
public class CustomerValidator : AbstractValidator<Customer> {
public CustomerValidator() {
RuleFor(x => x.Surname).NotEmpty();
RuleFor(x => x.Forename).NotEmpty().WithMessage("Please specify a first name");
RuleFor(x => x.Discount).NotEqual(0).When(x => x.HasDiscount);
RuleFor(x => x.Address).Length(20, 250);
RuleFor(x => x.Postcode).Must(BeAValidPostcode).WithMessage("Please specify a valid postcode");
}
private bool BeAValidPostcode(string postcode) {
// custom postcode validating logic goes here
}
}
Installation:https://docs.fluentvalidation.net/en/latest/installation.html
Install-Package FluentValidation
StudentValidator
namespace HelloApi.Validations
{
public class StudentValidator : AbstractValidator<Student>
{
public StudentValidator()
{
RuleFor(s => s.Id).InclusiveBetween(1,10).WithMessage("id需要在1和10之間");
}
}
}
ASP.NET Core Getting Started:https://docs.fluentvalidation.net/en/latest/aspnet.html
dotnet add package FluentValidation.AspNetCore
ConfigureServices
單個添加
services.AddControllers()
.AddFluentValidation();
// 通過依賴注入的方式(單個添加)
services.AddTransient<IValidator<Student>, StudentValidator>();
全部添加
// 通過掃描程序集的方式(全部添加)
services.AddControllers()
.AddFluentValidation(fv => fv.RegisterValidatorsFromAssemblyContaining<StudentValidator>());
返回數據處理
- 返回數據類型
- 格式化響應數據
返回數據類型
ASP.NET Core Web API 中控制器操作的返回類型:https://docs.microsoft.com/zh-cn/aspnet/core/web-api/action-return-types?view=aspnetcore-5.0
- 特定類型
- IActionResult
- ActionResult
特定類型:最簡單的操作返回基元或複雜數據類型(如 string 或自定義對象類型)
IActionResult:常見返回類型為 BadRequestResult (400)、NotFoundResult (404) 和 OkObjectResult (200)
[HttpPost]
[Route("option/body")]
public IActionResult CreateOption([FromBody] Student student)
{
if (!ModelState.IsValid)
{
return ValidationProblem();
}
//return BadRequest();
//return NotFound();
return Ok(student);
}
格式化響應數據
設置 ASP.NET Core Web API 中響應數據的格式:https://docs.microsoft.com/zh-cn/aspnet/core/web-api/advanced/formatting?view=aspnetcore-5.0
瀏覽器和內容協商
services.AddControllers(options =>
{
options.RespectBrowserAcceptHeader = true;// 瀏覽器和內容協商
});
添加 XML 格式支持
services.AddControllers(options =>
{
options.RespectBrowserAcceptHeader = true; // 瀏覽器和內容協商
})
.AddXmlSerializerFormatters() // 添加 XML 格式支持
.AddFluentValidation();
啟動程序,添加 XML Headers 訪問:
添加基於 Newtonsoft.Json 的 JSON 格式支持
添加 nuget 包:Microsoft.AspNetCore.Mvc.NewtonsoftJson
services.AddControllers(options =>
{
options.RespectBrowserAcceptHeader = true; // 瀏覽器和內容協商
})
.AddNewtonsoftJson()// 添加基於 Newtonsoft.Json 的 JSON 格式支持
.AddXmlSerializerFormatters() // 添加 XML 格式支持
.AddFluentValidation();
GitHub源碼鏈接:
https://github.com/MINGSON666/Personal-Learning-Library/tree/main/ArchitectTrainingCamp/HelloApi