asp.net - 在 MVC Controller 中将 JSON 绑定(bind)到 JToken

标签 asp.net asp.net-mvc asp.net-web-api asp.net-mvc-5 json.net

有没有办法让 MVC Controller 将传入的动态 JSON 绑定(bind)到 JToken 对象?

如果我使用 API Controller ,我可以这样做:

public class TestController : ApiController
{
    public void Post(JToken json)
    {
    }
}

并且发布的 json 被转换为 JToken 对象。 但是,如果我使用 MVC Controller ,则会导致服务器错误。

public class TestController : Controller
{
    [HttpPost]
    public ActionResult TestAction(JToken json)
    {
        return new HttpStatusCodeResult(HttpStatusCode.OK);
    }
}

我意识到还有其他方法来获取传入数据,但我更愿意在 MVC Controller 中将其作为 JToken 接收。

我尝试使用自定义ValueProviderFactory from here但我仍然收到 AJAX 调用返回的服务器错误:

$.ajax({
    url: '/Test/TestAction',    //or /api/Test
    type: 'POST',
    contentType: 'application/json',
    data: JSON.stringify({foo:"bar",wibble:"wobble"})
}).done(function (res) {
    alert('ok');
}).fail(function (xhr, status, error) {
    alert('error')
});

更新:

注意 - 如上所述,我已将默认的 JsonValueProviderFactory 替换为基于 Json.NET 的工厂。

经过进一步调查,问题似乎出现在 DefaultModelBinder.CreateModel 方法中。当 DefaultModelBinder 尝试创建 JToken 实例时,它会失败,因为 JToken 是一个抽象类。即使我将 TestAction 参数更改为 JObject,它仍然会失败,大概是因为对象层次结构中还有 JToken 属性。

最佳答案

在这种特殊情况下,将传入 JSON 的默认序列化器更改为 writing a custom ValueProviderFactory不工作。这似乎是因为 JToken 是一个抽象类,默认的 ModelBinder 无法创建涉及抽象类的模型实例。

解决方案是 create a custom ModelBinder对于操作:

public class JsonNetModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        if (!IsJSONRequest(controllerContext))
        {
            return base.BindModel(controllerContext, bindingContext);
        }

        var request = controllerContext.HttpContext.Request;
        request.InputStream.Seek(0, SeekOrigin.Begin);
        var jsonStringData = new StreamReader(request.InputStream).ReadToEnd();

        return JsonConvert.DeserializeObject(jsonStringData, bindingContext.ModelType);
    }
    private static bool IsJSONRequest(ControllerContext controllerContext)
    {
        var contentType = controllerContext.HttpContext.Request.ContentType;
        return contentType.Contains("application/json");
    }
}

并在 Action 上使用自定义 ModelBinder,如下所示:

public class TestController : Controller
{
    [HttpPost]
    public ActionResult TestAction([ModelBinder(typeof(JsonNetModelBinder))] JToken json)
    {
        return new HttpStatusCodeResult(HttpStatusCode.OK);
    }
}

关于asp.net - 在 MVC Controller 中将 JSON 绑定(bind)到 JToken,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36890706/

相关文章:

c# - 在不使用 App_Code 的情况下从 cshtml 文件创建一个简单类并调用其方法

html - 如何防止在 Razor(独立)中转义 html?

c# - 如何从 List MVC 制作表格?

c# - 如何在 ASP.NET WebApi 的每个请求上对 JWT token 应用自定义验证?

ASP.NET Web API 2 - 用户注册电子邮件确认失败

javascript - 如何将复杂的 JavaScript 对象发送到 ASP.net WebMethod?

c# - "Data source name not found and no default driver specified"错误

c# - 如何在 response.redirect 之前执行启动脚本?

javascript - MVC 验证后执行 Ajax

c# - 如何在 Web API 中传递可选参数