2017-01-24 60 views
4

在.netcore應用程序,我想提供以下(簡化):.NetCore MVC反序列化

// Create a new record, assume it returns an ID=1 
https://site/MyController/Save?FirstName=John&LastName=Doe&Status=Active 

// Update the record without full state 
PUT https://site/MyController/1 
{ 
    'DOB': '1/1/1970', 
    'Status': null 
} 

我想翻譯成第二個電話:

UPDATE MyModel SET DOB = '1/1/1970' AND Status=NULL WHERE Id = 1 

我可以當然在MyController中編寫我的Create方法來解析提交的值的請求(querystring/form/body),並相應地創建我的SQL。

不過,我更願意遵循MVC公約,並充分利用綁定MVC提供開箱即用:

public async Task<MyModel> Save(string id, [FromBody]MyModel instance) 
{ 
    await _MyRepository.UpdateAsync(id, message); 
    return message; 
} 

這裏的問題是,例如看起來就像這樣:

{ 
    'FirstName': null, 
    'LastName': null, 
    'DOB': '1/1/1970', 
    'Status': null 
} 

在哪一點我不能確定哪些字段應該在Db中被清空,哪些應該被單獨留下。

我已經實現了一個包裝類:

  • 反序列化時,將任何「髒」屬性,並且
  • 在系列化,只寫髒性能

這會改變我方法簽名了一下,但不給開發者施加負擔:

public async Task<MyModel> Save(string id, [FromBody]MyWrapper<MyModel> wrapper 
{ 
    await _MyRepository.UpdateAsync(id, wrapper.Instance, wrapper.DirtyProperties); 
    return wrapper.Instance; 
} 

個我的兩個問題是:

  1. 我是不是重新發明一個既定的模式
  2. 我可以攔截MVC反序列化(以優雅的方式)?
+0

不要將持久性模型用作控制器操作的返回值或輸入值。它尖叫着出現故障 – Tseng

回答

1

您可以查看自定義模型綁定。

  • 創建自己的模型綁定:

    /// <summary> 
    /// Defines an interface for model binders. 
    /// </summary> 
    public interface IModelBinder 
    { 
        /// <summary> 
        /// Attempts to bind a model. 
        /// </summary> 
        /// <param name="bindingContext">The <see cref="ModelBindingContext"/>.</param> 
        /// <returns> 
        /// <para> 
        /// A <see cref="Task"/> which will complete when the model binding process completes. 
        /// </para> 
        /// <para> 
        /// If model binding was successful, the <see cref="ModelBindingContext.Result"/> should have 
        /// <see cref="ModelBindingResult.IsModelSet"/> set to <c>true</c>. 
        /// </para> 
        /// <para> 
        /// A model binder that completes successfully should set <see cref="ModelBindingContext.Result"/> to 
        /// a value returned from <see cref="ModelBindingResult.Success"/>. 
        /// </para> 
        /// </returns> 
        Task BindModelAsync(ModelBindingContext bindingContext); 
    } 
    
  • 註冊粘結劑:

    services.AddMvc().Services.Configure<MvcOptions>(options => { 
        options.ModelBinders.Insert(0, new YourCustomModelBinder()); 
    }); 
    

MVC GitHub庫和 「Custom Model Binding」 的文章可能有助於實現IModelBinder接口類:

+0

這確實實現了我所要求的。但是,這也讓我很想嘗試創建中間件,因爲我(迄今爲止)僅利用MVC的增值功能很少。當然,這與我的問題相矛盾! –

0

PUT動詞需要整個實體,但您可以發送帶有delta的HTTP PATCH。幾乎沒有關於如何完成這些的官方文檔,但我確實找到了這個link,它展示瞭如何使用JSONPatchDocument來完成此操作,該操作基本上完成了攔截類的功能。

+0

從服務器端的角度來看,它是優雅的!對於我的使用案例,我試圖讓客戶/消費者變得簡單,讓他們採用相當詳細的PATCH文檔將是一個挑戰。 [鏈接](http://jsonpatch.com/) –