[Fix for #1850]Produces, Consumes and ObjectResult throw if there is a match all content type.
This commit is contained in:
parent
6cc5cfeae2
commit
8e91c1ada6
|
|
@ -4,6 +4,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Microsoft.AspNet.Mvc.Core;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc
|
||||||
|
|
@ -146,11 +147,19 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
private List<MediaTypeHeaderValue> GetContentTypes(string firstArg, string[] args)
|
private List<MediaTypeHeaderValue> GetContentTypes(string firstArg, string[] args)
|
||||||
{
|
{
|
||||||
|
var completeArgs = new List<string>();
|
||||||
|
completeArgs.Add(firstArg);
|
||||||
|
completeArgs.AddRange(args);
|
||||||
var contentTypes = new List<MediaTypeHeaderValue>();
|
var contentTypes = new List<MediaTypeHeaderValue>();
|
||||||
contentTypes.Add(MediaTypeHeaderValue.Parse(firstArg));
|
foreach (var arg in completeArgs)
|
||||||
foreach (var item in args)
|
|
||||||
{
|
{
|
||||||
var contentType = MediaTypeHeaderValue.Parse(item);
|
var contentType = MediaTypeHeaderValue.Parse(arg);
|
||||||
|
if (contentType.MatchesAllSubTypes || contentType.MatchesAllTypes)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
Resources.FormatMatchAllContentTypeIsNotAllowed(arg));
|
||||||
|
}
|
||||||
|
|
||||||
contentTypes.Add(contentType);
|
contentTypes.Add(contentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,12 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Http;
|
using Microsoft.AspNet.Http;
|
||||||
|
using Microsoft.AspNet.Mvc.Core;
|
||||||
using Microsoft.Framework.DependencyInjection;
|
using Microsoft.Framework.DependencyInjection;
|
||||||
using Microsoft.Framework.OptionsModel;
|
using Microsoft.Framework.OptionsModel;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
|
|
@ -36,6 +38,8 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
public override async Task ExecuteResultAsync(ActionContext context)
|
public override async Task ExecuteResultAsync(ActionContext context)
|
||||||
{
|
{
|
||||||
|
// See if the list of content types added to this object result is valid.
|
||||||
|
ThrowIfUnsupportedContentType();
|
||||||
var formatters = GetDefaultFormatters(context);
|
var formatters = GetDefaultFormatters(context);
|
||||||
var formatterContext = new OutputFormatterContext()
|
var formatterContext = new OutputFormatterContext()
|
||||||
{
|
{
|
||||||
|
|
@ -218,6 +222,17 @@ namespace Microsoft.AspNet.Mvc
|
||||||
return selectedFormatter;
|
return selectedFormatter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ThrowIfUnsupportedContentType()
|
||||||
|
{
|
||||||
|
var matchAllContentType = ContentTypes?.FirstOrDefault(
|
||||||
|
contentType => contentType.MatchesAllSubTypes || contentType.MatchesAllTypes);
|
||||||
|
if (matchAllContentType != null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
Resources.FormatObjectResult_MatchAllContentType(matchAllContentType, nameof(ContentTypes)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static IEnumerable<MediaTypeHeaderValue> SortMediaTypeHeaderValues(
|
private static IEnumerable<MediaTypeHeaderValue> SortMediaTypeHeaderValues(
|
||||||
IEnumerable<MediaTypeHeaderValue> headerValues)
|
IEnumerable<MediaTypeHeaderValue> headerValues)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.AspNet.Mvc.Core;
|
||||||
using Microsoft.AspNet.Mvc.Description;
|
using Microsoft.AspNet.Mvc.Description;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
|
|
||||||
|
|
@ -15,7 +17,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
|
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
|
||||||
public class ProducesAttribute : ResultFilterAttribute, IApiResponseMetadataProvider
|
public class ProducesAttribute : ResultFilterAttribute, IApiResponseMetadataProvider
|
||||||
{
|
{
|
||||||
public ProducesAttribute(string contentType, params string[] additionalContentTypes)
|
public ProducesAttribute([NotNull] string contentType, params string[] additionalContentTypes)
|
||||||
{
|
{
|
||||||
ContentTypes = GetContentTypes(contentType, additionalContentTypes);
|
ContentTypes = GetContentTypes(contentType, additionalContentTypes);
|
||||||
}
|
}
|
||||||
|
|
@ -37,11 +39,19 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
private List<MediaTypeHeaderValue> GetContentTypes(string firstArg, string[] args)
|
private List<MediaTypeHeaderValue> GetContentTypes(string firstArg, string[] args)
|
||||||
{
|
{
|
||||||
|
var completeArgs = new List<string>();
|
||||||
|
completeArgs.Add(firstArg);
|
||||||
|
completeArgs.AddRange(args);
|
||||||
var contentTypes = new List<MediaTypeHeaderValue>();
|
var contentTypes = new List<MediaTypeHeaderValue>();
|
||||||
contentTypes.Add(MediaTypeHeaderValue.Parse(firstArg));
|
foreach (var arg in completeArgs)
|
||||||
foreach (var item in args)
|
|
||||||
{
|
{
|
||||||
var contentType = MediaTypeHeaderValue.Parse(item);
|
var contentType = MediaTypeHeaderValue.Parse(arg);
|
||||||
|
if (contentType.MatchesAllSubTypes || contentType.MatchesAllTypes)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
Resources.FormatMatchAllContentTypeIsNotAllowed(arg));
|
||||||
|
}
|
||||||
|
|
||||||
contentTypes.Add(contentType);
|
contentTypes.Add(contentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,38 @@ namespace Microsoft.AspNet.Mvc.Core
|
||||||
private static readonly ResourceManager _resourceManager
|
private static readonly ResourceManager _resourceManager
|
||||||
= new ResourceManager("Microsoft.AspNet.Mvc.Core.Resources", typeof(Resources).GetTypeInfo().Assembly);
|
= new ResourceManager("Microsoft.AspNet.Mvc.Core.Resources", typeof(Resources).GetTypeInfo().Assembly);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The argument '{0}' is invalid. Media types containing wildcards (*) are not supported.
|
||||||
|
/// </summary>
|
||||||
|
internal static string MatchAllContentTypeIsNotAllowed
|
||||||
|
{
|
||||||
|
get { return GetString("MatchAllContentTypeIsNotAllowed"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The argument '{0}' is invalid. Media types containing wildcards (*) are not supported.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatMatchAllContentTypeIsNotAllowed(object p0)
|
||||||
|
{
|
||||||
|
return string.Format(CultureInfo.CurrentCulture, GetString("MatchAllContentTypeIsNotAllowed"), p0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The content-type '{0}' added in the '{1}' property is invalid. Media types containing wildcards (*) are not supported.
|
||||||
|
/// </summary>
|
||||||
|
internal static string ObjectResult_MatchAllContentType
|
||||||
|
{
|
||||||
|
get { return GetString("ObjectResult_MatchAllContentType"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The content-type '{0}' added in the '{1}' property is invalid. Media types containing wildcards (*) are not supported.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatObjectResult_MatchAllContentType(object p0, object p1)
|
||||||
|
{
|
||||||
|
return string.Format(CultureInfo.CurrentCulture, GetString("ObjectResult_MatchAllContentType"), p0, p1);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The provided anti-forgery token failed a custom data check.
|
/// The provided anti-forgery token failed a custom data check.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -117,6 +117,12 @@
|
||||||
<resheader name="writer">
|
<resheader name="writer">
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</resheader>
|
</resheader>
|
||||||
|
<data name="MatchAllContentTypeIsNotAllowed" xml:space="preserve">
|
||||||
|
<value>The argument '{0}' is invalid. Media types which match all types or match all subtypes are not supported.</value>
|
||||||
|
</data>
|
||||||
|
<data name="ObjectResult_MatchAllContentType" xml:space="preserve">
|
||||||
|
<value>The content-type '{0}' added in the '{1}' property is invalid. Media types which match all types or match all subtypes are not supported.</value>
|
||||||
|
</data>
|
||||||
<data name="AntiForgeryToken_AdditionalDataCheckFailed" xml:space="preserve">
|
<data name="AntiForgeryToken_AdditionalDataCheckFailed" xml:space="preserve">
|
||||||
<value>The provided anti-forgery token failed a custom data check.</value>
|
<value>The provided anti-forgery token failed a custom data check.</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ using Microsoft.Framework.DependencyInjection.Fallback;
|
||||||
using Microsoft.Framework.OptionsModel;
|
using Microsoft.Framework.OptionsModel;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
using Moq;
|
using Moq;
|
||||||
|
using Newtonsoft.Json.Utilities;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Core.Test.ActionResults
|
namespace Microsoft.AspNet.Mvc.Core.Test.ActionResults
|
||||||
|
|
@ -616,6 +617,32 @@ namespace Microsoft.AspNet.Mvc.Core.Test.ActionResults
|
||||||
response.VerifySet(resp => resp.ContentType = expectedResponseContentType);
|
response.VerifySet(resp => resp.ContentType = expectedResponseContentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("application/*", "application/*")]
|
||||||
|
[InlineData("application/xml, application/*, application/json", "application/*")]
|
||||||
|
[InlineData("application/*, application/json", "application/*")]
|
||||||
|
|
||||||
|
[InlineData("*/*", "*/*")]
|
||||||
|
[InlineData("application/xml, */*, application/json", "*/*")]
|
||||||
|
[InlineData("*/*, application/json", "*/*")]
|
||||||
|
public async Task ObjectResult_MatchAllContentType_Throws(string content, string invalidContentType)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var contentTypes = content.Split(',');
|
||||||
|
var objectResult = new ObjectResult(new Person() { Name = "John" });
|
||||||
|
objectResult.ContentTypes = contentTypes.Select(contentType => MediaTypeHeaderValue.Parse(contentType))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
var exception = await Assert.ThrowsAsync<InvalidOperationException>(
|
||||||
|
() => objectResult.ExecuteResultAsync(null));
|
||||||
|
|
||||||
|
var expectedMessage = string.Format("The content-type '{0}' added in the 'ContentTypes' property is " +
|
||||||
|
"invalid. Media types which match all types or match all subtypes are not supported.",
|
||||||
|
invalidContentType);
|
||||||
|
Assert.Equal(expectedMessage, exception.Message);
|
||||||
|
}
|
||||||
|
|
||||||
private static ActionContext CreateMockActionContext(
|
private static ActionContext CreateMockActionContext(
|
||||||
HttpResponse response = null,
|
HttpResponse response = null,
|
||||||
string requestAcceptHeader = "application/*",
|
string requestAcceptHeader = "application/*",
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using Microsoft.AspNet.Http.Core;
|
using Microsoft.AspNet.Http.Core;
|
||||||
using Microsoft.AspNet.Routing;
|
using Microsoft.AspNet.Routing;
|
||||||
using Moq;
|
using Moq;
|
||||||
|
|
@ -26,6 +27,49 @@ namespace Microsoft.AspNet.Mvc
|
||||||
Assert.Equal(expectedMessage, exception.Message);
|
Assert.Equal(expectedMessage, exception.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("", "")]
|
||||||
|
[InlineData("application/xml,, application/json", "")]
|
||||||
|
[InlineData(", application/json", "")]
|
||||||
|
[InlineData("invalid", "invalid")]
|
||||||
|
[InlineData("application/xml,invalid, application/json", "invalid")]
|
||||||
|
[InlineData("invalid, application/json", "invalid")]
|
||||||
|
public void Constructor_UnparsableContentType_Throws(string content, string invalidContentType)
|
||||||
|
{
|
||||||
|
// Act
|
||||||
|
var contentTypes = content.Split(',').Select(contentType => contentType.Trim()).ToArray();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var ex = Assert.Throws<FormatException>(
|
||||||
|
() => new ConsumesAttribute(contentTypes[0], contentTypes.Skip(1).ToArray()));
|
||||||
|
Assert.Equal("Invalid value '" + (invalidContentType ?? "<null>") + "'.",
|
||||||
|
ex.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("application/*", "application/*")]
|
||||||
|
[InlineData("application/xml, application/*, application/json", "application/*")]
|
||||||
|
[InlineData("application/*, application/json", "application/*")]
|
||||||
|
|
||||||
|
[InlineData("*/*", "*/*")]
|
||||||
|
[InlineData("application/xml, */*, application/json", "*/*")]
|
||||||
|
[InlineData("*/*, application/json", "*/*")]
|
||||||
|
public void Constructor_InvalidContentType_Throws(string content, string invalidContentType)
|
||||||
|
{
|
||||||
|
// Act
|
||||||
|
var contentTypes = content.Split(',').Select(contentType => contentType.Trim()).ToArray();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var ex = Assert.Throws<InvalidOperationException>(
|
||||||
|
() => new ConsumesAttribute(contentTypes[0], contentTypes.Skip(1).ToArray()));
|
||||||
|
|
||||||
|
Assert.Equal(
|
||||||
|
string.Format("The argument '{0}' is invalid. "+
|
||||||
|
"Media types which match all types or match all subtypes are not supported.",
|
||||||
|
invalidContentType),
|
||||||
|
ex.Message);
|
||||||
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("application/json")]
|
[InlineData("application/json")]
|
||||||
[InlineData("application/json;Parameter1=12")]
|
[InlineData("application/json;Parameter1=12")]
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Http.Core;
|
using Microsoft.AspNet.Http.Core;
|
||||||
using Microsoft.AspNet.Routing;
|
using Microsoft.AspNet.Routing;
|
||||||
|
|
@ -13,7 +14,7 @@ namespace Microsoft.AspNet.Mvc.Test
|
||||||
public class ProducesAttributeTests
|
public class ProducesAttributeTests
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task ProducesContentAttribute_SetsContentType()
|
public async Task ProducesAttribute_SetsContentType()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var mediaType1 = MediaTypeHeaderValue.Parse("application/json");
|
var mediaType1 = MediaTypeHeaderValue.Parse("application/json");
|
||||||
|
|
@ -34,16 +35,45 @@ namespace Microsoft.AspNet.Mvc.Test
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("")]
|
[InlineData("", "")]
|
||||||
[InlineData(null)]
|
[InlineData("application/xml,, application/json", "")]
|
||||||
[InlineData("invalid")]
|
[InlineData(", application/json", "")]
|
||||||
public void ProducesAttribute_InvalidContentType_Throws(string content)
|
[InlineData("invalid", "invalid")]
|
||||||
|
[InlineData("application/xml,invalid, application/json", "invalid")]
|
||||||
|
[InlineData("invalid, application/json", "invalid")]
|
||||||
|
public void ProducesAttribute_UnParsableContentType_Throws(string content, string invalidContentType)
|
||||||
{
|
{
|
||||||
// Act & Assert
|
// Act
|
||||||
|
var contentTypes = content.Split(',').Select(contentType => contentType.Trim()).ToArray();
|
||||||
|
|
||||||
|
// Assert
|
||||||
var ex = Assert.Throws<FormatException>(
|
var ex = Assert.Throws<FormatException>(
|
||||||
() => new ProducesAttribute(content));
|
() => new ProducesAttribute(contentTypes[0], contentTypes.Skip(1).ToArray()));
|
||||||
Assert.Equal("Invalid value '" + (content ?? "<null>") + "'.",
|
Assert.Equal("Invalid value '" + (invalidContentType ?? "<null>") + "'.", ex.Message);
|
||||||
ex.Message);
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("application/*", "application/*")]
|
||||||
|
[InlineData("application/xml, application/*, application/json", "application/*")]
|
||||||
|
[InlineData("application/*, application/json", "application/*")]
|
||||||
|
|
||||||
|
[InlineData("*/*", "*/*")]
|
||||||
|
[InlineData("application/xml, */*, application/json", "*/*")]
|
||||||
|
[InlineData("*/*, application/json", "*/*")]
|
||||||
|
public void ProducesAttribute_InvalidContentType_Throws(string content, string invalidContentType)
|
||||||
|
{
|
||||||
|
// Act
|
||||||
|
var contentTypes = content.Split(',').Select(contentType => contentType.Trim()).ToArray();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var ex = Assert.Throws<InvalidOperationException>(
|
||||||
|
() => new ProducesAttribute(contentTypes[0], contentTypes.Skip(1).ToArray()));
|
||||||
|
|
||||||
|
Assert.Equal(
|
||||||
|
string.Format("The argument '{0}' is invalid. "+
|
||||||
|
"Media types which match all types or match all subtypes are not supported.",
|
||||||
|
invalidContentType),
|
||||||
|
ex.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ValidateMediaType(MediaTypeHeaderValue expectedMediaType, MediaTypeHeaderValue actualMediaType)
|
private static void ValidateMediaType(MediaTypeHeaderValue expectedMediaType, MediaTypeHeaderValue actualMediaType)
|
||||||
|
|
|
||||||
|
|
@ -597,63 +597,6 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||||
Assert.Equal(typeof(JsonOutputFormatter).FullName, applicationJson.FormatterType);
|
Assert.Equal(typeof(JsonOutputFormatter).FullName, applicationJson.FormatterType);
|
||||||
}
|
}
|
||||||
|
|
||||||
// uses [Produces("*/*")]
|
|
||||||
[Fact]
|
|
||||||
public async Task ApiExplorer_ResponseContentType_AllTypes()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var server = TestServer.Create(_provider, _app);
|
|
||||||
var client = server.CreateClient();
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var response = await client.GetAsync("http://localhost/ApiExplorerResponseContentType/AllTypes");
|
|
||||||
|
|
||||||
var body = await response.Content.ReadAsStringAsync();
|
|
||||||
var result = JsonConvert.DeserializeObject<List<ApiExplorerData>>(body);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
var description = Assert.Single(result);
|
|
||||||
|
|
||||||
var formats = description.SupportedResponseFormats;
|
|
||||||
Assert.Equal(4, formats.Count);
|
|
||||||
|
|
||||||
var textXml = Assert.Single(formats, f => f.MediaType == "text/xml");
|
|
||||||
Assert.Equal(typeof(XmlDataContractSerializerOutputFormatter).FullName, textXml.FormatterType);
|
|
||||||
var applicationXml = Assert.Single(formats, f => f.MediaType == "application/xml");
|
|
||||||
Assert.Equal(typeof(XmlDataContractSerializerOutputFormatter).FullName, applicationXml.FormatterType);
|
|
||||||
|
|
||||||
var textJson = Assert.Single(formats, f => f.MediaType == "text/json");
|
|
||||||
Assert.Equal(typeof(JsonOutputFormatter).FullName, textJson.FormatterType);
|
|
||||||
var applicationJson = Assert.Single(formats, f => f.MediaType == "application/json");
|
|
||||||
Assert.Equal(typeof(JsonOutputFormatter).FullName, applicationJson.FormatterType);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task ApiExplorer_ResponseContentType_Range()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var server = TestServer.Create(_provider, _app);
|
|
||||||
var client = server.CreateClient();
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var response = await client.GetAsync("http://localhost/ApiExplorerResponseContentType/Range");
|
|
||||||
|
|
||||||
var body = await response.Content.ReadAsStringAsync();
|
|
||||||
var result = JsonConvert.DeserializeObject<List<ApiExplorerData>>(body);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
var description = Assert.Single(result);
|
|
||||||
|
|
||||||
var formats = description.SupportedResponseFormats;
|
|
||||||
Assert.Equal(2, formats.Count);
|
|
||||||
|
|
||||||
var textXml = Assert.Single(formats, f => f.MediaType == "text/xml");
|
|
||||||
Assert.Equal(typeof(XmlDataContractSerializerOutputFormatter).FullName, textXml.FormatterType);
|
|
||||||
|
|
||||||
var textJson = Assert.Single(formats, f => f.MediaType == "text/json");
|
|
||||||
Assert.Equal(typeof(JsonOutputFormatter).FullName, textJson.FormatterType);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task ApiExplorer_ResponseContentType_Specific()
|
public async Task ApiExplorer_ResponseContentType_Specific()
|
||||||
{
|
{
|
||||||
|
|
@ -671,10 +614,13 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||||
var description = Assert.Single(result);
|
var description = Assert.Single(result);
|
||||||
|
|
||||||
var formats = description.SupportedResponseFormats;
|
var formats = description.SupportedResponseFormats;
|
||||||
Assert.Equal(1, formats.Count);
|
Assert.Equal(2, formats.Count);
|
||||||
|
|
||||||
var applicationJson = Assert.Single(formats, f => f.MediaType == "application/json");
|
var applicationJson = Assert.Single(formats, f => f.MediaType == "application/json");
|
||||||
Assert.Equal(typeof(JsonOutputFormatter).FullName, applicationJson.FormatterType);
|
Assert.Equal(typeof(JsonOutputFormatter).FullName, applicationJson.FormatterType);
|
||||||
|
|
||||||
|
var textJson = Assert.Single(formats, f => f.MediaType == "text/json");
|
||||||
|
Assert.Equal(typeof(JsonOutputFormatter).FullName, textJson.FormatterType);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||||
private readonly Action<IApplicationBuilder> _app = new Startup().Configure;
|
private readonly Action<IApplicationBuilder> _app = new Startup().Configure;
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task ProducesContentAttribute_SingleContentType_PicksTheFirstSupportedFormatter()
|
public async Task ProducesAttribute_SingleContentType_PicksTheFirstSupportedFormatter()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var server = TestServer.Create(_provider, _app);
|
var server = TestServer.Create(_provider, _app);
|
||||||
|
|
@ -40,7 +40,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task ProducesContentAttribute_MultipleContentTypes_RunsConnegToSelectFormatter()
|
public async Task ProducesAttribute_MultipleContentTypes_RunsConnegToSelectFormatter()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var server = TestServer.Create(_provider, _app);
|
var server = TestServer.Create(_provider, _app);
|
||||||
|
|
@ -58,7 +58,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task NoProducesContentAttribute_ActionReturningString_RunsUsingTextFormatter()
|
public async Task NoProducesAttribute_ActionReturningString_RunsUsingTextFormatter()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var server = TestServer.Create(_provider, _app);
|
var server = TestServer.Create(_provider, _app);
|
||||||
|
|
@ -76,7 +76,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task NoProducesContentAttribute_ActionReturningAnyObject_RunsUsingDefaultFormatters()
|
public async Task NoProducesAttribute_ActionReturningAnyObject_RunsUsingDefaultFormatters()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var server = TestServer.Create(_provider, _app);
|
var server = TestServer.Create(_provider, _app);
|
||||||
|
|
@ -132,7 +132,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task ProducesContentAttribute_OnAction_OverridesTheValueOnClass()
|
public async Task ProducesAttribute_OnAction_OverridesTheValueOnClass()
|
||||||
{
|
{
|
||||||
var server = TestServer.Create(_provider, _app);
|
var server = TestServer.Create(_provider, _app);
|
||||||
var client = server.CreateClient();
|
var client = server.CreateClient();
|
||||||
|
|
@ -152,7 +152,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task ProducesContentAttribute_OnDerivedClass_OverridesTheValueOnBaseClass()
|
public async Task ProducesAttribute_OnDerivedClass_OverridesTheValueOnBaseClass()
|
||||||
{
|
{
|
||||||
var server = TestServer.Create(_provider, _app);
|
var server = TestServer.Create(_provider, _app);
|
||||||
var client = server.CreateClient();
|
var client = server.CreateClient();
|
||||||
|
|
@ -171,7 +171,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task ProducesContentAttribute_OnDerivedAction_OverridesTheValueOnBaseClass()
|
public async Task ProducesAttribute_OnDerivedAction_OverridesTheValueOnBaseClass()
|
||||||
{
|
{
|
||||||
var server = TestServer.Create(_provider, _app);
|
var server = TestServer.Create(_provider, _app);
|
||||||
var client = server.CreateClient();
|
var client = server.CreateClient();
|
||||||
|
|
@ -189,7 +189,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task ProducesContentAttribute_OnDerivedAction_OverridesTheValueOnBaseAction()
|
public async Task ProducesAttribute_OnDerivedAction_OverridesTheValueOnBaseAction()
|
||||||
{
|
{
|
||||||
var server = TestServer.Create(_provider, _app);
|
var server = TestServer.Create(_provider, _app);
|
||||||
var client = server.CreateClient();
|
var client = server.CreateClient();
|
||||||
|
|
@ -207,7 +207,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task ProducesContentAttribute_OnDerivedClassAndAction_OverridesTheValueOnBaseClass()
|
public async Task ProducesAttribute_OnDerivedClassAndAction_OverridesTheValueOnBaseClass()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var server = TestServer.Create(_provider, _app);
|
var server = TestServer.Create(_provider, _app);
|
||||||
|
|
@ -224,8 +224,9 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||||
var body = await response.Content.ReadAsStringAsync();
|
var body = await response.Content.ReadAsStringAsync();
|
||||||
Assert.Equal(expectedBody, body);
|
Assert.Equal(expectedBody, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task ProducesContentAttribute_IsNotHonored_ForJsonResult()
|
public async Task ProducesAttribute_IsNotHonored_ForJsonResult()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var server = TestServer.Create(_provider, _app);
|
var server = TestServer.Create(_provider, _app);
|
||||||
|
|
|
||||||
|
|
@ -15,28 +15,14 @@ namespace ApiExplorerWebSite
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Produces("*/*")]
|
[Produces("application/json", "text/json")]
|
||||||
public Product AllTypes()
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet]
|
|
||||||
[Produces("text/*")]
|
|
||||||
public Product Range()
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet]
|
|
||||||
[Produces("application/json")]
|
|
||||||
public Product Specific()
|
public Product Specific()
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Produces("application/hal+json")]
|
[Produces("application/hal+json", "text/hal+json")]
|
||||||
public Product NoMatch()
|
public Product NoMatch()
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ using Microsoft.AspNet.Mvc;
|
||||||
|
|
||||||
namespace ApiExplorerWebSite
|
namespace ApiExplorerWebSite
|
||||||
{
|
{
|
||||||
[Produces("*/*", Type = typeof(Product))]
|
[Produces("application/json", Type = typeof(Product))]
|
||||||
[Route("ApiExplorerResponseTypeOverrideOnAction")]
|
[Route("ApiExplorerResponseTypeOverrideOnAction")]
|
||||||
public class ApiExplorerResponseTypeOverrideOnActionController : Controller
|
public class ApiExplorerResponseTypeOverrideOnActionController : Controller
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ namespace ApiExplorerWebSite
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Produces("*/*", Type = typeof(Product))]
|
[Produces("application/json", Type = typeof(Product))]
|
||||||
public object GetObject()
|
public object GetObject()
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,8 @@ namespace ConnegWebSite
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.UseErrorReporter();
|
||||||
|
|
||||||
// Add MVC to the request pipeline
|
// Add MVC to the request pipeline
|
||||||
app.UseMvc(routes =>
|
app.UseMvc(routes =>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue