Middleware: [Docs] Purpose of ProblemDetails library
I’ve seen various mentions of Hellang.Middleware.ProblemDetails and I’m trying to figure out what it does. Regrettably, the readme and sample code don’t explain.
I suspect it catches unhandled exceptions and converts them to ProblemDetails. However that’s something that can be done in an exception middleware/filter/handler/whatever. Since this library seems really “fancy”, I’m sure it does more than just that! 😃
Can someone please tell me what this library actually “does”? Thanks!
(BTW: I’m not trolling, I really want to know. The Microsoft docs site even recommends this library.)
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Comments: 16 (12 by maintainers)
Yeah, I think that matches what I would expect 👍
Regarding the 422 status code; it’s an opinion of mine that syntactically correct, but semantically invalid requests should return back a different status code than 400 Bad Request:
From RFC 7231:
It’s increasingly common to use 422 Unprocessable Entity for this 😃
From RFC 4918:
Some people don’t like it (often because it’s part of the WebDAV RFC and not an “official” HTTP RFC (but this will soon change, with the inclusion of 422 in HTTPbis’ upcoming HTTP Semantics RFC, which obsoletes RFC 7231), so I’ve added an option to change it:
https://github.com/khellang/Middleware/blob/eb7f59cb5aaff0727466622af6230db12703a32f/src/ProblemDetails/ProblemDetailsOptions.cs#L133-L136
Some more info about
AddProblemDetailsConventions, based on khellang’s comments here:ProblemDetailsFactoryto use the middleware’s configuration instead. This will give you more consistent errors, no matter where they are produced. I.e. from MVC’s invalid state filter etc.ProblemDetailsinstances from controllers a bit more consistent, by calling the middleware hooksYes, you’re more or less correct. It’s basically just an error handling middleware. The advantage to using middleware as opposed to an MVC filter (or something similar,) is that it’ll handle error states that can occur outside of MVC, in other middleware.
Both error responses (based on status code, as long as no body has been produced yet) and exceptions are handled by the middleware (using the default configuration, almost anything can be configured) and transformed to consistent problem responses based on RFC7807. You can choose centrally how exceptions and status codes are mapped to problem responses.
The middleware is, unlike Microsofts error handling/developer exception middleware, meant to be used in the pipeline regardless of environment. There’s a setting that determines whether exception details should be added to the response. The default is to only include them in development. Like other error handling middleware, it’s best to include it as early as possible in the pipeline, to make sure it wraps as much of it as possible, so no error “gets out” 😆
AddProblemDetailsConventionsis specific to MVC. It basically just disables MVC’s built-in “client error mapping” so the middleware will handle them instead. It also does a bit of magic to use the middleware configuration when producing error responses through MVCObjectResult. See this filter. API controllers are MVC as well, they just have some conventions enabled, like implicit model binding and automatic validation error responses. You might want to call the method if you want to have 100% consistent error responses from your API (produced by the middleware).Let me know if something still isn’t clear 😅
There’s no customization in MVC’s handling of syntactical JSON errors using this middleware (even with the conventions enabled). It’s really weird that MVC calls the validation problem method to create a response for a syntax error. I would’ve guessed they threw an exception long before it reached the validation stage, but your post is devoid of any details so it’s hard to tell 😅
Anyway, I think it might be better to transfer this to a new issue…
UPDATE: Seems like MVC is simply swallowing a perfectly good
JsonExceptionand stuffing some message into the validationModelState. Looks like it’s impossible to differentiate between syntactic and semantic errors in MVC.https://github.com/dotnet/aspnetcore/blob/757367ebc3a19fcfb2dd101e7c0a9d4e9896fdfd/src/Mvc/Mvc.Core/src/Formatters/SystemTextJsonInputFormatter.cs#L75-L96
Indeed. Welcome to the dark side 😜
Yeah, what you sent is perfectly valid JSON, but your domain expected the
Barvalue to be there, but it wasn’t, so 422 makes a lot of sense to me 😃Here are some observed differences with
AddProblemDetailsConventions:"https://httpstatuses.com/500"instead of"https://tools.ietf.org/html/rfc7231#section-6.5.1"ObjectResultviaBadRequest(string)andBadRequest(ModelState).ValidationProblem(ModelState), not sure why?Problem()
With
AddProblemDetailsConventions: ✅Without
AddProblemDetailsConventions:"https://tools.ietf.org/html/rfc7231#section-6.5.1"ℹValidationProblem(ModelState)
With
AddProblemDetailsConventions:Without
AddProblemDetailsConventions:"https://tools.ietf.org/html/rfc7231#section-6.5.1"ℹBadRequest(ModelState)
With
AddProblemDetailsConventions: ✅Without
AddProblemDetailsConventions:BadRequest(string)
With
AddProblemDetailsConventions: ✅Without
AddProblemDetailsConventions:Exception
With
AddProblemDetailsConventions: ✅Without
AddProblemDetailsConventions: Same. ✅@lonix1 I’m familiar with how the model binder works and I’m not disputing 400 vs 422. I’m trying to understand in the context of this library–based on this documentation–the expected outcomes. As both you and this thread seem to imply there are cases where I could get a 400 triggered during model binding, except that’s not the behavior I’m actually experiencing.
With the conventions enabled, both malformed json (which is syntactically invalid) and passing a date where a number is expected result in 422 and never a 400. Same goes for any mismatched data types in any location (query, request body, path; string/int/date) that I’ve tested.
Try as I might, I’m unable to trigger a 400 response from the framework (wrt model binding). I merely wish to understand the expectations here as I actually prefer the 422, but if MVC will still return a 400 in some circumstances then I want to understand when/why so I can explain the difference to consumers (and think it should be included in this documentation). If it’s expected that other than an explicit
BadRequestI won’t see a 400 that’s great; it’s just not clear to me.I’m simply asking for clarification on the points already discussed here. If this sounds like a bug I’m more than happy to transfer my comments to a new issue (or if you’d like, I can do that anyways since this one is technically closed)
I had to look at the source and various blogs to get a sense of what this does.
ProblemDetailsif 1) they are error responses (in range 400…599), or 2) Content-Length empty, or 3) Content-Type emptyProblemDetailsfor error (400…599) responses, as well as unhandled exceptions; shows exception details and stack traceI cannot figure out however what
AddProblemDetailsConventions()does, and if I need it since I’m using API controllers (not MVC or RazorPages).@khellang Please tell me if this is correct and if I missed something?