Skip to content

Commit 00846a2

Browse files
authored
Use ProblemDetails.Status to configure ObjectResult.StatusCode (#17565)
This was missed when fixing #14663.
1 parent bd7c89a commit 00846a2

File tree

4 files changed

+103
-6
lines changed

4 files changed

+103
-6
lines changed

src/Mvc/Mvc.Core/src/DependencyInjection/ApiBehaviorOptionsSetup.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,10 @@ internal static IActionResult ProblemDetailsInvalidModelStateResponse(ProblemDet
4242
}
4343
else
4444
{
45-
result = new ObjectResult(problemDetails);
45+
result = new ObjectResult(problemDetails)
46+
{
47+
StatusCode = problemDetails.Status,
48+
};
4649
}
4750
result.ContentTypes.Add("application/problem+json");
4851
result.ContentTypes.Add("application/problem+xml");

src/Mvc/Mvc.Core/src/ObjectResult.cs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,22 @@ public virtual void OnFormatting(ActionContext context)
5454
throw new ArgumentNullException(nameof(context));
5555
}
5656

57-
if (StatusCode.HasValue)
57+
if (Value is ProblemDetails details)
5858
{
59-
context.HttpContext.Response.StatusCode = StatusCode.Value;
60-
61-
if (Value is ProblemDetails details && !details.Status.HasValue)
59+
if (details.Status != null && StatusCode == null)
60+
{
61+
StatusCode = details.Status;
62+
}
63+
else if (details.Status == null && StatusCode != null)
6264
{
63-
details.Status = StatusCode.Value;
65+
details.Status = StatusCode;
6466
}
6567
}
68+
69+
if (StatusCode.HasValue)
70+
{
71+
context.HttpContext.Response.StatusCode = StatusCode.Value;
72+
}
6673
}
6774
}
6875
}

src/Mvc/Mvc.Core/test/DependencyInjection/ApiBehaviorOptionsSetupTest.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
using Microsoft.AspNetCore.Http;
88
using Microsoft.AspNetCore.Mvc;
99
using Microsoft.AspNetCore.Mvc.Infrastructure;
10+
using Microsoft.AspNetCore.Mvc.ModelBinding;
11+
using Moq;
1012
using Xunit;
1113

1214
namespace Microsoft.Extensions.DependencyInjection
@@ -70,6 +72,29 @@ public void ProblemDetailsInvalidModelStateResponse_UsesUserConfiguredLink()
7072
Assert.Equal(link, problemDetails.Type);
7173
}
7274

75+
[Fact]
76+
public void ProblemDetailsInvalidModelStateResponse_UsesProblemDetailsFactory()
77+
{
78+
// Arrange
79+
var actionContext = GetActionContext();
80+
var factory = Mock.Of<ProblemDetailsFactory>(m => m.CreateValidationProblemDetails(It.IsAny<HttpContext>(), It.IsAny<ModelStateDictionary>(), null, null, null, null, null) == new ValidationProblemDetails
81+
{
82+
Status = 422,
83+
});
84+
85+
// Act
86+
var result = ApiBehaviorOptionsSetup.ProblemDetailsInvalidModelStateResponse(factory, actionContext);
87+
88+
// Assert
89+
var objectResult = Assert.IsType<ObjectResult>(result);
90+
Assert.Equal(422, objectResult.StatusCode);
91+
Assert.Equal(new[] { "application/problem+json", "application/problem+xml" }, objectResult.ContentTypes.OrderBy(c => c));
92+
93+
var problemDetails = Assert.IsType<ValidationProblemDetails>(objectResult.Value);
94+
Assert.Equal(422, problemDetails.Status);
95+
Assert.Equal("One or more validation errors occurred.", problemDetails.Title);
96+
}
97+
7398
[Fact]
7499
public void ProblemDetailsInvalidModelStateResponse_SetsTraceId()
75100
{

src/Mvc/Mvc.Core/test/ObjectResultTests.cs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,68 @@ public async Task ObjectResult_ExecuteResultAsync_SetsProblemDetailsStatus()
9494
Assert.Equal(StatusCodes.Status422UnprocessableEntity, details.Status.Value);
9595
}
9696

97+
[Fact]
98+
public async Task ObjectResult_ExecuteResultAsync_GetsStatusCodeFromProblemDetails()
99+
{
100+
// Arrange
101+
var details = new ProblemDetails { Status = StatusCodes.Status413RequestEntityTooLarge, };
102+
103+
var result = new ObjectResult(details)
104+
{
105+
Formatters = new FormatterCollection<IOutputFormatter>()
106+
{
107+
new NoOpOutputFormatter(),
108+
},
109+
};
110+
111+
var actionContext = new ActionContext()
112+
{
113+
HttpContext = new DefaultHttpContext()
114+
{
115+
RequestServices = CreateServices(),
116+
}
117+
};
118+
119+
// Act
120+
await result.ExecuteResultAsync(actionContext);
121+
122+
// Assert
123+
Assert.Equal(StatusCodes.Status413RequestEntityTooLarge, details.Status.Value);
124+
Assert.Equal(StatusCodes.Status413RequestEntityTooLarge, result.StatusCode.Value);
125+
Assert.Equal(StatusCodes.Status413RequestEntityTooLarge, actionContext.HttpContext.Response.StatusCode);
126+
}
127+
128+
[Fact]
129+
public async Task ObjectResult_ExecuteResultAsync_ResultAndProblemDetailsHaveStatusCodes()
130+
{
131+
// Arrange
132+
var details = new ProblemDetails { Status = StatusCodes.Status422UnprocessableEntity, };
133+
134+
var result = new BadRequestObjectResult(details)
135+
{
136+
Formatters = new FormatterCollection<IOutputFormatter>()
137+
{
138+
new NoOpOutputFormatter(),
139+
},
140+
};
141+
142+
var actionContext = new ActionContext()
143+
{
144+
HttpContext = new DefaultHttpContext()
145+
{
146+
RequestServices = CreateServices(),
147+
}
148+
};
149+
150+
// Act
151+
await result.ExecuteResultAsync(actionContext);
152+
153+
// Assert
154+
Assert.Equal(StatusCodes.Status422UnprocessableEntity, details.Status.Value);
155+
Assert.Equal(StatusCodes.Status400BadRequest, result.StatusCode.Value);
156+
Assert.Equal(StatusCodes.Status400BadRequest, actionContext.HttpContext.Response.StatusCode);
157+
}
158+
97159
private static IServiceProvider CreateServices()
98160
{
99161
var services = new ServiceCollection();

0 commit comments

Comments
 (0)