C# client. ProblemsDetails vs ValidationProblemDetails
See original GitHub issueSince ASP.NET core 2.2 Microsoft has been using ValidationProblemDetails by default when returning model state validation errors. BadRequest() Status Code 400
Note ValidationProblemDetails inherits from ProblemDetails but adds the “Errors” extension to hold model state validation errors.
The problem begins when the OpenAPI spec document is generated as it currently uses ProblemDetails. As a consequence when the C# client gets generated the ProblemDetails class below is created. Note there is no Errors extension
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.0.28.0 (Newtonsoft.Json v12.0.0.0)")]
public partial class ProblemDetails
{
[Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public string Type { get; set; }
[Newtonsoft.Json.JsonProperty("title", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public string Title { get; set; }
[Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public int? Status { get; set; }
[Newtonsoft.Json.JsonProperty("detail", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public string Detail { get; set; }
[Newtonsoft.Json.JsonProperty("instance", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public string Instance { get; set; }
[Newtonsoft.Json.JsonProperty("extensions", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public System.Collections.Generic.IDictionary<string, object> Extensions { get; set; }
}
To confirm ValidationProblemDetails results are being returned for 400 BadRequest responses I set the generated clients property ReadResponseAsString to true.
client.ReadResponseAsString = true;
When a Status Code 400 error is generated the APIException Result property looks like the following: Note Extensions is NULL and there is no Errors property.
In that same exception here is the contents of the Response property: Note it contains the errors extension which confirms Microsoft is returning JSON results compatible with ValidationProblemDetails
As a temporary work around I’ve set NSwag studio to not generate the ProblemDetails class. Instead I have my own ProblemDetails outside of the generated client but in the same namespace. It looks like this with the newly added Errors extension.
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.0.28.0 (Newtonsoft.Json v12.0.0.0)")]
public partial class ProblemDetails
{
[Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public string Type { get; set; }
[Newtonsoft.Json.JsonProperty("title", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public string Title { get; set; }
[Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public int? Status { get; set; }
[Newtonsoft.Json.JsonProperty("detail", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public string Detail { get; set; }
[Newtonsoft.Json.JsonProperty("instance", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public string Instance { get; set; }
[Newtonsoft.Json.JsonProperty("extensions", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public System.Collections.Generic.IDictionary<string, object> Extensions { get; set; }
[Newtonsoft.Json.JsonProperty("errors", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public System.Collections.Generic.IDictionary<string, object> Errors { get; set; }
}
I’m curious, where does the ProblemDetails defintion come from when its written to the OpenAPI 3.0 document. Is it coming from APIExplorer?
As far as I can tell, if a more appropriate ProblemDetails (i.e. ValidationProblemDetails) is generated in the spec it will flow through the entire tool chain and generated clients will just work. ValidationProblemDetails would be the obvious choice as its just an extension of ProblemDetails
Issue Analytics
- State:
- Created 4 years ago
- Comments:11 (5 by maintainers)
I’ve found the answer. I’m just surprised after so many hours of looking I could not find what in retrospect was obvious.
There’s likely a missing feature in MVC that is causing this to not be reported correctly. I don’t think assuming 400 =
ValidationProblemDetails
is correct because it’s trivial for users to customize it. What we’d need is for some way for MVC to report the default error response type for 400s, and for a way for users to customize it globally. However, since we’re already talking about atleast 5.0 before we could surface this information via ApiExplorer, you could consider working around this for now.