【问题标题】:MVC Web API POST Entity (500 internal server error)MVC Web API POST 实体(500 内部服务器错误)
【发布时间】:2013-10-12 14:42:51
【问题描述】:

我一直致力于为我公司的网站构建 API。我的所有 GET 操作都可以正常工作并返回我想要的 JSON。

我在使用 POST 创建新记录时遇到了问题。我正在将 JSON 发送到我的控制器。如果我的控制器正在接受字符串或对象参数,这可以正常工作,但在需要模型时不起作用。

在我的 api 控制器中,我有这个方法:

[HttpPost]
public void POSTEstimate(Estimate estimate)
{
    //never makes it to the first line when expecting a Model (Estimate)
}

从我一直在阅读的内容来看,Web API 应该能够反序列化自动发布的 JSON(并将其放入我的模型中),但我总是收到 500 内部服务器错误。当我告诉它接受字符串时,该方法工作正常。

这里有什么明显的我做错了吗?

编辑:这是我用来调用 API 方法的测试页面的堆栈跟踪:

[WebException: The remote server returned an error: (500) Internal Server Error.]
   System.Net.HttpWebRequest.GetResponse() +6120419
   PDR.Controllers.AdminController.test() in c:\PDR\PDR\PDR\Controllers\AdminController.cs:714
   lambda_method(Closure , ControllerBase , Object[] ) +96
   System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters) +17
   System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) +205
   System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +27
   System.Web.Mvc.Async.<>c__DisplayClass42.<BeginInvokeSynchronousActionMethod>b__41() +28
   System.Web.Mvc.Async.<>c__DisplayClass8`1.<BeginSynchronous>b__7(IAsyncResult _) +12
   System.Web.Mvc.Async.WrappedAsyncResult`1.End() +57
   System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult) +50
   System.Web.Mvc.Async.<>c__DisplayClass39.<BeginInvokeActionMethodWithFilters>b__33() +58
   System.Web.Mvc.Async.<>c__DisplayClass4f.<InvokeActionMethodFilterAsynchronously>b__49() +237
   System.Web.Mvc.Async.<>c__DisplayClass37.<BeginInvokeActionMethodWithFilters>b__36(IAsyncResult asyncResult) +12
   System.Web.Mvc.Async.WrappedAsyncResult`1.End() +57
   System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethodWithFilters(IAsyncResult asyncResult) +50
   System.Web.Mvc.Async.<>c__DisplayClass2a.<BeginInvokeAction>b__20() +24
   System.Web.Mvc.Async.<>c__DisplayClass25.<BeginInvokeAction>b__22(IAsyncResult asyncResult) +126
   System.Web.Mvc.Async.WrappedAsyncResult`1.End() +57
   System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(IAsyncResult asyncResult) +45
   System.Web.Mvc.<>c__DisplayClass1d.<BeginExecuteCore>b__18(IAsyncResult asyncResult) +14
   System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +25
   System.Web.Mvc.Async.WrappedAsyncResult`1.End() +62
   System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +61
   System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +25
   System.Web.Mvc.Async.WrappedAsyncResult`1.End() +62
   System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult) +49
   System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.EndExecute(IAsyncResult asyncResult) +10
   System.Web.Mvc.<>c__DisplayClass8.<BeginProcessRequest>b__3(IAsyncResult asyncResult) +28
   System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +25
   System.Web.Mvc.Async.WrappedAsyncResult`1.End() +62
   System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +49
   System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +9
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +9042109
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +184

【问题讨论】:

  • 调试应用程序时会发生什么?调试会告诉你为什么会发生 500 Internal Server Error。
  • 它在调试的任何地方都不会中断。它直接进入错误页面。
  • 服务器可能会发回一些关于 500 的信息。这说明了什么?
  • 那么错误一定是在模型绑定期间发生的......你确定你的模型类中没有任何错误吗(即带有一些可能抛出的代码或可能的属性的默认ctor扔等)?另外,我不确定您是否需要在 POST 上对 json 进行字符串化,您可以尝试将 $.ajax 调用的 data 设置为“真实”json,即没有转义或引用,只是看看这是否有什么不同?
  • 不这么认为 - 你应该以 ModelState.IsValid==false 而不是 Http 500 结束。我更倾向于认为默认模型绑定器正在受到来自尝试的异常的影响构建模型的实例,或绑定特定的属性值。如果您真的遇到困难,请尝试向您的 API (asp.net/web-api/overview/web-api-routing-and-actions/…) 添加自定义异常过滤器,这至少可以让您有机会看到“真正的”异常。

标签: c# asp.net-mvc asp.net-web-api


【解决方案1】:

Web API 与其他 REST 框架一样,鼓励并支持使用可序列化为 JSON DTO 的 POCO。序列化似乎失败了。

如果没有客户端代码,它应该创建一个格式正确的 JSON 正文以进行 POST,正确设置发布为 application/json 的内容类型,很难判断客户端代码的哪一部分不正确。

作为内部服务器错误报告的错误没有帮助。甚至没有查看 StackTrace 就无法访问您的代码这一事实清楚地表明问题出现在框架代码中。框架需要一个格式正确的 DTO,因此比较被 POST 的 DTO 与 DTO 的定义 OR 构造并序列化 DTO 的实例并比较实际的字符串。

【讨论】:

  • 我正在创建一个实体,然后使用内置的序列化程序 JavaScriptSerializer().Serialize(Entity) 创建 JSON,因此 JSON 应该是格式正确的 JSON。内容类型也在设置中。这种完全相同的方法适用于一些较小的模型。我最终在 POST 方法中接受了一个对象,对其进行 ToStringing,然后反序列化该字符串,该字符串在尝试接受我的实体时不起作用的相同输入下工作正常。我不太确定,因为我做了很多方法都可以很好地绑定到模型。
  • 基于此信息(仍然不清楚为什么合同无效(这将需要涉及的特定类),我会推动拆分关注点。数据传输对象不需要完全与实体对象相同的对象。并且实体中可能存在使其不太适合在服务边界处序列化的元素。而不是通过序列化映射(转到字符串并再次返回到不同的类型),映射通过代码。Automapper 是一个有助于理解和实现这一点的项目。
【解决方案2】:

我今天遇到了类似的事情,我的问题是我的控制器中有多种可能的操作可供 Web Api 使用,但它不知道该使用哪一个。因此,在我的情况下,我使用最长形式的客户端和服务器端进行操作,而不是依赖默认的 api 路由:

路由器:

config.Routes.MapHttpRoute(
            name: "ApiWithAction",
            routeTemplate: "metadataApi/{controller}/{action}/{id}",
            defaults: new {id = RouteParameter.Optional});

Ajax 调用:

[...]
var options = {
    url: basePath + 'metadataapi/employee/FetchPage',
    type: 'POST',
    data: filter,
    dataType: 'json'
};

return $.ajax(options);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-12-11
    • 2017-10-14
    • 2016-10-28
    • 2018-10-10
    • 1970-01-01
    • 1970-01-01
    • 2012-07-29
    相关资源
    最近更新 更多