格式化异常消息的位置以及如何将其报告给客户端

时间:2014-04-16 00:31:25

标签: c# ajax asp.net-mvc exception-handling

在我们的ASP.NET MVC 5 DDD应用程序中,我无法确定在何处格式化异常消息以及如何正确地将其报告给客户端。我关心的是关注点分离,DRY和正确的REST实现。在这种情况下,我关注4XX异常(未记录)。

例如,客户端(通过ajax POST)想要移动两个项目' ABC'和' DEF'到文件夹' XYZ'。请求从控制器到服务转到DAL,由于数据库约束,DAL会抛出异常(例如,名称' DEF'已存在于目标文件夹中 - 此异常必须来自DAL,服务层可以&#39 ; t处理并发)。在最后,我想显示html格式的本地化消息,例如"无法将项目 DEF 移动到 XYZ ,名称 DEF 已经存在。" (或作为带有适当数据的JSON)。作为回复,我想返回HTTP状态代码409,因此该消息最终会出现在jQuery的ajax错误函数中。我真的不想返回200 OK并最终获得ajax成功功能,因为它违反了REST原则(这个请求没有成功)。

我的问题(和问题)由两部分组成: 1)格式化消息的位置, 2)如何正确地将此错误消息中继到ajax错误函数。

我考虑(1a)创建MoveItemsException类并设置完全格式化的消息,其中抛出异常(= DAL中) - 但我真的觉得DAL不应该对错误消息的HTML格式负责,而且该message属性应仅包含纯文本。这是相关的问题FormattedException instead of throw new Exception(string.Format(...)) in .NET,但它并没有解决问题"其中"格式化消息。

我还考虑(1b)创建MoveItemsException类并向异常添加适当的属性(例如,DTO或导致此异常的项的ID),将异常消息属性保持为空并在控制器中基于格式设置相应的文本例外的内容。这似乎更好,但它不是干的,我必须在我处理这个异常的每个例子中重复这个。无论如何,本文合理地提倡这种方法:Should you report the message text of exceptions?

另一个选项(1c)是对异常类本身实现格式化,例如exception.FormatMessage(),但与(1b)不同,FormatMessage()不能访问更广泛的上下文。

然后,一旦我格式化了消息,我就想将此错误消息正确地传递给ajax错误函数。我可以用(2a)

var message = ...

return new HttpStatusCodeResult(HttpStatusCode.Conflict, message);

这是建议的,例如在这里,How to report error to $.ajax without throwing exception in MVC controller?,这很简单(因为我将消息作为errorThrown参数),但我不认为HTML格式的消息(或JSON)实际上是状态描述,那么多格式化错误消息的更好位置在响应文本(2b)中,例如:

var message = ...

Response.StatusCode = 409;
Response.Write(message);

return new EmptyResult();

或者在这种情况下,我创建了具有类似功能的自己的ActionResult。

您认为上述情景的最佳方法是什么?

编辑:

目前,我的解决方案是在控制器中捕获特定的4XX异常(带有效负载),将异常映射到viewmodel,将状态代码设置为相应的状态,例如: Response.StatusCode = 409;然后返回该特定异常的return PartialView("_MoveError", moveErrorViewModel);

的部分视图

1 个答案:

答案 0 :(得分:1)

  

我无法确定在何处格式化异常消息以及如何正确地将其报告给客户端。

我的意见

为最终用户提供异常消息不应该发生永远。 Web上下文中的异常意味着代码不正确。应记录此信息供管理员/开发人员处理。我建议阅读Eric Lippert's blog on Vexing exceptions on the types of exceptions and how to handle them

这并不意味着客户应该不知道出现了什么问题。在大多数情况下,它足以告诉最终用户出现问题,公司已经意识到这一点,并正在努力纠正它。在特殊情况下,如果您的公司需要联系客户,您可能希望在页面上包含事件号码(追溯到异常记录的标识符)。

当我需要做大量的ajax时,我通过一个全局函数包装每一次调用You can take a look at it in the question: Return partial view if action is ajax or child action universally 。这样做也意味着如果身份验证票证到期,您仍然可以返回可以告诉客户端执行任何操作的好的ajax(弹出登录模式,重定向到登录页面,等等)。