我试图创建的ObjectId类型在我的模型非常简单的模型绑定,但似乎无法使它工作至今。
这里的模型绑定:
public class ObjectIdModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
var result = bindingContext.ValueProvider.GetValue(bindingContext.FieldName);
return Task.FromResult(new ObjectId(result.FirstValue));
}
}
这是我编写的ModelBinderProvider:
public class ObjectIdModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context == null) throw new ArgumentNullException(nameof(context));
if (context.Metadata.ModelType == typeof(ObjectId))
{
return new BinderTypeModelBinder(typeof(ObjectIdModelBinder));
}
return null;
}
}
下面是我想要的身体参数绑定类:
public class Player
{
[BsonId]
[ModelBinder(BinderType = typeof(ObjectIdModelBinder))]
public ObjectId Id { get; set; }
public Guid PlatformId { get; set; }
public string Name { get; set; }
public int Score { get; set; }
public int Level { get; set; }
}
这是操作方法:
[HttpPost("join")]
public async Task<SomeThing> Join(Player player)
{
return await _someService.DoSomethingOnthePlayer(player);
}
对于这个代码的工作,我的意思是模型绑定跑,我继承了控制器的控制和去除从播放器参数的[FromBody]
属性。
当我运行这个,我可以进入模型绑定的BindModelAsync方法,但是我似乎无法摆脱后的数据Id参数值。我可以看到bindingContext.FieldName是正确的;它被设置为Id,然而result.FirstValue为空。
我已经从Asp.Net MVC走了一会儿,似乎很多事情都已经变了,变得更加混乱:-)
编辑根据意见,我想我应该提供更多的上下文。
如果我的球员动作参数之前把[FromBody],播放器设置为null。如果我删除[FromBody],播放器设置为默认值,而不是我博文的值。后机身如下图所示,它只是一个简单的JSON:
{
"Id": "507f1f77bcf86cd799439011"
"PlatformId": "9c8aae0f-6aad-45df-a5cf-4ca8f729b70f"
}
如果我删除[FromBody],播放器设置为默认值,而不是我博文的值。
从身体中读数据请选择(除非你使用[ApiController]
)。当您从[FromBody]
参数中删除Player
,该模型结合流程将填充使用途径,查询字符串和表单值Player
的性能,在默认情况下。在你的榜样,也有在这些位置没有这样的特性,所以没有Player
的属性被置。
如果我的球员动作参数之前把[FromBody],播放器设置为null。
与[FromBody]
属性的存在,该模型结合过程尝试根据设置有该请求的Content-Type
从主体读取。如果这是application/json
,身体会被解析为JSON,并映射到你的Player
的属性。在您的例子,JSON的解析过程失败,因为它不知道如何从一个string
转换为ObjectId
。发生这种情况时,你的控制器内ModelState.IsValid
将返回false
和你Player
参数会null
。
对于这个码工作,我的意思是用于模型粘合剂来运行,我继承来自控制器控制器并除去从所述播放器参数中的[FromBody]属性。
当您删除[FromBody]
,该[ModelBinder(...)]
属性你设置你的Id
财产受到尊重,并让你的代码运行。然而,随着[FromBody
]的存在,这个属性有效地将被忽略。有很多事情背后的幕后这里,但基本上它归结为一个事实,即你已经选择加入模型绑定从身体JSON而这也正是模型结合停止在这种情况下。
我上面说它的JSON的解析过程,真实未能这里由于不理解如何处理ObjectId
提及。作为该JSON-解析由Newtonsoft.Json(又名JSON.NET)处理,一种可能的解决方案是创建一个定制JsonConverter
。这是很好覆盖这里对堆栈溢出,所以我不会去到它是如何工作的细节。下面是一个完整的例子(错误处理略去了和懒惰):
public class ObjectIdJsonConverter : JsonConverter
{
public override bool CanConvert(Type objectType) =>
objectType == typeof(ObjectId);
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) =>
ObjectId.Parse(reader.Value as string);
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) =>
writer.WriteValue(((ObjectId)value).ToString());
}
为了充分利用这一点,只需用[ModelBinder(...)]
属性,这样的替换现有[JsonConverter(...)]
属性:
[BsonId]
[JsonConverter(typeof(ObjectIdJsonConverter))]
public ObjectId Id { get; set; }
或者,您可以ObjectIdJsonConverter
全球范围内,使之适用于所有ObjectId
性能,使用这样的事情在Startup.ConfigureServices
注册:
services.AddMvc()
.AddJsonOptions(options =>
options.SerializerSettings.Converters.Add(new ObjectIdJsonConverter());
);
你错了,在ModelBinder的。正确的代码:
public class ObjectIdModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
var result = bindingContext.ValueProvider.GetValue(bindingContext.FieldName);
bindingContext.Result = ModelBindingResult.Success(new ObjectId(result.FirstValue));
return Task.CompletedTask;
}
}