0

In our ASP.NET MVC 5 DDD application, I can't decide where to format exception message and how to correctly report it to client. I care about separation of concerns, DRY and correct REST implementation. In this case, I'm concerned about 4XX exceptions (not logged).

For example, client (via ajax POST) wants to move two items 'ABC' and 'DEF' to folder 'XYZ'. The request goes from controller through service to DAL and exception is thrown in DAL due to DB constrains (e.g., name 'DEF' already exists in target folder - and this exception must originate in DAL, service layer can't deal with concurrency). At the very end, I want to display html-formatted, localized message, such as "Can't move item DEF to XYZ, name DEF already exists." (or as JSON with appropriate data). As a reply, I'd like to return HTTP status code 409, so this message ends up in jQuery's ajax error function. I really don't want to return 200 OK and end up in ajax success function, since it goes against REST principles (this request didn't succeed).

My problem (and question) consists of two parts: 1) where to format the message, 2) how to correctly relay this error message to ajax error function.

I considered (1a) to create MoveItemsException class and set fully formatted message where the exception was thrown (= in DAL) - but I really feel that DAL shouldn't be responsible for HTML formatting of error message, and also that message property should contain only plain text only. This is related question, FormattedException instead of throw new Exception(string.Format(...)) in .NET, but it doesn't solve the question "where" to format the message.

I also considered (1b) to create MoveItemsException class and add appropriate properties to the exception (e.g., DTO or ID of item(s) that caused this exception), keep exception message property empty and format appropriate text in controller based on exception's content. This seems better, but it's not DRY, I'd have to repeat this in each instance where I'd be dealing with this exception. Anyway, this article reasonably advocates this approach: Should you report the message text of exceptions?

And another option (1c) is to implement formatting to the exception class itself, something like exception.FormatMessage(), but unlike in (1b), FormatMessage() wouldn't have access to broader context.

Then, once I have formatted message, I'd like to correctly deliver this error message to ajax error function. I can use (2a)

var message = ...

return new HttpStatusCodeResult(HttpStatusCode.Conflict, message);

This was suggested e.g. here, How to report error to $.ajax without throwing exception in MVC controller?, it would be simple (since I'd get message as errorThrown parameter), but I don't think that HTML-formatted message (or JSON) is actually status description, that much better place for formatted error message is in response text (2b), e.g.:

var message = ...

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

return new EmptyResult();

or in this case, I'd create my own ActionResult with similar functionality.

What do you think is the best approach for forementioned scenario?

EDIT:

For now, my solution is to catch specific 4XX exception (with payload) in controller, map the exception to viewmodel, set status code to corresponding status, e.g. Response.StatusCode = 409; and then return partial view for that specific exception return PartialView("_MoveError", moveErrorViewModel);

Community
  • 1
  • 1
Robert Goldwein
  • 5,805
  • 6
  • 33
  • 38
  • There is nothing wrong with sending back a StatusCode, but if you aren't going to program for it on the client side, there isn't much point. This is especially true if another programmer comes along, looks at the status code and tries to figure out why it's being set it it's never used. – Erik Philips Apr 16 '14 at 15:38
  • The reason for specific status code is that we stick to RFC, so we always try to choose the most appropriate status code (even e.g. 200 vs 204); on the client side, it (usually) suffices to check whether error is 4XX (user can correct it, e.g. a tool tip is displayed with message) or 5XX (user can't do anything about it, so "we're sorry" dialog pops up). – Robert Goldwein Apr 16 '14 at 16:09

1 Answers1

1

I can't decide where to format exception message and how to correctly report it to client.

My Opinion:

Giving the end-user an exception message shouldn't happen ever. An exception in a web context means that code is incorrect. This should be logged for an administrator/developer to handle. I would suggest reading Eric Lippert's blog on Vexing exceptions on the types of exceptions and how to handle them.

This doesn't mean that the client should be not aware that something went wrong however. In most cases, it's enough to tell the end user that something went wrong, the company is aware of it and working to correct it. In exceptional cases, you may want to include an incident number (tracked back to the exception logged identifier) on the page if your company needs to contact the client.

When I need to do a ton of ajax, I wrap every single call through a single global function. You can take a look at it in the question: Return partial view if action is ajax or child action universally . Doing this also means that if the authentication ticket expires, you can STILL return nice ajax that can tell your client side to do whatever you want (popup a login modal, redirect to login page, whatever).

Community
  • 1
  • 1
Erik Philips
  • 53,428
  • 11
  • 128
  • 150
  • Thank you for these links. You're right, Message property from any exception shouldn't reach end-user. Nevertheless, I don't see exceptions as evil as goto, I think that e.g. constrain violations should be handled as exceptions, I added my current solution to the original question. – Robert Goldwein Apr 16 '14 at 15:15