diff --git a/src/Http/Http.Extensions/src/HttpRequestJsonExtensions.cs b/src/Http/Http.Extensions/src/HttpRequestJsonExtensions.cs index 437283c330dd..2c9c924a8d98 100644 --- a/src/Http/Http.Extensions/src/HttpRequestJsonExtensions.cs +++ b/src/Http/Http.Extensions/src/HttpRequestJsonExtensions.cs @@ -283,7 +283,7 @@ private static bool HasJsonContentType(this HttpRequest request, out StringSegme } // Matches application/json - if (mt.MediaType.Equals(JsonConstants.JsonContentType, StringComparison.OrdinalIgnoreCase)) + if (mt.MediaType.Equals(ContentTypeConstants.JsonContentType, StringComparison.OrdinalIgnoreCase)) { charset = mt.Charset; return true; diff --git a/src/Http/Http.Extensions/src/HttpResponseJsonExtensions.cs b/src/Http/Http.Extensions/src/HttpResponseJsonExtensions.cs index 42aa63c2bf14..c7d003e6bb0b 100644 --- a/src/Http/Http.Extensions/src/HttpResponseJsonExtensions.cs +++ b/src/Http/Http.Extensions/src/HttpResponseJsonExtensions.cs @@ -88,7 +88,7 @@ public static Task WriteAsJsonAsync( options ??= ResolveSerializerOptions(response.HttpContext); - response.ContentType = contentType ?? JsonConstants.JsonContentTypeWithCharset; + response.ContentType = contentType ?? ContentTypeConstants.JsonContentTypeWithCharset; var startTask = Task.CompletedTask; if (!response.HasStarted) @@ -129,7 +129,7 @@ public static Task WriteAsJsonAsync( { ArgumentNullException.ThrowIfNull(response); - response.ContentType = contentType ?? JsonConstants.JsonContentTypeWithCharset; + response.ContentType = contentType ?? ContentTypeConstants.JsonContentTypeWithCharset; var startTask = Task.CompletedTask; if (!response.HasStarted) @@ -182,7 +182,7 @@ public static Task WriteAsJsonAsync( { ArgumentNullException.ThrowIfNull(response); - response.ContentType = contentType ?? JsonConstants.JsonContentTypeWithCharset; + response.ContentType = contentType ?? ContentTypeConstants.JsonContentTypeWithCharset; var startTask = Task.CompletedTask; if (!response.HasStarted) @@ -302,7 +302,7 @@ public static Task WriteAsJsonAsync( options ??= ResolveSerializerOptions(response.HttpContext); - response.ContentType = contentType ?? JsonConstants.JsonContentTypeWithCharset; + response.ContentType = contentType ?? ContentTypeConstants.JsonContentTypeWithCharset; var startTask = Task.CompletedTask; if (!response.HasStarted) @@ -365,7 +365,7 @@ public static Task WriteAsJsonAsync( ArgumentNullException.ThrowIfNull(type); ArgumentNullException.ThrowIfNull(context); - response.ContentType = contentType ?? JsonConstants.JsonContentTypeWithCharset; + response.ContentType = contentType ?? ContentTypeConstants.JsonContentTypeWithCharset; var startTask = Task.CompletedTask; if (!response.HasStarted) diff --git a/src/Http/Http.Extensions/src/JsonConstants.cs b/src/Http/Http.Extensions/src/JsonConstants.cs deleted file mode 100644 index 4e8411b180ab..000000000000 --- a/src/Http/Http.Extensions/src/JsonConstants.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace Microsoft.AspNetCore.Http; - -internal static class JsonConstants -{ - public const string JsonContentType = "application/json"; - public const string JsonContentTypeWithCharset = "application/json; charset=utf-8"; -} diff --git a/src/Http/Http.Extensions/src/Microsoft.AspNetCore.Http.Extensions.csproj b/src/Http/Http.Extensions/src/Microsoft.AspNetCore.Http.Extensions.csproj index 0f8c4b3a3bf4..aa9645a5faa1 100644 --- a/src/Http/Http.Extensions/src/Microsoft.AspNetCore.Http.Extensions.csproj +++ b/src/Http/Http.Extensions/src/Microsoft.AspNetCore.Http.Extensions.csproj @@ -35,6 +35,7 @@ + diff --git a/src/Http/Http.Extensions/src/RequestDelegateFactory.cs b/src/Http/Http.Extensions/src/RequestDelegateFactory.cs index 5ab4ccc690a8..c2e2b1ea0d28 100644 --- a/src/Http/Http.Extensions/src/RequestDelegateFactory.cs +++ b/src/Http/Http.Extensions/src/RequestDelegateFactory.cs @@ -126,7 +126,7 @@ public static partial class RequestDelegateFactory private static readonly MethodInfo AsMemoryMethod = new Func>(MemoryExtensions.AsMemory).Method; private static readonly MethodInfo ArrayPoolSharedReturnMethod = typeof(ArrayPool).GetMethod(nameof(ArrayPool.Shared.Return))!; - private static readonly string[] DefaultAcceptsAndProducesContentType = new[] { JsonConstants.JsonContentType }; + private static readonly string[] DefaultAcceptsAndProducesContentType = new[] { ContentTypeConstants.JsonContentType }; private static readonly string[] FormFileContentType = new[] { "multipart/form-data" }; private static readonly string[] FormContentType = new[] { "multipart/form-data", "application/x-www-form-urlencoded" }; private static readonly string[] PlaintextContentType = new[] { "text/plain" }; diff --git a/src/Http/Http.Extensions/test/HttpResponseJsonExtensionsTests.cs b/src/Http/Http.Extensions/test/HttpResponseJsonExtensionsTests.cs index 771a824112d6..35cfa265d7f1 100644 --- a/src/Http/Http.Extensions/test/HttpResponseJsonExtensionsTests.cs +++ b/src/Http/Http.Extensions/test/HttpResponseJsonExtensionsTests.cs @@ -26,7 +26,7 @@ public async Task WriteAsJsonAsyncGeneric_SimpleValue_JsonResponse() await context.Response.WriteAsJsonAsync(1); // Assert - Assert.Equal(JsonConstants.JsonContentTypeWithCharset, context.Response.ContentType); + Assert.Equal(ContentTypeConstants.JsonContentTypeWithCharset, context.Response.ContentType); Assert.Equal(StatusCodes.Status200OK, context.Response.StatusCode); var data = body.ToArray(); @@ -45,7 +45,7 @@ public async Task WriteAsJsonAsyncGeneric_NullValue_JsonResponse() await context.Response.WriteAsJsonAsync(value: null); // Assert - Assert.Equal(JsonConstants.JsonContentTypeWithCharset, context.Response.ContentType); + Assert.Equal(ContentTypeConstants.JsonContentTypeWithCharset, context.Response.ContentType); var data = Encoding.UTF8.GetString(body.ToArray()); Assert.Equal("null", data); @@ -65,7 +65,7 @@ public async Task WriteAsJsonAsyncGeneric_WithOptions_JsonResponse() await context.Response.WriteAsJsonAsync(new int[] { 1, 2, 3 }, options); // Assert - Assert.Equal(JsonConstants.JsonContentTypeWithCharset, context.Response.ContentType); + Assert.Equal(ContentTypeConstants.JsonContentTypeWithCharset, context.Response.ContentType); var data = Encoding.UTF8.GetString(body.ToArray()); Assert.Equal("[false,true,false]", data); @@ -97,7 +97,7 @@ public async Task WriteAsJsonAsyncGeneric_CustomStatusCode_StatusCodeUnchanged() await context.Response.WriteAsJsonAsync(1); // Assert - Assert.Equal(JsonConstants.JsonContentTypeWithCharset, context.Response.ContentType); + Assert.Equal(ContentTypeConstants.JsonContentTypeWithCharset, context.Response.ContentType); Assert.Equal(StatusCodes.Status418ImATeapot, context.Response.StatusCode); } @@ -167,7 +167,7 @@ public async Task WriteAsJsonAsync_SimpleValue_JsonResponse() await context.Response.WriteAsJsonAsync(1, typeof(int)); // Assert - Assert.Equal(JsonConstants.JsonContentTypeWithCharset, context.Response.ContentType); + Assert.Equal(ContentTypeConstants.JsonContentTypeWithCharset, context.Response.ContentType); Assert.Equal(StatusCodes.Status200OK, context.Response.StatusCode); var data = body.ToArray(); @@ -186,7 +186,7 @@ public async Task WriteAsJsonAsync_NullValue_JsonResponse() await context.Response.WriteAsJsonAsync(value: null, typeof(int?)); // Assert - Assert.Equal(JsonConstants.JsonContentTypeWithCharset, context.Response.ContentType); + Assert.Equal(ContentTypeConstants.JsonContentTypeWithCharset, context.Response.ContentType); var data = Encoding.UTF8.GetString(body.ToArray()); Assert.Equal("null", data); @@ -249,7 +249,7 @@ public async Task WriteAsJsonAsync_CustomStatusCode_StatusCodeUnchanged() await context.Response.WriteAsJsonAsync(1, typeof(int)); // Assert - Assert.Equal(JsonConstants.JsonContentTypeWithCharset, context.Response.ContentType); + Assert.Equal(ContentTypeConstants.JsonContentTypeWithCharset, context.Response.ContentType); Assert.Equal(StatusCodes.Status418ImATeapot, context.Response.StatusCode); } @@ -265,7 +265,7 @@ public async Task WriteAsJsonAsyncGeneric_AsyncEnumerable() await context.Response.WriteAsJsonAsync(AsyncEnumerable()); // Assert - Assert.Equal(JsonConstants.JsonContentTypeWithCharset, context.Response.ContentType); + Assert.Equal(ContentTypeConstants.JsonContentTypeWithCharset, context.Response.ContentType); Assert.Equal(StatusCodes.Status200OK, context.Response.StatusCode); Assert.Equal("[1,2]", Encoding.UTF8.GetString(body.ToArray())); @@ -290,7 +290,7 @@ public async Task WriteAsJsonAsync_AsyncEnumerable() await context.Response.WriteAsJsonAsync(AsyncEnumerable(), typeof(IAsyncEnumerable)); // Assert - Assert.Equal(JsonConstants.JsonContentTypeWithCharset, context.Response.ContentType); + Assert.Equal(ContentTypeConstants.JsonContentTypeWithCharset, context.Response.ContentType); Assert.Equal(StatusCodes.Status200OK, context.Response.StatusCode); Assert.Equal("[1,2]", Encoding.UTF8.GetString(body.ToArray())); @@ -318,7 +318,7 @@ public async Task WriteAsJsonAsyncGeneric_AsyncEnumerable_ClosedConnecton() await context.Response.WriteAsJsonAsync(AsyncEnumerable()); // Assert - Assert.Equal(JsonConstants.JsonContentTypeWithCharset, context.Response.ContentType); + Assert.Equal(ContentTypeConstants.JsonContentTypeWithCharset, context.Response.ContentType); Assert.Equal(StatusCodes.Status200OK, context.Response.StatusCode); // System.Text.Json might write the '[' before cancellation is observed @@ -352,7 +352,7 @@ public async Task WriteAsJsonAsync_AsyncEnumerable_ClosedConnecton() await context.Response.WriteAsJsonAsync(AsyncEnumerable(), typeof(IAsyncEnumerable)); // Assert - Assert.Equal(JsonConstants.JsonContentTypeWithCharset, context.Response.ContentType); + Assert.Equal(ContentTypeConstants.JsonContentTypeWithCharset, context.Response.ContentType); Assert.Equal(StatusCodes.Status200OK, context.Response.StatusCode); // System.Text.Json might write the '[' before cancellation is observed @@ -386,7 +386,7 @@ public async Task WriteAsJsonAsync_AsyncEnumerable_UserPassedTokenThrows() await Assert.ThrowsAnyAsync(() => context.Response.WriteAsJsonAsync(AsyncEnumerable(), typeof(IAsyncEnumerable), cts.Token)); // Assert - Assert.Equal(JsonConstants.JsonContentTypeWithCharset, context.Response.ContentType); + Assert.Equal(ContentTypeConstants.JsonContentTypeWithCharset, context.Response.ContentType); Assert.Equal(StatusCodes.Status200OK, context.Response.StatusCode); // System.Text.Json might write the '[' before cancellation is observed @@ -420,7 +420,7 @@ public async Task WriteAsJsonAsyncGeneric_AsyncEnumerable_UserPassedTokenThrows( await Assert.ThrowsAnyAsync(() => context.Response.WriteAsJsonAsync(AsyncEnumerable(), cts.Token)); // Assert - Assert.Equal(JsonConstants.JsonContentTypeWithCharset, context.Response.ContentType); + Assert.Equal(ContentTypeConstants.JsonContentTypeWithCharset, context.Response.ContentType); Assert.Equal(StatusCodes.Status200OK, context.Response.StatusCode); // System.Text.Json might write the '[' before cancellation is observed @@ -454,7 +454,7 @@ public async Task WriteAsJsonAsyncGeneric_WithJsonTypeInfo_JsonResponse() await context.Response.WriteAsJsonAsync(new int[] { 1, 2, 3 }, (JsonTypeInfo)options.GetTypeInfo(typeof(int[]))); // Assert - Assert.Equal(JsonConstants.JsonContentTypeWithCharset, context.Response.ContentType); + Assert.Equal(ContentTypeConstants.JsonContentTypeWithCharset, context.Response.ContentType); var data = Encoding.UTF8.GetString(body.ToArray()); Assert.Equal("[1,2,3]", data); @@ -475,7 +475,7 @@ public async Task WriteAsJsonAsync_NullValue_WithJsonTypeInfo_JsonResponse() await context.Response.WriteAsJsonAsync(value : null, options.GetTypeInfo(typeof(Uri))); // Assert - Assert.Equal(JsonConstants.JsonContentTypeWithCharset, context.Response.ContentType); + Assert.Equal(ContentTypeConstants.JsonContentTypeWithCharset, context.Response.ContentType); var data = Encoding.UTF8.GetString(body.ToArray()); Assert.Equal("null", data); diff --git a/src/Http/Http.Results/src/AcceptedAtRouteOfT.cs b/src/Http/Http.Results/src/AcceptedAtRouteOfT.cs index e01be31eca3b..e9467dbe1e54 100644 --- a/src/Http/Http.Results/src/AcceptedAtRouteOfT.cs +++ b/src/Http/Http.Results/src/AcceptedAtRouteOfT.cs @@ -122,6 +122,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi ArgumentNullException.ThrowIfNull(method); ArgumentNullException.ThrowIfNull(builder); - builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status202Accepted, HttpResultsHelper.ApplicationJsonContentTypes)); + builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status202Accepted, ContentTypeConstants.ApplicationJsonContentTypes)); } } diff --git a/src/Http/Http.Results/src/AcceptedOfT.cs b/src/Http/Http.Results/src/AcceptedOfT.cs index 939f45f19e92..6777d3549d58 100644 --- a/src/Http/Http.Results/src/AcceptedOfT.cs +++ b/src/Http/Http.Results/src/AcceptedOfT.cs @@ -100,6 +100,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi ArgumentNullException.ThrowIfNull(method); ArgumentNullException.ThrowIfNull(builder); - builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status202Accepted, HttpResultsHelper.ApplicationJsonContentTypes)); + builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status202Accepted, ContentTypeConstants.ApplicationJsonContentTypes)); } } diff --git a/src/Http/Http.Results/src/BadRequestOfT.cs b/src/Http/Http.Results/src/BadRequestOfT.cs index d28929f595af..4b932786eb3b 100644 --- a/src/Http/Http.Results/src/BadRequestOfT.cs +++ b/src/Http/Http.Results/src/BadRequestOfT.cs @@ -65,6 +65,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi ArgumentNullException.ThrowIfNull(method); ArgumentNullException.ThrowIfNull(builder); - builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status400BadRequest, HttpResultsHelper.ApplicationJsonContentTypes)); + builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status400BadRequest, ContentTypeConstants.ApplicationJsonContentTypes)); } } diff --git a/src/Http/Http.Results/src/ConflictOfT.cs b/src/Http/Http.Results/src/ConflictOfT.cs index 325ba7a90b89..bbfb3c6a503e 100644 --- a/src/Http/Http.Results/src/ConflictOfT.cs +++ b/src/Http/Http.Results/src/ConflictOfT.cs @@ -65,6 +65,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi ArgumentNullException.ThrowIfNull(method); ArgumentNullException.ThrowIfNull(builder); - builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status409Conflict, HttpResultsHelper.ApplicationJsonContentTypes)); + builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status409Conflict, ContentTypeConstants.ApplicationJsonContentTypes)); } } diff --git a/src/Http/Http.Results/src/CreatedAtRouteOfT.cs b/src/Http/Http.Results/src/CreatedAtRouteOfT.cs index 28fd3dc69162..d13d6154413b 100644 --- a/src/Http/Http.Results/src/CreatedAtRouteOfT.cs +++ b/src/Http/Http.Results/src/CreatedAtRouteOfT.cs @@ -125,6 +125,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi ArgumentNullException.ThrowIfNull(method); ArgumentNullException.ThrowIfNull(builder); - builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status201Created, HttpResultsHelper.ApplicationJsonContentTypes)); + builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status201Created, ContentTypeConstants.ApplicationJsonContentTypes)); } } diff --git a/src/Http/Http.Results/src/CreatedOfT.cs b/src/Http/Http.Results/src/CreatedOfT.cs index beda8bd77995..58d0638b218d 100644 --- a/src/Http/Http.Results/src/CreatedOfT.cs +++ b/src/Http/Http.Results/src/CreatedOfT.cs @@ -99,6 +99,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi ArgumentNullException.ThrowIfNull(method); ArgumentNullException.ThrowIfNull(builder); - builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status201Created, HttpResultsHelper.ApplicationJsonContentTypes)); + builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status201Created, ContentTypeConstants.ApplicationJsonContentTypes)); } } diff --git a/src/Http/Http.Results/src/FileContentHttpResult.cs b/src/Http/Http.Results/src/FileContentHttpResult.cs index f60e4d7d0b3f..52980167627a 100644 --- a/src/Http/Http.Results/src/FileContentHttpResult.cs +++ b/src/Http/Http.Results/src/FileContentHttpResult.cs @@ -61,7 +61,7 @@ internal FileContentHttpResult( { FileContents = fileContents; FileLength = fileContents.Length; - ContentType = contentType ?? HttpResultsHelper.BinaryContentType; + ContentType = contentType ?? ContentTypeConstants.BinaryContentType; FileDownloadName = fileDownloadName; EnableRangeProcessing = enableRangeProcessing; LastModified = lastModified; diff --git a/src/Http/Http.Results/src/FileStreamHttpResult.cs b/src/Http/Http.Results/src/FileStreamHttpResult.cs index e5ca5d76c918..4c2e76a130c2 100644 --- a/src/Http/Http.Results/src/FileStreamHttpResult.cs +++ b/src/Http/Http.Results/src/FileStreamHttpResult.cs @@ -67,7 +67,7 @@ internal FileStreamHttpResult( FileLength = fileStream.Length; } - ContentType = contentType ?? HttpResultsHelper.BinaryContentType; + ContentType = contentType ?? ContentTypeConstants.BinaryContentType; FileDownloadName = fileDownloadName; EnableRangeProcessing = enableRangeProcessing; LastModified = lastModified; diff --git a/src/Http/Http.Results/src/HttpResultsHelper.cs b/src/Http/Http.Results/src/HttpResultsHelper.cs index a7a9de11661e..bf3ac87379fc 100644 --- a/src/Http/Http.Results/src/HttpResultsHelper.cs +++ b/src/Http/Http.Results/src/HttpResultsHelper.cs @@ -17,13 +17,6 @@ namespace Microsoft.AspNetCore.Http; internal static partial class HttpResultsHelper { - internal const string BinaryContentType = "application/octet-stream"; - internal const string DefaultContentType = "text/plain; charset=utf-8"; - internal const string ProblemDetailsContentType = "application/problem+json"; - - internal static IEnumerable ApplicationJsonContentTypes { get; } = ["application/json"]; - internal static IEnumerable ProblemDetailsContentTypes { get; } = [ProblemDetailsContentType]; - private static readonly Encoding DefaultEncoding = Encoding.UTF8; [UnconditionalSuppressMessage("Trimming", "IL2026:RequiresUnreferencedCode", @@ -77,7 +70,7 @@ public static Task WriteResultAsContentAsync( ResponseContentTypeHelper.ResolveContentTypeAndEncoding( contentType, response.ContentType, - (DefaultContentType, DefaultEncoding), + (ContentTypeConstants.DefaultContentType, DefaultEncoding), ResponseContentTypeHelper.GetEncoding, out var resolvedContentType, out var resolvedContentTypeEncoding); diff --git a/src/Http/Http.Results/src/InternalServerErrorOfT.cs b/src/Http/Http.Results/src/InternalServerErrorOfT.cs index 85493f1957df..36ec9fed9512 100644 --- a/src/Http/Http.Results/src/InternalServerErrorOfT.cs +++ b/src/Http/Http.Results/src/InternalServerErrorOfT.cs @@ -65,6 +65,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi ArgumentNullException.ThrowIfNull(method); ArgumentNullException.ThrowIfNull(builder); - builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status500InternalServerError, HttpResultsHelper.ApplicationJsonContentTypes)); + builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status500InternalServerError, ContentTypeConstants.ApplicationJsonContentTypes)); } } diff --git a/src/Http/Http.Results/src/Microsoft.AspNetCore.Http.Results.csproj b/src/Http/Http.Results/src/Microsoft.AspNetCore.Http.Results.csproj index 435b47be5bd7..ea792b089048 100644 --- a/src/Http/Http.Results/src/Microsoft.AspNetCore.Http.Results.csproj +++ b/src/Http/Http.Results/src/Microsoft.AspNetCore.Http.Results.csproj @@ -20,6 +20,7 @@ + diff --git a/src/Http/Http.Results/src/NotFoundOfT.cs b/src/Http/Http.Results/src/NotFoundOfT.cs index c803b2067530..ad9c3a1032eb 100644 --- a/src/Http/Http.Results/src/NotFoundOfT.cs +++ b/src/Http/Http.Results/src/NotFoundOfT.cs @@ -64,6 +64,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi ArgumentNullException.ThrowIfNull(method); ArgumentNullException.ThrowIfNull(builder); - builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status404NotFound, HttpResultsHelper.ApplicationJsonContentTypes)); + builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status404NotFound, ContentTypeConstants.ApplicationJsonContentTypes)); } } diff --git a/src/Http/Http.Results/src/OkOfT.cs b/src/Http/Http.Results/src/OkOfT.cs index ba5efa0c2319..108674fdc2ac 100644 --- a/src/Http/Http.Results/src/OkOfT.cs +++ b/src/Http/Http.Results/src/OkOfT.cs @@ -64,6 +64,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi ArgumentNullException.ThrowIfNull(method); ArgumentNullException.ThrowIfNull(builder); - builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status200OK, HttpResultsHelper.ApplicationJsonContentTypes)); + builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status200OK, ContentTypeConstants.ApplicationJsonContentTypes)); } } diff --git a/src/Http/Http.Results/src/PhysicalFileHttpResult.cs b/src/Http/Http.Results/src/PhysicalFileHttpResult.cs index aa8cadf5e71f..594532bd1a14 100644 --- a/src/Http/Http.Results/src/PhysicalFileHttpResult.cs +++ b/src/Http/Http.Results/src/PhysicalFileHttpResult.cs @@ -58,7 +58,7 @@ internal PhysicalFileHttpResult( EntityTagHeaderValue? entityTag = null) { FileName = fileName; - ContentType = contentType ?? HttpResultsHelper.BinaryContentType; + ContentType = contentType ?? ContentTypeConstants.BinaryContentType; FileDownloadName = fileDownloadName; EnableRangeProcessing = enableRangeProcessing; LastModified = lastModified; diff --git a/src/Http/Http.Results/src/ProblemHttpResult.cs b/src/Http/Http.Results/src/ProblemHttpResult.cs index 9eec49a20642..4fe63c4277cc 100644 --- a/src/Http/Http.Results/src/ProblemHttpResult.cs +++ b/src/Http/Http.Results/src/ProblemHttpResult.cs @@ -36,7 +36,7 @@ internal ProblemHttpResult(ProblemDetails problemDetails) /// /// Gets the value for the Content-Type header: application/problem+json /// - public string ContentType => HttpResultsHelper.ProblemDetailsContentType; + public string ContentType => ContentTypeConstants.ProblemDetailsContentType; /// /// Gets the HTTP status code. diff --git a/src/Http/Http.Results/src/UnprocessableEntityOfT.cs b/src/Http/Http.Results/src/UnprocessableEntityOfT.cs index 764ed15514ac..475a0bc3ad2c 100644 --- a/src/Http/Http.Results/src/UnprocessableEntityOfT.cs +++ b/src/Http/Http.Results/src/UnprocessableEntityOfT.cs @@ -65,6 +65,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi ArgumentNullException.ThrowIfNull(method); ArgumentNullException.ThrowIfNull(builder); - builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status422UnprocessableEntity, HttpResultsHelper.ApplicationJsonContentTypes)); + builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status422UnprocessableEntity, ContentTypeConstants.ApplicationJsonContentTypes)); } } diff --git a/src/Http/Http.Results/src/Utf8ContentHttpResult.cs b/src/Http/Http.Results/src/Utf8ContentHttpResult.cs index 4ca984b0d457..df5ce7ae9649 100644 --- a/src/Http/Http.Results/src/Utf8ContentHttpResult.cs +++ b/src/Http/Http.Results/src/Utf8ContentHttpResult.cs @@ -62,7 +62,7 @@ public Task ExecuteAsync(HttpContext httpContext) httpContext.Response.StatusCode = statusCode; } - httpContext.Response.ContentType = ContentType ?? HttpResultsHelper.DefaultContentType; + httpContext.Response.ContentType = ContentType ?? ContentTypeConstants.DefaultContentType; httpContext.Response.ContentLength = ResponseContent.Length; return httpContext.Response.Body.WriteAsync(ResponseContent).AsTask(); diff --git a/src/Http/Http.Results/src/ValidationProblem.cs b/src/Http/Http.Results/src/ValidationProblem.cs index 653ac7bfe1c3..ba738cfbcf3e 100644 --- a/src/Http/Http.Results/src/ValidationProblem.cs +++ b/src/Http/Http.Results/src/ValidationProblem.cs @@ -39,7 +39,7 @@ internal ValidationProblem(HttpValidationProblemDetails problemDetails) /// /// Gets the value for the Content-Type header: application/problem+json. /// - public string ContentType => HttpResultsHelper.ProblemDetailsContentType; + public string ContentType => ContentTypeConstants.ProblemDetailsContentType; /// /// Gets the HTTP status code: @@ -76,6 +76,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi ArgumentNullException.ThrowIfNull(method); ArgumentNullException.ThrowIfNull(builder); - builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(HttpValidationProblemDetails), StatusCodes.Status400BadRequest, HttpResultsHelper.ProblemDetailsContentTypes)); + builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(HttpValidationProblemDetails), StatusCodes.Status400BadRequest, ContentTypeConstants.ProblemDetailsContentTypes)); } } diff --git a/src/Http/Http.Results/src/VirtualFileHttpResult.cs b/src/Http/Http.Results/src/VirtualFileHttpResult.cs index 10e677e1247f..0c84db49b216 100644 --- a/src/Http/Http.Results/src/VirtualFileHttpResult.cs +++ b/src/Http/Http.Results/src/VirtualFileHttpResult.cs @@ -63,7 +63,7 @@ internal VirtualFileHttpResult( EntityTagHeaderValue? entityTag = null) { FileName = fileName; - ContentType = contentType ?? HttpResultsHelper.BinaryContentType; + ContentType = contentType ?? ContentTypeConstants.BinaryContentType; FileDownloadName = fileDownloadName; EnableRangeProcessing = enableRangeProcessing; LastModified = lastModified; diff --git a/src/Http/Routing/src/Builder/OpenApiRouteHandlerBuilderExtensions.cs b/src/Http/Routing/src/Builder/OpenApiRouteHandlerBuilderExtensions.cs index 3defe3cf152d..cf6faa2267f9 100644 --- a/src/Http/Routing/src/Builder/OpenApiRouteHandlerBuilderExtensions.cs +++ b/src/Http/Routing/src/Builder/OpenApiRouteHandlerBuilderExtensions.cs @@ -76,7 +76,7 @@ public static RouteHandlerBuilder Produces( { if (responseType is Type && string.IsNullOrEmpty(contentType)) { - contentType = "application/json"; + contentType = ContentTypeConstants.JsonContentType; } if (contentType is null) @@ -103,12 +103,33 @@ public static RouteHandlerBuilder ProducesProblem(this RouteHandlerBuilder build { if (string.IsNullOrEmpty(contentType)) { - contentType = "application/problem+json"; + contentType = ContentTypeConstants.ProblemDetailsContentType; } return Produces(builder, statusCode, typeof(ProblemDetails), contentType); } + /// + /// Adds an with a type + /// to for all endpoints produced by . + /// + /// The . + /// The response status code. + /// The response content type. Defaults to "application/problem+json". + /// A that can be used to further customize the endpoint. +#pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters + public static TBuilder ProducesProblem(this TBuilder builder, int statusCode, string? contentType = null) +#pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters + where TBuilder : IEndpointConventionBuilder + { + if (string.IsNullOrEmpty(contentType)) + { + contentType = ContentTypeConstants.ProblemDetailsContentType; + } + + return builder.WithMetadata(new ProducesResponseTypeMetadata(statusCode, typeof(ProblemDetails), [contentType])); + } + /// /// Adds an with a type /// to for all endpoints produced by . @@ -124,12 +145,36 @@ public static RouteHandlerBuilder ProducesValidationProblem( { if (string.IsNullOrEmpty(contentType)) { - contentType = "application/problem+json"; + contentType = ContentTypeConstants.ProblemDetailsContentType; } return Produces(builder, statusCode, typeof(HttpValidationProblemDetails), contentType); } + /// + /// Adds an with a type + /// to for all endpoints produced by . + /// + /// The . + /// The response status code. Defaults to . + /// The response content type. Defaults to "application/problem+json". + /// A that can be used to further customize the endpoint. +#pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters + public static TBuilder ProducesValidationProblem( +#pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters + this TBuilder builder, + int statusCode = StatusCodes.Status400BadRequest, + string? contentType = null) + where TBuilder : IEndpointConventionBuilder + { + if (string.IsNullOrEmpty(contentType)) + { + contentType = ContentTypeConstants.ProblemDetailsContentType; + } + + return builder.WithMetadata(new ProducesResponseTypeMetadata(statusCode, typeof(HttpValidationProblemDetails), [contentType])); + } + /// /// Adds the to for all endpoints /// produced by . diff --git a/src/Http/Routing/src/Microsoft.AspNetCore.Routing.csproj b/src/Http/Routing/src/Microsoft.AspNetCore.Routing.csproj index 955a34fd54c3..16a710df5ce4 100644 --- a/src/Http/Routing/src/Microsoft.AspNetCore.Routing.csproj +++ b/src/Http/Routing/src/Microsoft.AspNetCore.Routing.csproj @@ -37,6 +37,7 @@ + diff --git a/src/Http/Routing/src/PublicAPI.Unshipped.txt b/src/Http/Routing/src/PublicAPI.Unshipped.txt index 1d1131ea95bf..f36374cf8952 100644 --- a/src/Http/Routing/src/PublicAPI.Unshipped.txt +++ b/src/Http/Routing/src/PublicAPI.Unshipped.txt @@ -3,4 +3,6 @@ Microsoft.AspNetCore.Routing.ContentEncodingMetadata Microsoft.AspNetCore.Routing.ContentEncodingMetadata.ContentEncodingMetadata(string! value, double quality) -> void Microsoft.AspNetCore.Routing.ContentEncodingMetadata.Quality.get -> double Microsoft.AspNetCore.Routing.ContentEncodingMetadata.Value.get -> string! +static Microsoft.AspNetCore.Http.OpenApiRouteHandlerBuilderExtensions.ProducesProblem(this TBuilder builder, int statusCode, string? contentType = null) -> TBuilder +static Microsoft.AspNetCore.Http.OpenApiRouteHandlerBuilderExtensions.ProducesValidationProblem(this TBuilder builder, int statusCode = 400, string? contentType = null) -> TBuilder static Microsoft.AspNetCore.Routing.RouteHandlerServices.Map(Microsoft.AspNetCore.Routing.IEndpointRouteBuilder! endpoints, string! pattern, System.Delegate! handler, System.Collections.Generic.IEnumerable? httpMethods, System.Func! populateMetadata, System.Func! createRequestDelegate, System.Reflection.MethodInfo! methodInfo) -> Microsoft.AspNetCore.Builder.RouteHandlerBuilder! diff --git a/src/Http/Routing/test/UnitTests/Builder/OpenApiRouteHandlerBuilderExtensionsTest.cs b/src/Http/Routing/test/UnitTests/Builder/OpenApiRouteHandlerBuilderExtensionsTest.cs index 54a87d2aa5aa..60e4435e91db 100644 --- a/src/Http/Routing/test/UnitTests/Builder/OpenApiRouteHandlerBuilderExtensionsTest.cs +++ b/src/Http/Routing/test/UnitTests/Builder/OpenApiRouteHandlerBuilderExtensionsTest.cs @@ -69,31 +69,38 @@ public void Produces_AddsProducesResponseTypeMetadataWithVoidType() } [Fact] - public void ProdcesProblem_AddsProducesResponseTypeMetadataWithProblemDetailsType() + public void ProducesProblem_AddsProducesResponseTypeMetadataWithProblemDetailsType() { - var testBuilder = new TestEndointConventionBuilder(); - var builder = new RouteHandlerBuilder(new[] { testBuilder }); + static void GenericProducesProblem(IEndpointConventionBuilder builder) => builder.ProducesProblem(StatusCodes.Status400BadRequest); + static void SpecificProducesProblem(RouteHandlerBuilder builder) => builder.ProducesProblem(StatusCodes.Status400BadRequest); - builder.ProducesProblem(StatusCodes.Status400BadRequest); + static void AssertMetadata(EndpointBuilder builder) + { + var metadata = Assert.IsType(Assert.Single(builder.Metadata)); + Assert.Equal(typeof(ProblemDetails), metadata.Type); + Assert.Equal(StatusCodes.Status400BadRequest, metadata.StatusCode); + Assert.Equal("application/problem+json", Assert.Single(metadata.ContentTypes)); + } + + RunWithBothBuilders(GenericProducesProblem, SpecificProducesProblem, AssertMetadata); - var metadata = Assert.IsType(Assert.Single(testBuilder.Metadata)); - Assert.Equal(typeof(ProblemDetails), metadata.Type); - Assert.Equal(StatusCodes.Status400BadRequest, metadata.StatusCode); - Assert.Equal("application/problem+json", Assert.Single(metadata.ContentTypes)); } [Fact] - public void ProdcesValidiationProblem_AddsProducesResponseTypeMetadataWithHttpValidationProblemDetailsType() + public void ProducesValidationProblem_AddsProducesResponseTypeMetadataWithHttpValidationProblemDetailsType() { - var testBuilder = new TestEndointConventionBuilder(); - var builder = new RouteHandlerBuilder(new[] { testBuilder }); + static void GenericProducesProblem(IEndpointConventionBuilder builder) => builder.ProducesValidationProblem(); + static void SpecificProducesProblem(RouteHandlerBuilder builder) => builder.ProducesValidationProblem(); - builder.ProducesValidationProblem(); + static void AssertMetadata(EndpointBuilder builder) + { + var metadata = Assert.IsType(Assert.Single(builder.Metadata)); + Assert.Equal(typeof(HttpValidationProblemDetails), metadata.Type); + Assert.Equal(StatusCodes.Status400BadRequest, metadata.StatusCode); + Assert.Equal("application/problem+json", Assert.Single(metadata.ContentTypes)); + } - var metadata = Assert.IsType(Assert.Single(testBuilder.Metadata)); - Assert.Equal(typeof(HttpValidationProblemDetails), metadata.Type); - Assert.Equal(StatusCodes.Status400BadRequest, metadata.StatusCode); - Assert.Equal("application/problem+json", Assert.Single(metadata.ContentTypes)); + RunWithBothBuilders(GenericProducesProblem, SpecificProducesProblem, AssertMetadata); } [Fact] diff --git a/src/Shared/ContentTypeConstants.cs b/src/Shared/ContentTypeConstants.cs new file mode 100644 index 000000000000..42dfd4b5938b --- /dev/null +++ b/src/Shared/ContentTypeConstants.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +internal static class ContentTypeConstants +{ + public const string JsonContentType = "application/json"; + internal static IEnumerable ApplicationJsonContentTypes { get; } = ["application/json"]; + public const string ProblemDetailsContentType = "application/problem+json"; + public static readonly IEnumerable ProblemDetailsContentTypes = [ProblemDetailsContentType]; + public const string JsonContentTypeWithCharset = "application/json; charset=utf-8"; + public const string BinaryContentType = "application/octet-stream"; + public const string DefaultContentType = "text/plain; charset=utf-8"; +}