在ASP.Net Core中Model Binding並沒有太大的改變,
比較有感的應該是Action裡面也內建DI了,
也可以讓建構注入乾淨一點。
Model Binding又稱Data Binding,
是ASP.Net MVC中強大的功能之一,
搭配View宣告的ViewModel(Data Model)使用
,可以無腦的繫結到你想要的資料,
但有時也會因為資料綁定順序問題踩雷踩不完。
Model Binding的對象有三大資料來源:
- Route(路由):瀏覽器上的網址,如https://localhost:44363/Home/Index/1
- QueryString(查詢字串):URL上問號(?)後面的資訊,如https://localhost:44363/Home/Index?id=2
- FormData(表單資料):包在<form></form>表單中的<input>,如範例:
<form> <input name='id' type='hidden' value='3' /> </form>
建議可搭配Postman或Fiddler等封包模擬工具測試。
那如果三個資料來源同時存在呢?
筆者後續的範例會使用Postman進行測試。
送出請求後觀察Action收到的值
再拿Route跟QueryString比較看看
由此可知在Binding優序上FormData > Route > QueryString。
但我們可以使用[FromSource]來限定資料來源對象,
常見的有[FromRoute]、[FromQuery]、[FromForm]、[FromHeader]、[FromBody]等,
[FromServices]是ASP.Net Core加入的新特色,
只要在Startup ConfigureServices中進行DI註冊,
就可以透過方法注入的方式獲得物件。
我們先建立一個MyCustomService,
public class MyCustomService
{
public string getMyName => "My name is MyCustomService.";
}
並於Startup ConfigureServices中註冊DI。
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<MyCustomService>();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
接著在HomeController中新增一個方法進行測試。
public void DITest([FromServices] MyCustomService myService)
{
}
使用偵錯模式進行觀察
接下來會針對介紹一連串Model Binding的詳細操作,
如果你有手刻前端input的需求可以參考看看。
當綁定對象是單一屬性時,預設使用key-value(name-value)的方式綁定,
MVC的ModelBinder會自動忽略大小寫,
並從資料來源中尋找與變數同名的值。
當綁定對象是一個自訂類別時(通常是ViewModel),
我們依舊可使用key-value的方式綁定。
範例類別:
public class Pokemon
{
public int Id { get; set; }
public string Property { get; set; }
public string Name { get; set; }
}
測試結果:
我們也可以使用parameter_name.property_name的方式綁定,測試如下:
若同時使用則綁定帶有parameter_name的key(綁定敘述較完整者):
當綁定的物件不只一層時,
可透過.
的方式進行綁定,
我們修改一下範例類別:
public class Pokemon
{
public int Id { get; set; }
public string Property { get; set; }
public string Name { get; set; }
public Trainer trainer { get; set; }
}
public class Trainer
{
public int Id { get; set; }
public string Name { get; set; }
public string Sex { get; set; }
}
測試結果:
綁定Collection(集合)型資料時,
則使用[index].property_name或parameter_name[index].property_name的方式綁定。
測試[index].property_name:
測試parameter_name[index].property_name:
最後講一下筆者很少用到的ModelBinder,
預設資料綁定器會尋找一個特定的對象(Model),
而假設你有需要覆寫資料綁定器時,
Model Binder會幫我們從中攔截傳入的值,
修改並回傳綁定的結果。
筆者寫了一個簡單的範例,
當傳入參數key值為id時,
比較value後修改回傳值。
public class CustomModelBInder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
var values = bindingContext.ValueProvider.GetValue("id");
var value = Int32.Parse(values.FirstValue);
if (value> 10)
bindingContext.Result = ModelBindingResult.Success(value +10);
else
bindingContext.Result = ModelBindingResult.Success(value + 100);
return Task.CompletedTask;
}
}
接著使用路由傳值的方式傳入id,
並在id綁定前套上自訂的ModelBinder。
傳入id = 3,得到結果103:
傳入id = 11,得到結果21:
如果需要更多Model Binder的詳細介紹可參考MSDN。
本篇Model Binding就介紹到這,
如果內容有誤的地方再麻煩各路大神不吝指教。
參考
https://docs.microsoft.com/zh-tw/aspnet/core/mvc/models/model-binding?view=aspnetcore-2.1
https://docs.microsoft.com/en-us/aspnet/core/mvc/advanced/custom-model-binding?view=aspnetcore-2.1