Ver código fonte

Problem details cleanup (#34557)

* Problem details cleanup

* Move HttpValidationProblemDetails to Microsoft.AspNetCore.Http per API review
* Return Content-Type headers when returning ProblemDetails responses
Pranav K 4 anos atrás
pai
commit
edc3534b41

+ 1 - 3
src/Http/Http.Extensions/src/HttpValidationProblemDetails.cs

@@ -1,12 +1,10 @@
 // Copyright (c) .NET Foundation. All rights reserved.
 // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
 
-using System;
-using System.Collections.Generic;
 using System.Text.Json.Serialization;
 using Microsoft.AspNetCore.Mvc;
 
-namespace Microsoft.AspNetCore.Http.Extensions
+namespace Microsoft.AspNetCore.Http
 {
     /// <summary>
     /// A <see cref="ProblemDetails"/> for validation errors.

+ 1 - 3
src/Http/Http.Extensions/src/ProblemDetails.cs

@@ -1,10 +1,8 @@
 // Copyright (c) .NET Foundation. All rights reserved.
 // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
 
-using System;
-using System.Collections.Generic;
 using System.Text.Json.Serialization;
-using Microsoft.AspNetCore.Http.Extensions;
+using Microsoft.AspNetCore.Http;
 
 namespace Microsoft.AspNetCore.Mvc
 {

+ 4 - 4
src/Http/Http.Extensions/src/PublicAPI.Unshipped.txt

@@ -89,10 +89,10 @@
 *REMOVED*~static Microsoft.AspNetCore.Http.SessionExtensions.GetString(this Microsoft.AspNetCore.Http.ISession session, string key) -> string
 *REMOVED*~static Microsoft.AspNetCore.Http.SessionExtensions.SetInt32(this Microsoft.AspNetCore.Http.ISession session, string key, int value) -> void
 *REMOVED*~static Microsoft.AspNetCore.Http.SessionExtensions.SetString(this Microsoft.AspNetCore.Http.ISession session, string key, string value) -> void
-Microsoft.AspNetCore.Http.Extensions.HttpValidationProblemDetails
-Microsoft.AspNetCore.Http.Extensions.HttpValidationProblemDetails.Errors.get -> System.Collections.Generic.IDictionary<string!, string![]!>!
-Microsoft.AspNetCore.Http.Extensions.HttpValidationProblemDetails.HttpValidationProblemDetails() -> void
-Microsoft.AspNetCore.Http.Extensions.HttpValidationProblemDetails.HttpValidationProblemDetails(System.Collections.Generic.IDictionary<string!, string![]!>! errors) -> void
+Microsoft.AspNetCore.Http.HttpValidationProblemDetails
+Microsoft.AspNetCore.Http.HttpValidationProblemDetails.Errors.get -> System.Collections.Generic.IDictionary<string!, string![]!>!
+Microsoft.AspNetCore.Http.HttpValidationProblemDetails.HttpValidationProblemDetails() -> void
+Microsoft.AspNetCore.Http.HttpValidationProblemDetails.HttpValidationProblemDetails(System.Collections.Generic.IDictionary<string!, string![]!>! errors) -> void
 Microsoft.AspNetCore.Http.Extensions.QueryBuilder.Add(string! key, System.Collections.Generic.IEnumerable<string!>! values) -> void
 Microsoft.AspNetCore.Http.Extensions.QueryBuilder.Add(string! key, string! value) -> void
 Microsoft.AspNetCore.Http.Extensions.QueryBuilder.GetEnumerator() -> System.Collections.Generic.IEnumerator<System.Collections.Generic.KeyValuePair<string!, string!>>!

+ 6 - 1
src/Http/Http.Results/src/ObjectResult.cs

@@ -37,6 +37,11 @@ namespace Microsoft.AspNetCore.Http.Result
         /// </summary>
         public int? StatusCode { get; set; }
 
+        /// <summary>
+        /// Gets the value for the <c>Content-Type</c> header.
+        /// </summary>
+        public string? ContentType { get; set; }
+
         public Task ExecuteAsync(HttpContext httpContext)
         {
             var loggerFactory = httpContext.RequestServices.GetRequiredService<ILoggerFactory>();
@@ -61,7 +66,7 @@ namespace Microsoft.AspNetCore.Http.Result
             }
 
             OnFormatting(httpContext);
-            return httpContext.Response.WriteAsJsonAsync(Value);
+            return httpContext.Response.WriteAsJsonAsync(Value, Value.GetType(), options: null, contentType: ContentType);
         }
 
         protected virtual void OnFormatting(HttpContext httpContext)

+ 11 - 3
src/Http/Http.Results/src/Results.cs

@@ -479,14 +479,19 @@ namespace Microsoft.AspNetCore.Http
             string? title = null,
             string? type = null)
         {
-            return new ObjectResult(new ProblemDetails
+            var problemDetails = new ProblemDetails
             {
                 Detail = detail,
                 Instance = instance,
                 Status = statusCode,
                 Title = title,
                 Type = type
-            });
+            };
+
+            return new ObjectResult(problemDetails)
+            {
+                ContentType = "application/problem+json",
+            };
         }
 
         /// <summary>
