-
Notifications
You must be signed in to change notification settings - Fork 709
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,8 +8,10 @@ namespace Microsoft.Extensions.DependencyInjection; | |
using Microsoft.AspNetCore.Http; | ||
using Microsoft.AspNetCore.Http.Json; | ||
using Microsoft.AspNetCore.Routing; | ||
using System.Diagnostics.CodeAnalysis; | ||
Check failure on line 11 in src/AspNetCore/WebApi/src/Asp.Versioning.Http/DependencyInjection/IServiceCollectionExtensions.cs GitHub Actions / Analyze
Check failure on line 11 in src/AspNetCore/WebApi/src/Asp.Versioning.Http/DependencyInjection/IServiceCollectionExtensions.cs GitHub Actions / Analyze
Check failure on line 11 in src/AspNetCore/WebApi/src/Asp.Versioning.Http/DependencyInjection/IServiceCollectionExtensions.cs GitHub Actions / Analyze
Check failure on line 11 in src/AspNetCore/WebApi/src/Asp.Versioning.Http/DependencyInjection/IServiceCollectionExtensions.cs GitHub Actions / Analyze
|
||
using Microsoft.Extensions.DependencyInjection.Extensions; | ||
using Microsoft.Extensions.Options; | ||
using static DynamicallyAccessedMemberTypes; | ||
Check failure on line 14 in src/AspNetCore/WebApi/src/Asp.Versioning.Http/DependencyInjection/IServiceCollectionExtensions.cs GitHub Actions / Analyze
Check failure on line 14 in src/AspNetCore/WebApi/src/Asp.Versioning.Http/DependencyInjection/IServiceCollectionExtensions.cs GitHub Actions / Analyze
Check failure on line 14 in src/AspNetCore/WebApi/src/Asp.Versioning.Http/DependencyInjection/IServiceCollectionExtensions.cs GitHub Actions / Analyze
Check failure on line 14 in src/AspNetCore/WebApi/src/Asp.Versioning.Http/DependencyInjection/IServiceCollectionExtensions.cs GitHub Actions / Analyze
|
||
using static ServiceDescriptor; | ||
|
||
/// <summary> | ||
|
@@ -74,6 +76,65 @@ public static IApiVersioningBuilder EnableApiVersionBinding( this IApiVersioning | |
return builder; | ||
} | ||
|
||
/// <summary> | ||
/// Adds error object support in problem details. | ||
/// </summary> | ||
/// <param name="services">The <see cref="IServiceCollection">services</see> available in the application.</param> | ||
/// <param name="setup">The <see cref="JsonOptions">JSON options</see> setup <see cref="Action{T}"/> to perform, if any.</param> | ||
/// <returns>The original <paramref name="services"/>.</returns> | ||
/// <remarks> | ||
/// <para> | ||
/// This method is only intended to provide backward compatibility with previous library versions by converting | ||
/// <see cref="Microsoft.AspNetCore.Mvc.ProblemDetails"/> into Error Objects that conform to the | ||
/// <a ref="https://github.com/microsoft/api-guidelines/blob/vNext/Guidelines.md#7102-error-condition-responses">Error Responses</a> | ||
/// in the Microsoft REST API Guidelines and | ||
/// <a ref="https://docs.oasis-open.org/odata/odata-json-format/v4.01/odata-json-format-v4.01.html#_Toc38457793">OData Error Responses</a>. | ||
/// </para> | ||
/// <para> | ||
/// This method should be called before <see cref="ProblemDetailsServiceCollectionExtensions.AddProblemDetails(IServiceCollection)"/>. | ||
/// </para> | ||
/// </remarks> | ||
public static IServiceCollection AddErrorObjects( this IServiceCollection services, Action<JsonOptions>? setup = default ) => | ||
AddErrorObjects<ErrorObjectWriter>( services, setup ); | ||
|
||
/// <summary> | ||
/// Adds error object support in problem details. | ||
/// </summary> | ||
/// <typeparam name="TWriter">The type of <see cref="ErrorObjectWriter"/>.</typeparam> | ||
/// <param name="services">The <see cref="IServiceCollection">services</see> available in the application.</param> | ||
/// <param name="setup">The <see cref="JsonOptions">JSON options</see> setup <see cref="Action{T}"/> to perform, if any.</param> | ||
/// <returns>The original <paramref name="services"/>.</returns> | ||
/// <remarks> | ||
/// <para> | ||
/// This method is only intended to provide backward compatibility with previous library versions by converting | ||
/// <see cref="Microsoft.AspNetCore.Mvc.ProblemDetails"/> into Error Objects that conform to the | ||
/// <a ref="https://github.com/microsoft/api-guidelines/blob/vNext/Guidelines.md#7102-error-condition-responses">Error Responses</a> | ||
/// in the Microsoft REST API Guidelines and | ||
/// <a ref="https://docs.oasis-open.org/odata/odata-json-format/v4.01/odata-json-format-v4.01.html#_Toc38457793">OData Error Responses</a>. | ||
/// </para> | ||
/// <para> | ||
/// This method should be called before <see cref="ProblemDetailsServiceCollectionExtensions.AddProblemDetails(IServiceCollection)"/>. | ||
/// </para> | ||
/// </remarks> | ||
public static IServiceCollection AddErrorObjects<[DynamicallyAccessedMembers( PublicConstructors )] TWriter>( | ||
this IServiceCollection services, | ||
Action<JsonOptions>? setup = default ) | ||
where TWriter : ErrorObjectWriter | ||
{ | ||
ArgumentNullException.ThrowIfNull( services ); | ||
|
||
services.TryAddEnumerable( Singleton<IProblemDetailsWriter, TWriter>() ); | ||
services.Configure( setup ?? DefaultErrorObjectJsonConfig ); | ||
|
||
// TODO: remove with TryAddErrorObjectJsonOptions in 9.0+ | ||
services.AddTransient<ErrorObjectsAdded>(); | ||
|
||
return services; | ||
} | ||
|
||
private static void DefaultErrorObjectJsonConfig( JsonOptions options ) => | ||
options.SerializerOptions.TypeInfoResolverChain.Insert( 0, ErrorObjectWriter.ErrorObjectJsonContext.Default ); | ||
|
||
private static void AddApiVersioningServices( IServiceCollection services ) | ||
{ | ||
ArgumentNullException.ThrowIfNull( services ); | ||
|
@@ -179,23 +240,48 @@ static Rfc7231ProblemDetailsWriter NewProblemDetailsWriter( IServiceProvider ser | |
new( (IProblemDetailsWriter) serviceProvider.GetRequiredService( decoratedType ) ); | ||
} | ||
|
||
// TODO: retain for 8.1.x back-compat, but remove in 9.0+ in favor of AddErrorObjects for perf | ||
private static void TryAddErrorObjectJsonOptions( IServiceCollection services ) | ||
{ | ||
var serviceType = typeof( IProblemDetailsWriter ); | ||
var implementationType = typeof( ErrorObjectWriter ); | ||
var markerType = typeof( ErrorObjectsAdded ); | ||
var hasErrorObjects = false; | ||
var hasErrorObjectsJsonConfig = false; | ||
|
||
for ( var i = 0; i < services.Count; i++ ) | ||
{ | ||
var service = services[i]; | ||
|
||
// inheritance is intentionally not considered here because it will require a user-defined | ||
// JsonSerlizerContext and IConfigureOptions<JsonOptions> | ||
if ( service.ServiceType == serviceType && | ||
service.ImplementationType == implementationType ) | ||
if ( !hasErrorObjects && | ||
service.ServiceType == serviceType && | ||
implementationType.IsAssignableFrom( service.ImplementationType ) ) | ||
{ | ||
services.TryAddEnumerable( Singleton<IConfigureOptions<JsonOptions>, ErrorObjectJsonOptionsSetup>() ); | ||
return; | ||
hasErrorObjects = true; | ||
|
||
if ( hasErrorObjectsJsonConfig ) | ||
{ | ||
break; | ||
} | ||
} | ||
else if ( service.ServiceType == markerType ) | ||
{ | ||
hasErrorObjectsJsonConfig = true; | ||
|
||
if ( hasErrorObjects ) | ||
{ | ||
break; | ||
} | ||
} | ||
} | ||
|
||
if ( hasErrorObjects && !hasErrorObjectsJsonConfig ) | ||
{ | ||
services.Configure<JsonOptions>( DefaultErrorObjectJsonConfig ); | ||
} | ||
} | ||
|
||
// TEMP: this is a marker class to test whether Error Objects have been explicitly added. remove in 9.0+ | ||
#pragma warning disable CA1812 // Avoid uninstantiated internal classes | ||
private sealed class ErrorObjectsAdded { } | ||
} |
This file was deleted.