【问题标题】:ASP.NET MVC Action returns 500 on invalid JSONASP.NET MVC 操作在无效 JSON 上返回 500
【发布时间】:2017-05-19 17:33:33
【问题描述】:

我正在为合作伙伴公司创建一个用于上传报告的 API,它看起来像这样:

[Route("UploadReport"), HttpPost]
public async Task<ActionResult> UploadReport(CancellationToken cancellationToken)
{
    if (Request.ContentType?.ToLower()?.StartsWith("application/json") != true)
    {
        return new MyJsonResult(HttpStatusCode.UnsupportedMediaType, "{\"Error\":\"Content-Type must be \\\"application\\/json\\\"\"}");
    }

    var json = new { reportContentType = "", reportContent = "" };
    Request.InputStream.Seek(0, SeekOrigin.Begin);

    try
    {
        json = JsonConvert.DeserializeAnonymousType(await new StreamReader(Request.InputStream, GetRequestEncoding(Request)).ReadToEndAsync(), json);
    }
    catch
    {
        return new MyJsonResult(HttpStatusCode.BadRequest, "{\"Error\":\"Failed to parse the JSON.\"}");
    }

    // From here, I go on to store the result and return an OK response.
}

关键是我想要求他们发送一个Content-Type: application/json Header,如果我无法解析JSON,我想返回一个400 Bad Request

但如果我发送带有无效 JSON 的POST(注意"text/html" 后面缺少的逗号):

POST https://[debug-server]/UploadReport HTTP/1.1
Host: [debug-server]
Content-Length: 95
Content-Type: application/json

{
  "reportContentType":"text/html"
  "reportContent":"<h2>This is an example report</h2>"
}

我收到这个 500 错误:

(所以你可以搜索这个):

Server Error in '/' Application.

...

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 

Exception Details: System.ArgumentException: Invalid object passed in, ':' or '}' expected. (41): {
  "reportContentType":"text/html"
  "reportContent":"<h2>This is an example report</h2>"
}

Source Error: 


An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.  

Stack Trace: 



[ArgumentException: Invalid object passed in, ':' or '}' expected. (41): {
  "reportContentType":"text/html"
  "reportContent":"<h2>This is an example report</h2>"
}]
System.Web.Script.Serialization.JavaScriptObjectDeserializer.DeserializeDictionary(Int32 depth) +1251
System.Web.Script.Serialization.JavaScriptObjectDeserializer.DeserializeInternal(Int32 depth) +123
System.Web.Script.Serialization.JavaScriptObjectDeserializer.BasicDeserialize(String input, Int32 depthLimit, JavaScriptSerializer serializer) +79
System.Web.Script.Serialization.JavaScriptSerializer.Deserialize(JavaScriptSerializer serializer, String input, Type type, Int32 depthLimit) +37
System.Web.Mvc.JsonValueProviderFactory.GetDeserializedObject(ControllerContext controllerContext) +213
System.Web.Mvc.JsonValueProviderFactory.GetValueProvider(ControllerContext controllerContext) +16
System.Web.Mvc.ValueProviderFactoryCollection.GetValueProvider(ControllerContext controllerContext) +69
System.Web.Mvc.ControllerBase.get_ValueProvider() +30
System.Web.Mvc.ControllerActionInvoker.GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor) +62
System.Web.Mvc.ControllerActionInvoker.GetParameterValues(ControllerContext controllerContext, ActionDescriptor actionDescriptor) +105
System.Web.Mvc.Async.<>c__DisplayClass21.<BeginInvokeAction>b__19(AsyncCallback asyncCallback, Object asyncState) +743
System.Web.Mvc.Async.WrappedAsyncResult`1.CallBeginDelegate(AsyncCallback callback, Object callbackState) +14
System.Web.Mvc.Async.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +128
System.Web.Mvc.Async.AsyncControllerActionInvoker.BeginInvokeAction(ControllerContext controllerContext, String actionName, AsyncCallback callback, Object state) +343
System.Web.Mvc.Controller.<BeginExecuteCore>b__1c(AsyncCallback asyncCallback, Object asyncState, ExecuteCoreState innerState) +25
System.Web.Mvc.Async.WrappedAsyncVoid`1.CallBeginDelegate(AsyncCallback callback, Object callbackState) +30
System.Web.Mvc.Async.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +128
System.Web.Mvc.Controller.BeginExecuteCore(AsyncCallback callback, Object state) +465
System.Web.Mvc.Controller.<BeginExecute>b__14(AsyncCallback asyncCallback, Object callbackState, Controller controller) +18
System.Web.Mvc.Async.WrappedAsyncVoid`1.CallBeginDelegate(AsyncCallback callback, Object callbackState) +20
System.Web.Mvc.Async.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +128
System.Web.Mvc.Controller.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state) +374
System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state) +16
System.Web.Mvc.MvcHandler.<BeginProcessRequest>b__4(AsyncCallback asyncCallback, Object asyncState, ProcessRequestState innerState) +52
System.Web.Mvc.Async.WrappedAsyncVoid`1.CallBeginDelegate(AsyncCallback callback, Object callbackState) +30
System.Web.Mvc.Async.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +128
System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state) +384
System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state) +48
System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData) +16
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +103
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155



--------------------------------------------------------------------------------
Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.6.1087.0

如果我不包含 Content-Type: application/json 标头并删除要求它的子句,它可以正常工作。所以有些东西会看到带有 Content-Type: application/json 的请求并尝试解析它,这会在无效 JSON 上引发异常。

所以我的两个问题是:

是什么原因造成的?

如何预防?

【问题讨论】:

  • 您是否在 json 字符串中的第一个对象后漏掉了一个逗号? { "reportContentType":"text/html", "reportContent":"

    这是一个示例报告

    " }
  • 是和不是。我的观点是,如果存在无效的 JSON(例如,有人省略了逗号),我想要 400 错误,而不是 500 错误。
  • 在操作参数中使用string 参数而不是CancellationToken 会有所帮助。在函数中解析它。在这里,它无法解析参数。所以,它直接把错误扔在脸上!
  • 尝试添加一个新的字符串变量以查看Request.ContentType... 返回的内容并禁用if 处理
  • @PrashanthBenny 你明白了。虽然接受CancellationToken 类型的参数只是传入Request.TimedOutToken,而不是解析它的请求。但是,通过指定任何参数,MVC 会尝试解析请求,并且(如果无效)抛出 500 异常。

标签: c# asp.net json asp.net-mvc


【解决方案1】:

查找请求验证。把它关掉。一定有帮助。

【讨论】:

  • 我尝试禁用请求验证,但无法使用它。
  • 您还可以处理全局 asax 文件中的错误。检查它的类型并返回所需的答案。首先清除当前http上下文的响应。然后更改响应的内容类型。并将json字符串写入响应。
  • 我原本也想过这个,但似乎付出的努力远远超过了它的价值。
【解决方案2】:

所以这里的关键是删除签名中的所有参数。因此,我可以使用Request.TimedOutToken 代替CancellationToken 类型的参数,而不是使用。所以现在我的签名是这样的:

[Route("UploadReport"), HttpPost]
public async Task<ActionResult> UploadReport()

在方法中没有任何参数的情况下,MVC 的请求处理程序退出尝试解析 JSON 以提供参数值,我可以自己解析请求中的 JSON。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-08
    • 2011-08-16
    • 2013-09-11
    • 2021-07-21
    • 1970-01-01
    • 1970-01-01
    • 2011-08-15
    • 2010-09-18
    相关资源
    最近更新 更多