如何在ASP.NET Core中将JSON请求正文验证为有效JSON [英] How to validate json request body as valid json in asp.net core

查看:370
本文介绍了如何在ASP.NET Core中将JSON请求正文验证为有效JSON的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

In asp.net core 2.1, when a controller action is set as:

    [HttpPost]
    public JsonResult GetAnswer(SampleModel question)
    {               
        return Json(question.Answer);
    }

其中SampleModel定义为:

where the SampleModel is defined as:

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

    public string Answer { get; set; }
}

这仍然被视为有效请求:

this is still considered as valid request:

{
  "question": "some question",
  "question": "some question 2",
  "answer": "some answer"
}

在控制器中,我可以看到第二个问题是model的值和model是否有效.

In the controller I can see that second question is the value of model and model is valid.

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

Question is how to validate just body of request as valid JSON even before model binding?

推荐答案

根据 Timothy Shields的回答,很难说如果我们有重复的属性键,那将是一个无效的json.

According to Timothy Shields's answer, it's hard to say that would be an invalid json if we have duplicated property keys.

当使用ASP.NET Core 2.1时,它根本不会抛出.

And when using ASP.NET Core 2.1, it won't throw at all.

12.0.1开始, Newtonsoft.Json 具有 DuplicatePropertyNameHandling设置 .如果设置DuplicatePropertyNameHandling.Error并传递重复的属性,则会抛出该错误.因此,最简单的方法是创建自定义模型联编程序.我们可以反序列化JSON并在抛出时更改ModelState.

As of 12.0.1, the Newtonsoft.Json has a DuplicatePropertyNameHandling settings. It will throw if we set DuplicatePropertyNameHandling.Error and pass a duplicated property. So the easiest way I can come up is to create a custom model binder. We could deserialize the JSON and change the ModelState if it throws .

首先安装最新的Newtonsoft.Json:

  <ItemGroup>
    <PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
  </ItemGroup>

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

and then register a JsonLoadSettings option as a singleton service for later reuse :

services.AddSingleton<JsonLoadSettings>(sp =>{
    return new JsonLoadSettings { 
        DuplicatePropertyNameHandling =  DuplicatePropertyNameHandling.Error,
    };
});

现在,我们可以创建一个自定义模型联编程序来处理重复的属性:

Now we can create a custom model binder to deal with duplicated properties :

public class XJsonModelBinder: IModelBinder
{
    private JsonLoadSettings _loadSettings;
    public XJsonModelBinder(JsonLoadSettings loadSettings)
    {
        this._loadSettings = loadSettings;
    }

    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (bindingContext == null) { throw new ArgumentNullException(nameof(bindingContext)); }
        var modelName = bindingContext.BinderModelName?? "XJson";
        var modelType = bindingContext.ModelType;

        // create a JsonTextReader
        var req = bindingContext.HttpContext.Request;
        var raw= req.Body;
        if(raw == null){ 
            bindingContext.ModelState.AddModelError(modelName,"invalid request body stream");
            return Task.CompletedTask;
        }
        JsonTextReader reader = new JsonTextReader(new StreamReader(raw));

        // binding 
        try{
            var json= (JObject) JToken.Load(reader,this._loadSettings);
            var o  = json.ToObject(modelType);
            bindingContext.Result = ModelBindingResult.Success(o);
        }catch(Exception e){
            bindingContext.ModelState.AddModelError(modelName,e.ToString()); // you might want to custom the error info
            bindingContext.Result = ModelBindingResult.Failed();
        }
        return Task.CompletedTask;
    }
}

要多次读取Request.Body,我们还可以创建一个虚拟Filter:

To enable read the Request.Body multiple times, we could also create a dummy Filter:

public class EnableRewindResourceFilterAttribute : Attribute, IResourceFilter
{
    public void OnResourceExecuting(ResourceExecutingContext context)
    {
        context.HttpContext.Request.EnableRewind();
    }
    public void OnResourceExecuted(ResourceExecutedContext context) { }
}

最后,用[ModelBinder(typeof(XJsonModelBinder))]EnableRewindResourceFilter装饰操作方法:

Lastly, decorate the action method with [ModelBinder(typeof(XJsonModelBinder))] and EnableRewindResourceFilter:

    [HttpPost]
    [EnableRewindResourceFilter]
    public JsonResult GetAnswer([ModelBinder(typeof(XJsonModelBinder))]SampleModel question)
    {               
        if(ModelState.IsValid){
            return Json(question.Answer);
        }
        else{
            // ... deal with invalid state
        }
    }

演示:

这篇关于如何在ASP.NET Core中将JSON请求正文验证为有效JSON的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