@@ -517,7 +522,10 @@ namespace Microsoft.AspNetCore.Http
                 Status = statusCode,
             };
 
-            return new ObjectResult(problemDetails);
+            return new ObjectResult(problemDetails)
+            {
+                ContentType = "application/problem+json",
+            };
         }
 
         /// <summary>

+ 1 - 2
src/Mvc/Mvc.Core/src/Infrastructure/ValidationProblemDetailsJsonConverter.cs

@@ -1,10 +1,9 @@
 // Copyright (c) .NET Foundation. All rights reserved.
 // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
 
-using System;
 using System.Text.Json;
 using System.Text.Json.Serialization;
-using Microsoft.AspNetCore.Http.Extensions;
+using Microsoft.AspNetCore.Http;
 
 namespace Microsoft.AspNetCore.Mvc.Infrastructure
 {

+ 1 - 3
src/Mvc/Mvc.Core/src/ValidationProblemDetails.cs

@@ -1,10 +1,8 @@
 // Copyright (c) .NET Foundation. All rights reserved.
 // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
 
-using System;
-using System.Collections.Generic;
 using System.Text.Json.Serialization;
-using Microsoft.AspNetCore.Http.Extensions;
+using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Mvc.Core;
 using Microsoft.AspNetCore.Mvc.Infrastructure;
 using Microsoft.AspNetCore.Mvc.ModelBinding;

+ 11 - 0
src/Mvc/test/Mvc.FunctionalTests/SimpleWithWebApplicationBuilderTests.cs

@@ -96,5 +96,16 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
             await response.AssertStatusCodeAsync(HttpStatusCode.MovedPermanently);
             Assert.Equal("/json", response.Headers.Location.ToString());
         }
+
+        [Fact]
+        public async Task ActionReturningProblemDetails_ConfiguresContentType()
+        {
+            // Act
+            var response = await Client.GetAsync("/problem");
+
+            // Assert
+            await response.AssertStatusCodeAsync(HttpStatusCode.InternalServerError);
+            Assert.Equal("application/problem+json", response.Content.Headers.ContentType.ToString());
+        }
     }
 }

+ 2 - 2
src/Mvc/test/WebSites/SimpleWebSiteWithWebApplicationBuilder/Program.cs

@@ -1,7 +1,6 @@
 // Copyright (c) .NET Foundation. All rights reserved.
 // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
 
-using Microsoft.AspNetCore.Builder;
 using static Microsoft.AspNetCore.Http.Results;
 
 var app = WebApplication.Create(args);
@@ -24,7 +23,8 @@ app.MapGet("/many-results", (int id) =>
     return Redirect("/json", permanent: true);
 });
 
-app.Run();
+app.MapGet("/problem", () => Results.Problem("Some problem"));
 
+app.Run();
 
 record Person(string Name, int Age);

+ 1 - 4
src/Shared/HttpValidationProblemDetailsJsonConverter.cs

@@ -1,13 +1,10 @@
 // Copyright (c) .NET Foundation. All rights reserved.
 // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
 
-
-using System;
-using System.Collections.Generic;
 using System.Text.Json;
 using System.Text.Json.Serialization;
 
-namespace Microsoft.AspNetCore.Http.Extensions
+namespace Microsoft.AspNetCore.Http
 {
     internal sealed class HttpValidationProblemDetailsJsonConverter : JsonConverter<HttpValidationProblemDetails>
     {

+ 1 - 3
src/Shared/ProblemDetailsJsonConverter.cs

@@ -1,14 +1,12 @@
 // Copyright (c) .NET Foundation. All rights reserved.
 // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
 
-
-using System;
 using System.Diagnostics.CodeAnalysis;
 using System.Text.Json;
 using System.Text.Json.Serialization;
 using Microsoft.AspNetCore.Mvc;
 
-namespace Microsoft.AspNetCore.Http.Extensions
+namespace Microsoft.AspNetCore.Http
 {
     internal sealed class ProblemDetailsJsonConverter : JsonConverter<ProblemDetails>
     {