c# – .NetCore MVC反序列化

在.netcore应用程序中,我想提供以下(简化):

// 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中哪些字段应为NULL,哪些字段应保持不变.

我已经实现了一个包装类:

>在反序列化时,设置任何“脏”属性,并且
>序列化时,只写脏属性

这会稍微改变我的方法签名,但不会给开发人员带来负担:

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

我的两个问题是:

>我是否正在重新发明既定模式?
>我可以拦截MVC反序列化(以优雅的方式)吗?

最佳答案 您可以查看自定义模型绑定.

>创建自己的模型绑定器:实现IModelBinder接口的类:

/// <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 repo和“Custom Model Binding”文章可能有所帮助:

点赞