question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

C# client. ProblemsDetails vs ValidationProblemDetails

See original GitHub issue

Since ASP.NET core 2.2 Microsoft has been using ValidationProblemDetails by default when returning model state validation errors. BadRequest() Status Code 400

See https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.validationproblemdetails?view=aspnetcore-3.0

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.

ProblemDetails2

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

ProblemDetails1

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:closed
  • Created 4 years ago
  • Comments:11 (5 by maintainers)

github_iconTop GitHub Comments

4reactions
ghostcommented, Dec 10, 2019

I’ve found the answer. I’m just surprised after so many hours of looking I could not find what in retrospect was obvious.

[ProducesResponseType(typeof(ValidationProblemDetails), 400)]
public IActionResult CreateOrder([FromBody]Order order)
3reactions
pranavkmcommented, Dec 12, 2019

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.

Read more comments on GitHub >

github_iconTop Results From Across the Web

A standard way of specifying errors in HTTP API responses
A brief introduction of Problem details. If you have developed HTTP APIs, I'm sure that many times you have had the need to...
Read more >
Using the ProblemDetails Class in ASP.NET Core Web API
ProblemDetails class in ASP.NET Core Web APIs helps us to standardize our error handling and have better communication with API clients.
Read more >
Handle errors in ASP.NET Core web APIs
ASP.NET Core supports creating Problem Details for HTTP APIs using the IProblemDetailsService. For more information, see the Problem details ...
Read more >
Is there a .NET standard equivalent of ...
I am developing a mobile application that uses an ASP.NET Core API that responds using the standard error classes (ValidationProblemDetails ...
Read more >
Handling HTTP API Errors with Problem Details - YouTube
If you're developing an HTTP API, having a consistent way of returning errors can make handling errors on the client -side simpler.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found