Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 06d3d62

Browse filesBrowse files
Simplify the setup of Error Objects. Related to #1072
1 parent f9aa66d commit 06d3d62
Copy full SHA for 06d3d62

File tree

Expand file treeCollapse file tree

2 files changed

+90
-30
lines changed
Filter options
Expand file treeCollapse file tree

2 files changed

+90
-30
lines changed

‎src/AspNetCore/WebApi/src/Asp.Versioning.Http/DependencyInjection/IServiceCollectionExtensions.cs

Copy file name to clipboardExpand all lines: src/AspNetCore/WebApi/src/Asp.Versioning.Http/DependencyInjection/IServiceCollectionExtensions.cs
+90-6Lines changed: 90 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ namespace Microsoft.Extensions.DependencyInjection;
1111
using Microsoft.Extensions.DependencyInjection.Extensions;
1212
using Microsoft.Extensions.Options;
1313
using System;
14+
using System.Diagnostics.CodeAnalysis;
1415
using static Microsoft.Extensions.DependencyInjection.ServiceDescriptor;
16+
using static System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes;
1517

1618
/// <summary>
1719
/// Provides extension methods for the <see cref="IServiceCollection"/> interface.
@@ -75,6 +77,65 @@ public static IApiVersioningBuilder EnableApiVersionBinding( this IApiVersioning
7577
return builder;
7678
}
7779

