C# 如何在asp.net核心中将json请求正文验证为有效的json

C# 如何在asp.net核心中将json请求正文验证为有效的json,c#,asp.net-core,asp.net-core-2.1,model-validation,C#,Asp.net Core,Asp.net Core 2.1,Model Validation,在asp.net core 2.1中,当控制器操作设置为: [HttpPost] public JsonResult GetAnswer(SampleModel question) { return Json(question.Answer); } 其中,样本模型定义为: public class SampleModel { [Required] public string Question { ge

在asp.net core 2.1中,当控制器操作设置为:

    [HttpPost]
    public JsonResult GetAnswer(SampleModel question)
    {               
        return Json(question.Answer);
    }
其中,样本模型定义为:

public class SampleModel
{
    [Required]
    public string Question { get; set; }

    public string Answer { get; set; }
}
这仍然被视为有效的请求:

{
  "question": "some question",
  "question": "some question 2",
  "answer": "some answer"
}
在控制器中,我可以看到第二个问题是模型的值,并且模型是有效的

问题是,即使在模型绑定之前,如何将请求主体验证为有效的JSON?

根据,如果我们有重复的属性键,很难说这是无效的JSON

当使用ASP.NET Core 2.1时,它不会抛出任何错误

12.0.1
起,具有一个
。如果我们设置
DuplicatePropertyNameHandling.Error
并传递一个重复的属性,它将抛出。所以我能想到的最简单的方法就是创建一个自定义模型绑定器。我们可以对JSON进行反序列化,并在抛出时更改ModelState

首先,安装最新的
Newtonsoft.Json


然后将
JsonLoadSettings
选项注册为单例服务,以便以后重用:

services.AddSingleton(sp=>{
返回新的JsonLoadSettings{
DuplicatePropertyNameHandling=DuplicatePropertyNameHandling.Error,
};
});
现在,我们可以创建自定义模型绑定器来处理重复的特性:

公共类XJsonModelBinder:IModelBinder
{
私有JsonLoadSettings\u loadSettings;
公共XJsonModelBinder(JsonLoadSettings加载设置)
{
这是。_loadSettings=loadSettings;
}
公共任务BindModelAsync(ModelBindingContext bindingContext)
{
如果(bindingContext==null){抛出新的ArgumentNullException(nameof(bindingContext));}
var modelName=bindingContext.BinderModelName??“XJson”;
var modelType=bindingContext.modelType;
//创建一个JsonTextReader
var req=bindingContext.HttpContext.Request;
var raw=请求主体;
如果(原始==null){
bindingContext.ModelState.AddModelError(modelName,“无效的请求正文流”);
返回Task.CompletedTask;
}
JsonTextReader reader=newjsontextreader(newstreamreader(raw));
//装订
试一试{
var json=(JObject)JToken.Load(reader,this.\u loadSettings);
var o=json.ToObject(modelType);
bindingContext.Result=ModelBindingResult.Success(o);
}捕获(例外e){
bindingContext.ModelState.AddModelError(modelName,e.ToString());//您可能需要自定义错误信息
bindingContext.Result=ModelBindingResult.Failed();
}
返回Task.CompletedTask;
}
}
要启用多次读取
请求.Body
,我们还可以创建一个虚拟
过滤器

public class EnableRewindResourceFilterAttribute : Attribute, IResourceFilter
{
    public void OnResourceExecuting(ResourceExecutingContext context)
    {
        context.HttpContext.Request.EnableRewind();
    }
    public void OnResourceExecuted(ResourceExecutedContext context) { }
}
最后,使用
[ModelBinder(typeof(XJsonModelBinder))]
启用RewinderSourceFilter
装饰操作方法:

public class EnableRewindResourceFilterAttribute : Attribute, IResourceFilter
{
    public void OnResourceExecuting(ResourceExecutingContext context)
    {
        context.HttpContext.Request.EnableRewind();
    }
    public void OnResourceExecuted(ResourceExecutedContext context) { }
}
[HttpPost]
[启用重新布线资源过滤器]
公共JsonResult GetAnswer([ModelBinder(typeof(XJsonModelBinder))]SampleModel问题)
{               
if(ModelState.IsValid){
返回Json(问题.答案);
}
否则{
//…处理无效状态
}
}
演示:


尝试捕获并测试您期望的对象,如果不是,则它不是有效的模型如果您想要第一个数据,则请求[“SampleModel.answer”]或您如何调用它,但您也可以为此创建一个特殊的处理程序,但为了测试您请求[“NameOfyInput”]@JohnnBlade如果反序列化成功,如何测试对象是否与我预期的不一样?谢谢你的回答,不知怎的,我有点吃惊,因为同一级别上的重复键在技术上并不构成无效的json,但我的背景大多是强类型语言,所以这可能是我现在思考的一部分。