Merge pull request #8537 from dotnet-maestro-bot/merge/release/2.2-to-master
[automated] Merge branch 'release/2.2' => 'master'
This commit is contained in:
commit
60325c8010
|
|
@ -15,12 +15,7 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer
|
|||
bool MethodMatches()
|
||||
{
|
||||
var methodNameMatchBehavior = GetNameMatchBehavior(conventionMethod);
|
||||
if (!IsNameMatch(methodInfo.Name, conventionMethod.Name, methodNameMatchBehavior))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return IsNameMatch(methodInfo.Name, conventionMethod.Name, methodNameMatchBehavior);
|
||||
}
|
||||
|
||||
bool ParametersMatch()
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
|
@ -84,21 +85,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
|||
throw new ArgumentNullException(nameof(result));
|
||||
}
|
||||
|
||||
// If the user sets the content type both on the ObjectResult (example: by Produces) and Response object,
|
||||
// then the one set on ObjectResult takes precedence over the Response object
|
||||
if (result.ContentTypes == null || result.ContentTypes.Count == 0)
|
||||
{
|
||||
var responseContentType = context.HttpContext.Response.ContentType;
|
||||
if (!string.IsNullOrEmpty(responseContentType))
|
||||
{
|
||||
if (result.ContentTypes == null)
|
||||
{
|
||||
result.ContentTypes = new MediaTypeCollection();
|
||||
}
|
||||
|
||||
result.ContentTypes.Add(responseContentType);
|
||||
}
|
||||
}
|
||||
InferContentTypes(context, result);
|
||||
|
||||
var objectType = result.DeclaredType;
|
||||
if (objectType == null || objectType == typeof(object))
|
||||
|
|
@ -113,8 +100,8 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
|||
result.Value);
|
||||
|
||||
var selectedFormatter = FormatterSelector.SelectFormatter(
|
||||
formatterContext,
|
||||
(IList<IOutputFormatter>)result.Formatters ?? Array.Empty<IOutputFormatter>(),
|
||||
formatterContext,
|
||||
(IList<IOutputFormatter>)result.Formatters ?? Array.Empty<IOutputFormatter>(),
|
||||
result.ContentTypes);
|
||||
if (selectedFormatter == null)
|
||||
{
|
||||
|
|
@ -130,5 +117,27 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
|||
result.OnFormatting(context);
|
||||
return selectedFormatter.WriteAsync(formatterContext);
|
||||
}
|
||||
|
||||
private static void InferContentTypes(ActionContext context, ObjectResult result)
|
||||
{
|
||||
Debug.Assert(result.ContentTypes != null);
|
||||
if (result.ContentTypes.Count != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If the user sets the content type both on the ObjectResult (example: by Produces) and Response object,
|
||||
// then the one set on ObjectResult takes precedence over the Response object
|
||||
var responseContentType = context.HttpContext.Response.ContentType;
|
||||
if (!string.IsNullOrEmpty(responseContentType))
|
||||
{
|
||||
result.ContentTypes.Add(responseContentType);
|
||||
}
|
||||
else if (result.Value is ProblemDetails)
|
||||
{
|
||||
result.ContentTypes.Add("application/problem+json");
|
||||
result.ContentTypes.Add("application/problem+xml");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,11 +11,13 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
{
|
||||
public class ObjectResult : ActionResult, IStatusCodeActionResult
|
||||
{
|
||||
private MediaTypeCollection _contentTypes;
|
||||
|
||||
public ObjectResult(object value)
|
||||
{
|
||||
Value = value;
|
||||
Formatters = new FormatterCollection<IOutputFormatter>();
|
||||
ContentTypes = new MediaTypeCollection();
|
||||
_contentTypes = new MediaTypeCollection();
|
||||
}
|
||||
|
||||
[ActionResultObjectValue]
|
||||
|
|
@ -23,7 +25,11 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
|
||||
public FormatterCollection<IOutputFormatter> Formatters { get; set; }
|
||||
|
||||
public MediaTypeCollection ContentTypes { get; set; }
|
||||
public MediaTypeCollection ContentTypes
|
||||
{
|
||||
get => _contentTypes;
|
||||
set => _contentTypes = value ?? throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
|
||||
public Type DeclaredType { get; set; }
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,32 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
|||
{
|
||||
public class ObjectResultExecutorTest
|
||||
{
|
||||
[Fact]
|
||||
public async Task ExecuteAsync_UsesSpecifiedContentType()
|
||||
{
|
||||
// Arrange
|
||||
var executor = CreateExecutor();
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var actionContext = new ActionContext() { HttpContext = httpContext };
|
||||
httpContext.Request.Headers[HeaderNames.Accept] = "application/xml"; // This will not be used
|
||||
httpContext.Response.ContentType = "text/json";
|
||||
|
||||
var result = new ObjectResult("input")
|
||||
{
|
||||
ContentTypes = { "text/xml", },
|
||||
};
|
||||
result.Formatters.Add(new TestXmlOutputFormatter());
|
||||
result.Formatters.Add(new TestJsonOutputFormatter());
|
||||
result.Formatters.Add(new TestStringOutputFormatter()); // This will be chosen based on the content type
|
||||
|
||||
// Act
|
||||
await executor.ExecuteAsync(actionContext, result);
|
||||
|
||||
// Assert
|
||||
MediaTypeAssert.Equal("text/xml; charset=utf-8", httpContext.Response.ContentType);
|
||||
}
|
||||
|
||||
// For this test case probably the most common use case is when there is a format mapping based
|
||||
// content type selected but the developer had set the content type on the Response.ContentType
|
||||
[Fact]
|
||||
|
|
@ -85,6 +111,74 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
|||
Assert.Equal(406, httpContext.Response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ExecuteAsync_ForProblemDetailsValue_UsesSpecifiedContentType()
|
||||
{
|
||||
// Arrange
|
||||
var executor = CreateExecutor();
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var actionContext = new ActionContext() { HttpContext = httpContext };
|
||||
httpContext.Response.ContentType = "application/json";
|
||||
|
||||
var result = new ObjectResult(new ProblemDetails())
|
||||
{
|
||||
ContentTypes = { "text/plain" },
|
||||
};
|
||||
result.Formatters.Add(new TestXmlOutputFormatter());
|
||||
result.Formatters.Add(new TestJsonOutputFormatter());
|
||||
result.Formatters.Add(new TestStringOutputFormatter()); // This will be chosen based on the content type
|
||||
|
||||
// Act
|
||||
await executor.ExecuteAsync(actionContext, result);
|
||||
|
||||
// Assert
|
||||
MediaTypeAssert.Equal("text/plain; charset=utf-8", httpContext.Response.ContentType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ExecuteAsync_ForProblemDetailsValue_UsesResponseContentType()
|
||||
{
|
||||
// Arrange
|
||||
var executor = CreateExecutor();
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var actionContext = new ActionContext() { HttpContext = httpContext };
|
||||
httpContext.Response.ContentType = "application/json";
|
||||
|
||||
var result = new ObjectResult(new ProblemDetails());
|
||||
result.Formatters.Add(new TestXmlOutputFormatter());
|
||||
result.Formatters.Add(new TestJsonOutputFormatter()); // This will be chosen based on the response content type
|
||||
result.Formatters.Add(new TestStringOutputFormatter());
|
||||
|
||||
// Act
|
||||
await executor.ExecuteAsync(actionContext, result);
|
||||
|
||||
// Assert
|
||||
MediaTypeAssert.Equal("application/json; charset=utf-8", httpContext.Response.ContentType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ExecuteAsync_NoContentTypeProvidedForProblemDetails_UsesDefaultContentTypes()
|
||||
{
|
||||
// Arrange
|
||||
var executor = CreateExecutor();
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var actionContext = new ActionContext() { HttpContext = httpContext };
|
||||
|
||||
var result = new ObjectResult(new ProblemDetails());
|
||||
result.Formatters.Add(new TestXmlOutputFormatter()); // This will be chosen based on the implicitly added content type
|
||||
result.Formatters.Add(new TestJsonOutputFormatter());
|
||||
result.Formatters.Add(new TestStringOutputFormatter());
|
||||
|
||||
// Act
|
||||
await executor.ExecuteAsync(actionContext, result);
|
||||
|
||||
// Assert
|
||||
MediaTypeAssert.Equal("application/problem+xml; charset=utf-8", httpContext.Response.ContentType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ExecuteAsync_NoFormatterFound_Returns406()
|
||||
{
|
||||
|
|
@ -310,6 +404,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
|||
{
|
||||
SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json"));
|
||||
SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/json"));
|
||||
SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/*+json"));
|
||||
|
||||
SupportedEncodings.Add(Encoding.UTF8);
|
||||
}
|
||||
|
|
@ -326,6 +421,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
|||
{
|
||||
SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/xml"));
|
||||
SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/xml"));
|
||||
SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/*+xml"));
|
||||
|
||||
SupportedEncodings.Add(Encoding.UTF8);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue