Skip to content

Make ProblemDetailsDefaults public #47978

Open
@Tornhoof

Description

@Tornhoof

Background and Motivation

Replaces #47822

Problem Details (RFC 7807) is a standardized way to communicate details for errors in HTTP Responses.
In ASP.NET Core this is surfaced by the public type ProblemDetails and related types. The RFC states, that an URL in Type is the canonical way to identify the details, a list of default URLs for the common Status Codes is available in ProblemDetailsDefaults, this type also includes a method to apply defaults to ProblemDetails, but the type is internal. There is infrastructure available to write serialized ProblemDetails into responses, but it is designed around having access to HttpContext.
If a developer wants to use the Problem Details without an active HttpRequest, he can't apply the nice defaults via the above mentioned type, instead need to maintain their own list and logic. The URLs currently point to the most recent HTTP rfc, this change was done for 8.0 via PR #43232

So I propose to make the type public.

Proposed API

// Microsoft.AspNetCore.Http.Extensions.dll (ProblemDetailsDefaults is currently in multiple assemblies, but they all depend on Http.Extensions)
namespace Microsoft.AspNetCore.Http;

- internal static class ProblemDetailsDefaults
+ public static class ProblemDetailsDefaults
{
-  public static readonly Dictionary<int, (string Type, string Title)> Defaults;
+  public static readonly IReadOnlyDictionary<int, (string Type, string Title)> Defaults;
   public static void Apply(ProblemDetails problemDetails, int? statusCode);
}

The type is changed to public, and the type of the static readonly field was changed to IReadOnlyDictionary, to prevent accidental changes.

Usage Examples

var pd = new ProblemDetails();
ProblemDetailDefaults.Apply(pd, 200);

Alternative Designs

@halter73 suggested in #47822 that the name Apply might not be descriptive enough and/or to add it to the ProblemDetails type directly named ApplyStatusCodeDefaults

namespace Microsoft.AspNetCore.Mvc;
 
public class ProblemDetails
{
+     public void ApplyStatusCodeDefaults(int? statusCode);
}

There is also the interface IProblemDetailsService where the same method could be added:

namespace Microsoft.AspNetCore.Mvc;
 
public interface IProblemDetailsService
{
+     public void ApplyStatusCodeDefaults(ProblemDetails problemDetails, int? statusCode);
}

Risks

  • Making the static type public is the easiest, with few risks as the type is internal at the moment, but it has risks as the type is included in multiple assemblies.
  • Adding it to the ProblemDetails as a member requires more thought, as there are already derived types of ProblemDetails and defaults might mean something else for them, the method might need to be virtual.
  • The interface is just for completeness here, as this is a proper breaking change (without some default interface implementation workarounds), while I doubt that many devs supply their own implementation of that interface, I don't think it is worth it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    api-needs-workAPI needs work before it is approved, it is NOT ready for implementationarea-minimalIncludes minimal APIs, endpoint filters, parameter binding, request delegate generator etcarea-mvcIncludes: MVC, Actions and Controllers, Localization, CORS, most templates

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions