Make ProblemDetailsDefaults public
- Dominant language
- C#
- Stars
- 38.4k
- Forks
- 10.9k
- Avg merge
- 2d 6h
- Merged PRs (30d)
- 290
Description
## Background and Motivation
Replaces https://github.com/dotnet/aspnetcore/issues/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](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.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](https://github.com/dotnet/aspnetcore/blob/main/src/Shared/ProblemDetails/ProblemDetailsDefaults.cs), 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 https://github.com/dotnet/aspnetcore/pull/43232
So I propose to make the type public.
## Proposed API
```diff
// 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 Defaults;
+ public static readonly IReadOnlyDictionary 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
```csharp
var pd = new ProblemDetails();
ProblemDetailDefaults.Apply(pd, 200);
```
## Alternative Designs
@halter73 suggested in https://github.com/dotnet/aspnetcore/issues/47822 that the name ``Apply`` might not be descriptive enough and/or to add it to the ``ProblemDetails`` type directly named ``ApplyStatusCodeDefaults``
```diff
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:
```diff
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.
Contributor guide
Assessment
This issue has not been assessed yet.