80+
/// <summary>
81+
/// Adds error object support in problem details.
82+
/// </summary>
83+
/// <param name="services">The <see cref="IServiceCollection">services</see> available in the application.</param>
84+
/// <param name="setup">The <see cref="JsonOptions">JSON options</see> setup <see cref="Action{T}"/> to perform, if any.</param>
85+
/// <returns>The original <paramref name="services"/>.</returns>
86+
/// <remarks>
87+
/// <para>
88+
/// This method is only intended to provide backward compatibility with previous library versions by converting
89+
/// <see cref="Microsoft.AspNetCore.Mvc.ProblemDetails"/> into Error Objects that conform to the
90+
/// <a ref="https://github.com/microsoft/api-guidelines/blob/vNext/Guidelines.md#7102-error-condition-responses">Error Responses</a>
91+
/// in the Microsoft REST API Guidelines and
92+
/// <a ref="https://docs.oasis-open.org/odata/odata-json-format/v4.01/odata-json-format-v4.01.html#_Toc38457793">OData Error Responses</a>.
93+
/// </para>
94+
/// <para>
95+
/// This method should be called before <see cref="ProblemDetailsServiceCollectionExtensions.AddProblemDetails(IServiceCollection)"/>.
96+
/// </para>
97+
/// </remarks>
98+
public static IServiceCollection AddErrorObjects( this IServiceCollection services, Action<JsonOptions>? setup = default ) =>
99+
AddErrorObjects<ErrorObjectWriter>( services, setup );
100+
101+
/// <summary>
102+
/// Adds error object support in problem details.
103+
/// </summary>
104+
/// <typeparam name="TWriter">The type of <see cref="ErrorObjectWriter"/>.</typeparam>
105+
/// <param name="services">The <see cref="IServiceCollection">services</see> available in the application.</param>
106+
/// <param name="setup">The <see cref="JsonOptions">JSON options</see> setup <see cref="Action{T}"/> to perform, if any.</param>
107+
/// <returns>The original <paramref name="services"/>.</returns>
108+
/// <remarks>
109+
/// <para>
110+
/// This method is only intended to provide backward compatibility with previous library versions by converting
111+
/// <see cref="Microsoft.AspNetCore.Mvc.ProblemDetails"/> into Error Objects that conform to the
112+
/// <a ref="https://github.com/microsoft/api-guidelines/blob/vNext/Guidelines.md#7102-error-condition-responses">Error Responses</a>
113+
/// in the Microsoft REST API Guidelines and
114+
/// <a ref="https://docs.oasis-open.org/odata/odata-json-format/v4.01/odata-json-format-v4.01.html#_Toc38457793">OData Error Responses</a>.
115+
/// </para>
116+
/// <para>
117+
/// This method should be called before <see cref="ProblemDetailsServiceCollectionExtensions.AddProblemDetails(IServiceCollection)"/>.
118+
/// </para>
119+
/// </remarks>
120+
public static IServiceCollection AddErrorObjects<[DynamicallyAccessedMembers( PublicConstructors )] TWriter>(
121+
this IServiceCollection services,
122+
Action<JsonOptions>? setup = default )
123+
where TWriter : ErrorObjectWriter
124+
{
125+
ArgumentNullException.ThrowIfNull( services );
126+
127+
services.TryAddEnumerable( Singleton<IProblemDetailsWriter, TWriter>() );
128+
services.Configure( setup ?? DefaultErrorObjectJsonConfig );
129+
130+
// TODO: remove with TryAddErrorObjectJsonOptions in 9.0+
131+
services.AddTransient<ErrorObjectsAdded>();
132+
133+
return services;
134+
}
135+
136+
private static void DefaultErrorObjectJsonConfig( JsonOptions options ) =>
137+
options.SerializerOptions.TypeInfoResolverChain.Insert( 0, ErrorObjectWriter.ErrorObjectJsonContext.Default );
138+
78139
private static void AddApiVersioningServices( IServiceCollection services )
79140
{
80141
ArgumentNullException.ThrowIfNull( services );
@@ -180,23 +241,46 @@ static Rfc7231ProblemDetailsWriter NewProblemDetailsWriter( IServiceProvider ser
180241
new( (IProblemDetailsWriter) serviceProvider.GetRequiredService( decoratedType ) );
181242
}
182243

244+
// TODO: retain for 8.1.x back-compat, but remove in 9.0+ in favor of AddErrorObjects for perf
183245
private static void TryAddErrorObjectJsonOptions( IServiceCollection services )
184246
{
185247
var serviceType = typeof( IProblemDetailsWriter );
186248
var implementationType = typeof( ErrorObjectWriter );
249+
var markerType = typeof( ErrorObjectsAdded );
250+
var hasErrorObjects = false;
251+
var hasErrorObjectsJsonConfig = false;
187252

188253
for ( var i = 0; i < services.Count; i++ )
189254
{
190255
var service = services[i];
191256

192-
// inheritance is intentionally not considered here because it will require a user-defined
193-
// JsonSerlizerContext and IConfigureOptions<JsonOptions>
194-
if ( service.ServiceType == serviceType &&
195-
service.ImplementationType == implementationType )
257+
if ( !hasErrorObjects &&
258+
service.ServiceType == serviceType &&
259+
implementationType.IsAssignableFrom( service.ImplementationType ) )
196260
{
197-
services.TryAddEnumerable( Singleton<IConfigureOptions<JsonOptions>, ErrorObjectJsonOptionsSetup>() );
198-
return;
261+
hasErrorObjects = true;
262+
263+
if ( hasErrorObjectsJsonConfig )
264+
{
265+
break;
266+
}
199267
}
268+
else if ( service.ServiceType == markerType )
269+
{
270+
hasErrorObjectsJsonConfig = true;
271+
272+
if ( hasErrorObjects )
273+
{
274+
break;
275+
}
276+
}
277+
}
278+
279+
if ( hasErrorObjects && !hasErrorObjectsJsonConfig )
280+
{
281+
services.Configure<JsonOptions>( DefaultErrorObjectJsonConfig );
200282
}
201283
}
284+
285+
private sealed class ErrorObjectsAdded { }
202286
}

‎src/AspNetCore/WebApi/src/Asp.Versioning.Http/ErrorObjectJsonOptionsSetup.cs

Copy file name to clipboardExpand all lines: src/AspNetCore/WebApi/src/Asp.Versioning.Http/ErrorObjectJsonOptionsSetup.cs
-24Lines changed: 0 additions & 24 deletions
This file was deleted.

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.