Correct polarity of MediaTypeHeaderValue.IsSubsetOf()` checks and remove one conneg fallback

- aspnet/Mvc#3138 part 2/2
- request's Content-Type header must be a subset of what an `IInputFormatter` can consume
  - `[Consumes]` is similar
- what an `IOutputFormatter` produces must be a subset of the request's Accept header
  - `FormatFilter` and `ObjectResult` are similar
- `ObjectResult` no longer falls back to `Content-Type` header if no `Accept` value is acceptable
- left `WebApiCompatShim` code alone for consistency with down-level `System.Net.Http.Formatting`
- correct tests to match new behaviour
  - do not test `Accept` values containing a `charset` parameter; that case is not valid

WIP:
- four test failures; something about comparing media types w/ charset included
- why do some localization tests fail in VS?

nits:
- add `InputFormatterTests`
- add / update comments and doc comments
- correct xUnit attributes in `ActionResultTest`; odd it doesn't show up in command-line runs
This commit is contained in:
Doug Bunting 2015-10-13 15:18:11 -07:00
parent 2e2043f427
commit 03625c38af
17 changed files with 460 additions and 147 deletions

View File

@ -56,10 +56,10 @@ namespace Microsoft.AspNet.Mvc
MediaTypeHeaderValue requestContentType = null; MediaTypeHeaderValue requestContentType = null;
MediaTypeHeaderValue.TryParse(context.HttpContext.Request.ContentType, out requestContentType); MediaTypeHeaderValue.TryParse(context.HttpContext.Request.ContentType, out requestContentType);
// Only execute if this is the last filter before calling the action. // Confirm the request's content type is more specific than a media type this action supports e.g. OK
// This ensures that we only run the filter which is closest to the action. // if client sent "text/plain" data and this action supports "text/*".
if (requestContentType != null && if (requestContentType != null &&
!ContentTypes.Any(contentType => contentType.IsSubsetOf(requestContentType))) !ContentTypes.Any(contentType => requestContentType.IsSubsetOf(contentType)))
{ {
context.Result = new UnsupportedMediaTypeResult(); context.Result = new UnsupportedMediaTypeResult();
} }
@ -102,7 +102,9 @@ namespace Microsoft.AspNet.Mvc
return !isActionWithoutConsumeConstraintPresent; return !isActionWithoutConsumeConstraintPresent;
} }
if (ContentTypes.Any(c => c.IsSubsetOf(requestContentType))) // Confirm the request's content type is more specific than a media type this action supports e.g. OK
// if client sent "text/plain" data and this action supports "text/*".
if (ContentTypes.Any(contentType => requestContentType.IsSubsetOf(contentType)))
{ {
return true; return true;
} }

View File

@ -183,7 +183,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
_cursor = new FilterCursor(_filters); _cursor = new FilterCursor(_filters);
ActionContext.ModelState.MaxAllowedErrors = _maxModelValidationErrors; ActionContext.ModelState.MaxAllowedErrors = _maxModelValidationErrors;
await InvokeAllAuthorizationFiltersAsync(); await InvokeAllAuthorizationFiltersAsync();
// If Authorization Filters return a result, it's a short circuit because // If Authorization Filters return a result, it's a short circuit because
@ -663,7 +663,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
"Microsoft.AspNet.Mvc.BeforeActionMethod", "Microsoft.AspNet.Mvc.BeforeActionMethod",
new new
{ {
actionContext = ActionContext, actionContext = ActionContext,
arguments = _actionExecutingContext.ActionArguments, arguments = _actionExecutingContext.ActionArguments,
controller = _actionExecutingContext.Controller controller = _actionExecutingContext.Controller
}); });

View File

@ -13,7 +13,7 @@ using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNet.Mvc.Formatters namespace Microsoft.AspNet.Mvc.Formatters
{ {
/// <summary> /// <summary>
/// A filter which will use the format value in the route data or query string to set the content type on an /// A filter which will use the format value in the route data or query string to set the content type on an
/// <see cref="ObjectResult" /> returned from an action. /// <see cref="ObjectResult" /> returned from an action.
/// </summary> /// </summary>
public class FormatFilter : IFormatFilter, IResourceFilter, IResultFilter public class FormatFilter : IFormatFilter, IResourceFilter, IResultFilter
@ -48,13 +48,13 @@ namespace Microsoft.AspNet.Mvc.Formatters
public MediaTypeHeaderValue ContentType { get; } public MediaTypeHeaderValue ContentType { get; }
/// <summary> /// <summary>
/// <c>true</c> if the current <see cref="FormatFilter"/> is active and will execute. /// <c>true</c> if the current <see cref="FormatFilter"/> is active and will execute.
/// </summary> /// </summary>
public bool IsActive { get; } public bool IsActive { get; }
/// <summary> /// <summary>
/// As a <see cref="IResourceFilter"/>, this filter looks at the request and rejects it before going ahead if /// As a <see cref="IResourceFilter"/>, this filter looks at the request and rejects it before going ahead if
/// 1. The format in the request doesnt match any format in the map. /// 1. The format in the request does not match any format in the map.
/// 2. If there is a conflicting producesFilter. /// 2. If there is a conflicting producesFilter.
/// </summary> /// </summary>
/// <param name="context">The <see cref="ResourceExecutingContext"/>.</param> /// <param name="context">The <see cref="ResourceExecutingContext"/>.</param>
@ -67,7 +67,8 @@ namespace Microsoft.AspNet.Mvc.Formatters
if (!IsActive) if (!IsActive)
{ {
return; // no format specified by user, so the filter is muted // no format specified by user, so the filter is muted
return;
} }
if (ContentType == null) if (ContentType == null)
@ -77,19 +78,22 @@ namespace Microsoft.AspNet.Mvc.Formatters
return; return;
} }
// Determine media types this action supports.
var responseTypeFilters = context.Filters.OfType<IApiResponseMetadataProvider>(); var responseTypeFilters = context.Filters.OfType<IApiResponseMetadataProvider>();
var contentTypes = new List<MediaTypeHeaderValue>(); var supportedMediaTypes = new List<MediaTypeHeaderValue>();
foreach (var filter in responseTypeFilters) foreach (var filter in responseTypeFilters)
{ {
filter.SetContentTypes(contentTypes); filter.SetContentTypes(supportedMediaTypes);
} }
if (contentTypes.Count != 0) // Check if support is adequate for requested media type.
if (supportedMediaTypes.Count != 0)
{ {
// We need to check if the action can generate the content type the user asked for. If it cannot, exit // We need to check if the action can generate the content type the user asked for. That is, treat the
// here with not found result. // request's format and IApiResponseMetadataProvider-provided content types similarly to an Accept
if (!contentTypes.Any(c => ContentType.IsSubsetOf(c))) // header and an output formatter's SupportedMediaTypes: Confirm action supports a more specific media
// type than requested e.g. OK if "text/*" requested and action supports "text/plain".
if (!supportedMediaTypes.Any(contentType => contentType.IsSubsetOf(ContentType)))
{ {
context.Result = new HttpNotFoundResult(); context.Result = new HttpNotFoundResult();
} }

View File

@ -62,12 +62,17 @@ namespace Microsoft.AspNet.Mvc.Formatters
var contentType = context.HttpContext.Request.ContentType; var contentType = context.HttpContext.Request.ContentType;
MediaTypeHeaderValue requestContentType; MediaTypeHeaderValue requestContentType;
if (!MediaTypeHeaderValue.TryParse(contentType, out requestContentType)) if (!MediaTypeHeaderValue.TryParse(contentType, out requestContentType) || requestContentType == null)
{ {
return false; return false;
} }
return SupportedMediaTypes.Any(supportedMediaType => supportedMediaType.IsSubsetOf(requestContentType)); // Confirm the request's content type is more specific than a media type this formatter supports e.g. OK if
// client sent "text/plain" data and this formatter supports "text/*".
return SupportedMediaTypes.Any(supportedMediaType =>
{
return requestContentType.IsSubsetOf(supportedMediaType);
});
} }
/// <summary> /// <summary>

View File

@ -77,6 +77,8 @@ namespace Microsoft.AspNet.Mvc.Formatters
{ {
List<MediaTypeHeaderValue> mediaTypes = null; List<MediaTypeHeaderValue> mediaTypes = null;
// Confirm this formatter supports a more specific media type than requested e.g. OK if "text/*"
// requested and formatter supports "text/plain". Treat contentType like it came from an Accept header.
foreach (var mediaType in _supportedMediaTypes) foreach (var mediaType in _supportedMediaTypes)
{ {
if (mediaType.IsSubsetOf(contentType)) if (mediaType.IsSubsetOf(contentType))
@ -119,8 +121,7 @@ namespace Microsoft.AspNet.Mvc.Formatters
{ {
var requestCharset = requestContentType.Charset; var requestCharset = requestContentType.Charset;
encoding = SupportedEncodings.FirstOrDefault( encoding = SupportedEncodings.FirstOrDefault(
supportedEncoding => supportedEncoding => requestCharset.Equals(supportedEncoding.WebName));
requestCharset.Equals(supportedEncoding.WebName));
} }
} }
@ -151,10 +152,11 @@ namespace Microsoft.AspNet.Mvc.Formatters
} }
else else
{ {
// Since supportedMedia Type is going to be more specific check if supportedMediaType is a subset // Confirm this formatter supports a more specific media type than requested e.g. OK if "text/*"
// of the content type which is typically what we get on acceptHeader. // requested and formatter supports "text/plain". contentType is typically what we got in an Accept
mediaType = SupportedMediaTypes // header.
.FirstOrDefault(supportedMediaType => supportedMediaType.IsSubsetOf(contentType)); mediaType = SupportedMediaTypes.FirstOrDefault(
supportedMediaType => supportedMediaType.IsSubsetOf(contentType));
} }
if (mediaType != null) if (mediaType != null)
@ -201,11 +203,11 @@ namespace Microsoft.AspNet.Mvc.Formatters
// Copy the media type as we don't want it to affect the next request // Copy the media type as we don't want it to affect the next request
selectedMediaType = selectedMediaType.Copy(); selectedMediaType = selectedMediaType.Copy();
// Not text-based media types will use an encoding/charset - binary formats just ignore it. We want to // Note text-based media types will use an encoding/charset - binary formats just ignore it. We want to
// make this class work with media types that use encodings, and those that don't. // make this class work with media types that use encodings, and those that don't.
// //
// The default implementation of SelectCharacterEncoding will read from the list of SupportedEncodings // The default implementation of SelectCharacterEncoding will read from the list of SupportedEncodings
// and will always choose a default encoding if any are supported. So, the only cases where the // and will always choose a default encoding if any are supported. So, the only cases where the
// selectedEncoding can be null are: // selectedEncoding can be null are:
// //
// 1). No supported encodings - we assume this is a non-text format // 1). No supported encodings - we assume this is a non-text format
@ -237,21 +239,17 @@ namespace Microsoft.AspNet.Mvc.Formatters
if (acceptCharsetHeaders != null && acceptCharsetHeaders.Count > 0) if (acceptCharsetHeaders != null && acceptCharsetHeaders.Count > 0)
{ {
var sortedAcceptCharsetHeaders = acceptCharsetHeaders var sortedAcceptCharsetHeaders = acceptCharsetHeaders
.Where(acceptCharset => .Where(acceptCharset => acceptCharset.Quality != HeaderQuality.NoMatch)
acceptCharset.Quality != HeaderQuality.NoMatch) .OrderByDescending(m => m, StringWithQualityHeaderValueComparer.QualityComparer);
.OrderByDescending(
m => m, StringWithQualityHeaderValueComparer.QualityComparer);
foreach (var acceptCharset in sortedAcceptCharsetHeaders) foreach (var acceptCharset in sortedAcceptCharsetHeaders)
{ {
var charset = acceptCharset.Value; var charset = acceptCharset.Value;
if (!string.IsNullOrWhiteSpace(charset)) if (!string.IsNullOrWhiteSpace(charset))
{ {
var encoding = SupportedEncodings.FirstOrDefault( var encoding = SupportedEncodings.FirstOrDefault(supportedEncoding =>
supportedEncoding => charset.Equals(supportedEncoding.WebName, StringComparison.OrdinalIgnoreCase) ||
charset.Equals(supportedEncoding.WebName, charset.Equals("*", StringComparison.Ordinal));
StringComparison.OrdinalIgnoreCase) ||
charset.Equals("*", StringComparison.Ordinal));
if (encoding != null) if (encoding != null)
{ {
return encoding; return encoding;

View File

@ -86,17 +86,15 @@ namespace Microsoft.AspNet.Mvc
{ {
var logger = formatterContext.HttpContext.RequestServices.GetRequiredService<ILogger<ObjectResult>>(); var logger = formatterContext.HttpContext.RequestServices.GetRequiredService<ILogger<ObjectResult>>();
// Check if any content-type was explicitly set (for example, via ProducesAttribute // Check if any content-type was explicitly set (for example, via ProducesAttribute
// or Url path extension mapping). If yes, then ignore content-negotiation and use this content-type. // or URL path extension mapping). If yes, then ignore content-negotiation and use this content-type.
if (ContentTypes.Count == 1) if (ContentTypes.Count == 1)
{ {
logger.LogVerbose( logger.LogVerbose(
"Skipped content negotiation as content type '{ContentType}' is explicitly set for the response.", "Skipped content negotiation as content type '{ContentType}' is explicitly set for the response.",
ContentTypes[0]); ContentTypes[0]);
return SelectFormatterUsingAnyAcceptableContentType(formatterContext, return SelectFormatterUsingAnyAcceptableContentType(formatterContext, formatters, ContentTypes);
formatters,
ContentTypes);
} }
var sortedAcceptHeaderMediaTypes = GetSortedAcceptHeaderMediaTypes(formatterContext); var sortedAcceptHeaderMediaTypes = GetSortedAcceptHeaderMediaTypes(formatterContext);
@ -106,11 +104,7 @@ namespace Microsoft.AspNet.Mvc
{ {
// Check if we have enough information to do content-negotiation, otherwise get the first formatter // Check if we have enough information to do content-negotiation, otherwise get the first formatter
// which can write the type. // which can write the type.
MediaTypeHeaderValue requestContentType = null; if (!sortedAcceptHeaderMediaTypes.Any())
MediaTypeHeaderValue.TryParse(
formatterContext.HttpContext.Request.ContentType,
out requestContentType);
if (!sortedAcceptHeaderMediaTypes.Any() && requestContentType == null)
{ {
logger.LogVerbose("No information found on request to perform content negotiation."); logger.LogVerbose("No information found on request to perform content negotiation.");
@ -122,25 +116,12 @@ namespace Microsoft.AspNet.Mvc
// //
// 1. Select based on sorted accept headers. // 1. Select based on sorted accept headers.
if (sortedAcceptHeaderMediaTypes.Any()) selectedFormatter = SelectFormatterUsingSortedAcceptHeaders(
{ formatterContext,
selectedFormatter = SelectFormatterUsingSortedAcceptHeaders( formatters,
formatterContext, sortedAcceptHeaderMediaTypes);
formatters,
sortedAcceptHeaderMediaTypes);
}
// 2. No formatter was found based on accept headers, fall back on request Content-Type header. // 2. No formatter was found based on Accept header. Fallback to type-based match.
if (selectedFormatter == null && requestContentType != null)
{
selectedFormatter = SelectFormatterUsingAnyAcceptableContentType(
formatterContext,
formatters,
new[] { requestContentType });
}
// 3. No formatter was found based on Accept and request Content-Type headers, so
// fallback on type based match.
if (selectedFormatter == null) if (selectedFormatter == null)
{ {
logger.LogVerbose("Could not find an output formatter based on content negotiation."); logger.LogVerbose("Could not find an output formatter based on content negotiation.");
@ -157,15 +138,15 @@ namespace Microsoft.AspNet.Mvc
if (sortedAcceptHeaderMediaTypes.Any()) if (sortedAcceptHeaderMediaTypes.Any())
{ {
// Filter and remove accept headers which cannot support any of the user specified content types. // Filter and remove accept headers which cannot support any of the user specified content types.
// That is, confirm this result supports a more specific media type than requested e.g. OK if
// "text/*" requested and result supports "text/plain".
var filteredAndSortedAcceptHeaders = sortedAcceptHeaderMediaTypes var filteredAndSortedAcceptHeaders = sortedAcceptHeaderMediaTypes
.Where(acceptHeader => .Where(acceptHeader => ContentTypes.Any(contentType => contentType.IsSubsetOf(acceptHeader)));
ContentTypes.Any(contentType =>
contentType.IsSubsetOf(acceptHeader)));
selectedFormatter = SelectFormatterUsingSortedAcceptHeaders( selectedFormatter = SelectFormatterUsingSortedAcceptHeaders(
formatterContext, formatterContext,
formatters, formatters,
filteredAndSortedAcceptHeaders); filteredAndSortedAcceptHeaders);
} }
if (selectedFormatter == null) if (selectedFormatter == null)
@ -177,9 +158,9 @@ namespace Microsoft.AspNet.Mvc
// In any of these cases, if the user has specified content types, // In any of these cases, if the user has specified content types,
// do a last effort to find a formatter which can write any of the user specified content type. // do a last effort to find a formatter which can write any of the user specified content type.
selectedFormatter = SelectFormatterUsingAnyAcceptableContentType( selectedFormatter = SelectFormatterUsingAnyAcceptableContentType(
formatterContext, formatterContext,
formatters, formatters,
ContentTypes); ContentTypes);
} }
} }
@ -202,9 +183,9 @@ namespace Microsoft.AspNet.Mvc
} }
public virtual IOutputFormatter SelectFormatterUsingSortedAcceptHeaders( public virtual IOutputFormatter SelectFormatterUsingSortedAcceptHeaders(
OutputFormatterContext formatterContext, OutputFormatterContext formatterContext,
IEnumerable<IOutputFormatter> formatters, IEnumerable<IOutputFormatter> formatters,
IEnumerable<MediaTypeHeaderValue> sortedAcceptHeaders) IEnumerable<MediaTypeHeaderValue> sortedAcceptHeaders)
{ {
IOutputFormatter selectedFormatter = null; IOutputFormatter selectedFormatter = null;
foreach (var contentType in sortedAcceptHeaders) foreach (var contentType in sortedAcceptHeaders)
@ -212,8 +193,7 @@ namespace Microsoft.AspNet.Mvc
// Loop through each of the formatters and see if any one will support this // Loop through each of the formatters and see if any one will support this
// mediaType Value. // mediaType Value.
selectedFormatter = formatters.FirstOrDefault( selectedFormatter = formatters.FirstOrDefault(
formatter => formatter => formatter.CanWriteResult(formatterContext, contentType));
formatter.CanWriteResult(formatterContext, contentType));
if (selectedFormatter != null) if (selectedFormatter != null)
{ {
// we found our match. // we found our match.
@ -225,15 +205,14 @@ namespace Microsoft.AspNet.Mvc
} }
public virtual IOutputFormatter SelectFormatterUsingAnyAcceptableContentType( public virtual IOutputFormatter SelectFormatterUsingAnyAcceptableContentType(
OutputFormatterContext formatterContext, OutputFormatterContext formatterContext,
IEnumerable<IOutputFormatter> formatters, IEnumerable<IOutputFormatter> formatters,
IEnumerable<MediaTypeHeaderValue> acceptableContentTypes) IEnumerable<MediaTypeHeaderValue> acceptableContentTypes)
{ {
var selectedFormatter = formatters.FirstOrDefault( var selectedFormatter = formatters.FirstOrDefault(
formatter => formatter => acceptableContentTypes.Any(
acceptableContentTypes contentType => formatter.CanWriteResult(formatterContext, contentType)));
.Any(contentType =>
formatter.CanWriteResult(formatterContext, contentType)));
return selectedFormatter; return selectedFormatter;
} }
@ -264,7 +243,7 @@ namespace Microsoft.AspNet.Mvc
if (respectAcceptHeader) if (respectAcceptHeader)
{ {
sortedAcceptHeaderMediaTypes = SortMediaTypeHeaderValues(incomingAcceptHeaderMediaTypes) sortedAcceptHeaderMediaTypes = SortMediaTypeHeaderValues(incomingAcceptHeaderMediaTypes)
.Where(header => header.Quality != HeaderQuality.NoMatch); .Where(header => header.Quality != HeaderQuality.NoMatch);
} }
return sortedAcceptHeaderMediaTypes; return sortedAcceptHeaderMediaTypes;
@ -286,9 +265,9 @@ namespace Microsoft.AspNet.Mvc
{ {
// Use OrderBy() instead of Array.Sort() as it performs fewer comparisons. In this case the comparisons // Use OrderBy() instead of Array.Sort() as it performs fewer comparisons. In this case the comparisons
// are quite expensive so OrderBy() performs better. // are quite expensive so OrderBy() performs better.
return headerValues.OrderByDescending(headerValue => return headerValues.OrderByDescending(
headerValue, headerValue => headerValue,
MediaTypeHeaderValueComparer.QualityComparer); MediaTypeHeaderValueComparer.QualityComparer);
} }
private IEnumerable<IOutputFormatter> GetDefaultFormatters(ActionContext context) private IEnumerable<IOutputFormatter> GetDefaultFormatters(ActionContext context)
@ -302,7 +281,7 @@ namespace Microsoft.AspNet.Mvc
.GetRequiredService<IActionBindingContextAccessor>() .GetRequiredService<IActionBindingContextAccessor>()
.ActionBindingContext; .ActionBindingContext;
// In scenarios where there is a resource filter which directly shortcircuits using an ObjectResult. // In scenarios where there is a resource filter which directly short-circuits using an ObjectResult.
// actionBindingContext is not setup yet and is null. // actionBindingContext is not setup yet and is null.
if (actionBindingContext == null) if (actionBindingContext == null)
{ {

View File

@ -0,0 +1,292 @@
// 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.Threading.Tasks;
using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.Net.Http.Headers;
using Xunit;
namespace Microsoft.AspNet.Mvc.Formatters
{
public class InputFormatterTest
{
private class CatchAllFormatter : TestFormatter
{
public CatchAllFormatter()
{
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("*/*"));
}
}
[Theory]
[InlineData("application/mathml-content+xml")]
[InlineData("application/mathml-presentation+xml")]
[InlineData("application/mathml+xml; undefined=ignored")]
[InlineData("application/octet-stream; padding=3")]
[InlineData("application/xml")]
[InlineData("application/xml-dtd; undefined=ignored")]
[InlineData("multipart/mixed; boundary=gc0p4Jq0M2Yt08j34c0p")]
[InlineData("multipart/mixed; boundary=gc0p4Jq0M2Yt08j34c0p; undefined=ignored")]
[InlineData("text/html")]
public void CatchAll_CanRead_ReturnsTrueForSupportedMediaTypes(string requestContentType)
{
// Arrange
var formatter = new CatchAllFormatter();
var httpContext = new DefaultHttpContext();
httpContext.Request.ContentType = requestContentType;
var context = new InputFormatterContext(
httpContext,
modelName: string.Empty,
modelState: new ModelStateDictionary(),
modelType: typeof(void));
// Act
var result = formatter.CanRead(context);
// Assert
Assert.True(result);
}
private class MultipartFormatter : TestFormatter
{
public MultipartFormatter()
{
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("multipart/*"));
}
}
[Theory]
[InlineData("multipart/mixed; boundary=gc0p4Jq0M2Yt08j34c0p")]
[InlineData("multipart/mixed; boundary=gc0p4Jq0M2Yt08j34c0p; undefined=ignored")]
public void MultipartFormatter_CanRead_ReturnsTrueForSupportedMediaTypes(string requestContentType)
{
// Arrange
var formatter = new MultipartFormatter();
var httpContext = new DefaultHttpContext();
httpContext.Request.ContentType = requestContentType;
var context = new InputFormatterContext(
httpContext,
modelName: string.Empty,
modelState: new ModelStateDictionary(),
modelType: typeof(void));
// Act
var result = formatter.CanRead(context);
// Assert
Assert.True(result);
}
[Theory]
[InlineData("application/mathml-content+xml")]
[InlineData("application/mathml-presentation+xml")]
[InlineData("application/mathml+xml; undefined=ignored")]
[InlineData("application/octet-stream; padding=3")]
[InlineData("application/xml")]
[InlineData("application/xml-dtd; undefined=ignored")]
[InlineData("text/html")]
public void MultipartFormatter_CanRead_ReturnsFalseForUnsupportedMediaTypes(string requestContentType)
{
// Arrange
var formatter = new MultipartFormatter();
var httpContext = new DefaultHttpContext();
httpContext.Request.ContentType = requestContentType;
var context = new InputFormatterContext(
httpContext,
modelName: string.Empty,
modelState: new ModelStateDictionary(),
modelType: typeof(void));
// Act
var result = formatter.CanRead(context);
// Assert
Assert.False(result);
}
private class MultipartMixedFormatter : TestFormatter
{
public MultipartMixedFormatter()
{
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("multipart/mixed"));
}
}
[Theory]
[InlineData("multipart/mixed; boundary=gc0p4Jq0M2Yt08j34c0p")]
[InlineData("multipart/mixed; boundary=gc0p4Jq0M2Yt08j34c0p; undefined=ignored")]
public void MultipartMixedFormatter_CanRead_ReturnsTrueForSupportedMediaTypes(string requestContentType)
{
// Arrange
var formatter = new MultipartMixedFormatter();
var httpContext = new DefaultHttpContext();
httpContext.Request.ContentType = requestContentType;
var context = new InputFormatterContext(
httpContext,
modelName: string.Empty,
modelState: new ModelStateDictionary(),
modelType: typeof(void));
// Act
var result = formatter.CanRead(context);
// Assert
Assert.True(result);
}
[Theory]
[InlineData("application/mathml-content+xml")]
[InlineData("application/mathml-presentation+xml")]
[InlineData("application/mathml+xml; undefined=ignored")]
[InlineData("application/octet-stream; padding=3")]
[InlineData("application/xml")]
[InlineData("application/xml-dtd; undefined=ignored")]
[InlineData("text/html")]
public void MultipartMixedFormatter_CanRead_ReturnsFalseForUnsupportedMediaTypes(string requestContentType)
{
// Arrange
var formatter = new MultipartMixedFormatter();
var httpContext = new DefaultHttpContext();
httpContext.Request.ContentType = requestContentType;
var context = new InputFormatterContext(
httpContext,
modelName: string.Empty,
modelState: new ModelStateDictionary(),
modelType: typeof(void));
// Act
var result = formatter.CanRead(context);
// Assert
Assert.False(result);
}
private class MathMLFormatter : TestFormatter
{
public MathMLFormatter()
{
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/mathml-content+xml"));
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/mathml-presentation+xml"));
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/mathml+xml"));
}
}
[Theory]
[InlineData("application/mathml-content+xml")]
[InlineData("application/mathml-presentation+xml")]
[InlineData("application/mathml+xml; undefined=ignored")]
public void MathMLFormatter_CanRead_ReturnsTrueForSupportedMediaTypes(string requestContentType)
{
// Arrange
var formatter = new MathMLFormatter();
var httpContext = new DefaultHttpContext();
httpContext.Request.ContentType = requestContentType;
var context = new InputFormatterContext(
httpContext,
modelName: string.Empty,
modelState: new ModelStateDictionary(),
modelType: typeof(void));
// Act
var result = formatter.CanRead(context);
// Assert
Assert.True(result);
}
[Theory]
[InlineData("application/octet-stream; padding=3")]
[InlineData("application/xml")]
[InlineData("application/xml-dtd; undefined=ignored")]
[InlineData("multipart/mixed; boundary=gc0p4Jq0M2Yt08j34c0p")]
[InlineData("multipart/mixed; boundary=gc0p4Jq0M2Yt08j34c0p; undefined=ignored")]
[InlineData("text/html")]
public void MathMLFormatter_CanRead_ReturnsFalseForUnsupportedMediaTypes(string requestContentType)
{
// Arrange
var formatter = new MathMLFormatter();
var httpContext = new DefaultHttpContext();
httpContext.Request.ContentType = requestContentType;
var context = new InputFormatterContext(
httpContext,
modelName: string.Empty,
modelState: new ModelStateDictionary(),
modelType: typeof(void));
// Act
var result = formatter.CanRead(context);
// Assert
Assert.False(result);
}
// IsSubsetOf does not follow XML media type conventions. This formatter does not support "application/*+xml".
private class XmlFormatter : TestFormatter
{
public XmlFormatter()
{
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/xml"));
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/xml"));
}
}
[Theory]
[InlineData("application/xml")]
public void XMLFormatter_CanRead_ReturnsTrueForSupportedMediaTypes(string requestContentType)
{
// Arrange
var formatter = new XmlFormatter();
var httpContext = new DefaultHttpContext();
httpContext.Request.ContentType = requestContentType;
var context = new InputFormatterContext(
httpContext,
modelName: string.Empty,
modelState: new ModelStateDictionary(),
modelType: typeof(void));
// Act
var result = formatter.CanRead(context);
// Assert
Assert.True(result);
}
[Theory]
[InlineData("application/mathml-content+xml")]
[InlineData("application/mathml-presentation+xml")]
[InlineData("application/mathml+xml; undefined=ignored")]
[InlineData("application/octet-stream; padding=3")]
[InlineData("application/xml-dtd; undefined=ignored")]
[InlineData("multipart/mixed; boundary=gc0p4Jq0M2Yt08j34c0p")]
[InlineData("multipart/mixed; boundary=gc0p4Jq0M2Yt08j34c0p; undefined=ignored")]
[InlineData("text/html")]
public void XMLFormatter_CanRead_ReturnsFalseForUnsupportedMediaTypes(string requestContentType)
{
// Arrange
var formatter = new XmlFormatter();
var httpContext = new DefaultHttpContext();
httpContext.Request.ContentType = requestContentType;
var context = new InputFormatterContext(
httpContext,
modelName: string.Empty,
modelState: new ModelStateDictionary(),
modelType: typeof(void));
// Act
var result = formatter.CanRead(context);
// Assert
Assert.False(result);
}
private class TestFormatter : InputFormatter
{
public override Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
{
throw new NotImplementedException();
}
}
}
}

View File

@ -12,7 +12,6 @@ using Microsoft.AspNet.Http.Features;
using Microsoft.AspNet.Http.Internal; using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Mvc.Abstractions; using Microsoft.AspNet.Mvc.Abstractions;
using Microsoft.AspNet.Mvc.Formatters; using Microsoft.AspNet.Mvc.Formatters;
using Microsoft.AspNet.Mvc.Formatters.Xml;
using Microsoft.AspNet.Mvc.Infrastructure; using Microsoft.AspNet.Mvc.Infrastructure;
using Microsoft.AspNet.Routing; using Microsoft.AspNet.Routing;
using Microsoft.AspNet.Testing.xunit; using Microsoft.AspNet.Testing.xunit;
@ -133,7 +132,7 @@ namespace Microsoft.AspNet.Mvc
var result = new ObjectResult(input); var result = new ObjectResult(input);
result.ContentTypes = new List<MediaTypeHeaderValue>(); result.ContentTypes = new List<MediaTypeHeaderValue>();
result.ContentTypes.Add(MediaTypeHeaderValue.Parse(expectedContentType)); result.ContentTypes.Add(MediaTypeHeaderValue.Parse("application/json"));
// Act // Act
await result.ExecuteResultAsync(actionContext); await result.ExecuteResultAsync(actionContext);
@ -157,7 +156,7 @@ namespace Microsoft.AspNet.Mvc
// Set the content type property explicitly to a single value. // Set the content type property explicitly to a single value.
var result = new ObjectResult(input); var result = new ObjectResult(input);
result.ContentTypes = new List<MediaTypeHeaderValue>(); result.ContentTypes = new List<MediaTypeHeaderValue>();
result.ContentTypes.Add(MediaTypeHeaderValue.Parse(expectedContentType)); result.ContentTypes.Add(MediaTypeHeaderValue.Parse("application/json"));
// Act // Act
await result.ExecuteResultAsync(actionContext); await result.ExecuteResultAsync(actionContext);
@ -338,23 +337,23 @@ namespace Microsoft.AspNet.Mvc
[InlineData("application/xml")] [InlineData("application/xml")]
[InlineData("application/custom")] [InlineData("application/custom")]
[InlineData("application/xml;q=1, application/custom;q=0.8")] [InlineData("application/xml;q=1, application/custom;q=0.8")]
public void SelectFormatter_WithNoMatchingAcceptHeadersAndRequestContentType_PicksFormatterBasedOnObjectType public void SelectFormatter_WithNoMatchingAcceptHeader_PicksFormatterBasedOnObjectType(string acceptHeader)
(string acceptHeader)
{ {
// For no accept headers, // For no Accept headers, CanWriteResult is called once for the type match pass. For each additional Accept
// can write is called twice once for the request Content-Type and once for the type match pass. // header, it is called once.
// For each additional accept header, it is called once.
// Arrange // Arrange
var acceptHeaderCollection = string.IsNullOrEmpty(acceptHeader) ? var acceptHeaderCollection = string.IsNullOrEmpty(acceptHeader) ?
null : MediaTypeHeaderValue.ParseList(new[] { acceptHeader }).ToArray(); null :
MediaTypeHeaderValue.ParseList(new[] { acceptHeader }).ToArray();
var stream = new MemoryStream(); var stream = new MemoryStream();
var httpResponse = new Mock<HttpResponse>(); var httpResponse = new Mock<HttpResponse>();
httpResponse.SetupProperty<string>(o => o.ContentType); httpResponse.SetupProperty<string>(o => o.ContentType);
httpResponse.SetupGet(r => r.Body).Returns(stream); httpResponse.SetupGet(r => r.Body).Returns(stream);
var actionContext = CreateMockActionContext(httpResponse.Object, var actionContext = CreateMockActionContext(
requestAcceptHeader: acceptHeader, httpResponse.Object,
requestContentType: "application/xml"); requestAcceptHeader: acceptHeader,
requestContentType: "application/text");
var input = "testInput"; var input = "testInput";
var result = new ObjectResult(input); var result = new ObjectResult(input);
var mockCountingFormatter = new Mock<IOutputFormatter>(); var mockCountingFormatter = new Mock<IOutputFormatter>();
@ -365,35 +364,40 @@ namespace Microsoft.AspNet.Mvc
Object = input, Object = input,
DeclaredType = typeof(string) DeclaredType = typeof(string)
}; };
var mockCountingSupportedContentType = MediaTypeHeaderValue.Parse("application/text"); var requestContentType = MediaTypeHeaderValue.Parse("application/text");
mockCountingFormatter.Setup(o => o.CanWriteResult(context, mockCountingFormatter
It.Is<MediaTypeHeaderValue>(mth => mth == null))) .Setup(o => o.CanWriteResult(context, It.Is<MediaTypeHeaderValue>(mth => mth == null)))
.Returns(true); .Returns(true);
mockCountingFormatter.Setup(o => o.CanWriteResult(context, mockCountingSupportedContentType)) mockCountingFormatter
.Returns(true); .Setup(o => o.CanWriteResult(context, requestContentType))
.Returns(true);
// Set more than one formatters. The test output formatter throws on write. // Set more than one formatters. The test output formatter throws on write.
result.Formatters = new List<IOutputFormatter> result.Formatters = new List<IOutputFormatter>
{ {
new CannotWriteFormatter(), new CannotWriteFormatter(),
mockCountingFormatter.Object, mockCountingFormatter.Object,
}; };
// Act // Act
var formatter = result.SelectFormatter(context, result.Formatters); var formatter = result.SelectFormatter(context, result.Formatters);
// Assert // Assert
Assert.Equal(mockCountingFormatter.Object, formatter); Assert.Equal(mockCountingFormatter.Object, formatter);
// CanWriteResult is called once for the type-based match.
mockCountingFormatter.Verify(v => v.CanWriteResult(context, null), Times.Once()); mockCountingFormatter.Verify(v => v.CanWriteResult(context, null), Times.Once());
// CanWriteResult is invoked for the following cases: // CanWriteResult is never called for the request's Content-Type.
// 1. For each accept header present mockCountingFormatter.Verify(v => v.CanWriteResult(context, requestContentType), Times.Never());
// 2. Request Content-Type
// 3. Type based match // In total, CanWriteResult is invoked for the following cases:
var callCount = (acceptHeaderCollection == null ? 0 : acceptHeaderCollection.Count()) + 2; // 1. For each Accept header present
mockCountingFormatter.Verify(v => v.CanWriteResult(context, // 2. Type-based match
It.IsNotIn<MediaTypeHeaderValue>(mockCountingSupportedContentType)), var callCount = (acceptHeaderCollection == null ? 0 : acceptHeaderCollection.Count()) + 1;
Times.Exactly(callCount)); mockCountingFormatter.Verify(
v => v.CanWriteResult(It.IsAny< OutputFormatterContext>(), It.IsAny<MediaTypeHeaderValue>()),
Times.Exactly(callCount));
} }
[Fact] [Fact]

View File

@ -22,10 +22,10 @@ namespace Microsoft.AspNet.Mvc.Formatters
[Theory] [Theory]
[InlineData("application/json", true)] [InlineData("application/json", true)]
[InlineData("application/*", true)] [InlineData("application/*", false)]
[InlineData("*/*", true)] [InlineData("*/*", false)]
[InlineData("text/json", true)] [InlineData("text/json", true)]
[InlineData("text/*", true)] [InlineData("text/*", false)]
[InlineData("text/xml", false)] [InlineData("text/xml", false)]
[InlineData("application/xml", false)] [InlineData("application/xml", false)]
[InlineData("", false)] [InlineData("", false)]

View File

@ -75,8 +75,8 @@ namespace Microsoft.AspNet.Mvc.Formatters
[Theory] [Theory]
[InlineData("application/json-patch+json", true)] [InlineData("application/json-patch+json", true)]
[InlineData("application/json", false)] [InlineData("application/json", false)]
[InlineData("application/*", true)] [InlineData("application/*", false)]
[InlineData("*/*", true)] [InlineData("*/*", false)]
public void CanRead_ReturnsTrueOnlyForJsonPatchContentType(string requestContentType, bool expectedCanRead) public void CanRead_ReturnsTrueOnlyForJsonPatchContentType(string requestContentType, bool expectedCanRead)
{ {
// Arrange // Arrange

View File

@ -56,10 +56,10 @@ namespace Microsoft.AspNet.Mvc.Formatters.Xml
// Mono issue - https://github.com/aspnet/External/issues/18 // Mono issue - https://github.com/aspnet/External/issues/18
[FrameworkSkipCondition(RuntimeFrameworks.Mono)] [FrameworkSkipCondition(RuntimeFrameworks.Mono)]
[InlineData("application/xml", true)] [InlineData("application/xml", true)]
[InlineData("application/*", true)] [InlineData("application/*", false)]
[InlineData("*/*", true)] [InlineData("*/*", false)]
[InlineData("text/xml", true)] [InlineData("text/xml", true)]
[InlineData("text/*", true)] [InlineData("text/*", false)]
[InlineData("text/json", false)] [InlineData("text/json", false)]
[InlineData("application/json", false)] [InlineData("application/json", false)]
[InlineData("", false)] [InlineData("", false)]

View File

@ -41,10 +41,10 @@ namespace Microsoft.AspNet.Mvc.Formatters.Xml
[Theory] [Theory]
[InlineData("application/xml", true)] [InlineData("application/xml", true)]
[InlineData("application/*", true)] [InlineData("application/*", false)]
[InlineData("*/*", true)] [InlineData("*/*", false)]
[InlineData("text/xml", true)] [InlineData("text/xml", true)]
[InlineData("text/*", true)] [InlineData("text/*", false)]
[InlineData("text/json", false)] [InlineData("text/json", false)]
[InlineData("application/json", false)] [InlineData("application/json", false)]
[InlineData("", false)] [InlineData("", false)]

View File

@ -170,7 +170,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
"<DummyClass xmlns=\"http://schemas.datacontract.org/2004/07/ActionResultsWebSite\">" + "<DummyClass xmlns=\"http://schemas.datacontract.org/2004/07/ActionResultsWebSite\">" +
"<SampleInt>2</SampleInt><SampleString>foo</SampleString></DummyClass>"; "<SampleInt>2</SampleInt><SampleString>foo</SampleString></DummyClass>";
var request = new HttpRequestMessage(HttpMethod.Post, "Home/GetCustomErrorObject"); var request = new HttpRequestMessage(HttpMethod.Post, "Home/GetCustomErrorObject");
request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json;charset=utf-8")); request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json"));
request.Content = new StringContent(input, Encoding.UTF8, "application/xml"); request.Content = new StringContent(input, Encoding.UTF8, "application/xml");
// Act // Act
@ -218,7 +218,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
Assert.Equal("content", await response.Content.ReadAsStringAsync()); Assert.Equal("content", await response.Content.ReadAsStringAsync());
} }
[Theory] [Fact]
public async Task ContentResult_WritesContent_SetsContentTypeAndEncoding() public async Task ContentResult_WritesContent_SetsContentTypeAndEncoding()
{ {
// Arrange // Arrange

View File

@ -43,10 +43,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
[Theory] [Theory]
[InlineData("application/json")] [InlineData("application/json")]
[InlineData("application/*")]
[InlineData("*/*")]
[InlineData("text/json")] [InlineData("text/json")]
[InlineData("text/*")]
public async Task JsonInputFormatter_IsSelectedForJsonRequest(string requestContentType) public async Task JsonInputFormatter_IsSelectedForJsonRequest(string requestContentType)
{ {
// Arrange // Arrange

View File

@ -100,7 +100,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
{ {
// Arrange // Arrange
var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/Home/ReturnUser"); var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/Home/ReturnUser");
request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/xml;charset=utf-8")); request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/xml"));
// Act // Act
var response = await Client.SendAsync(request); var response = await Client.SendAsync(request);

View File

@ -21,7 +21,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
public HttpClient Client { get; } public HttpClient Client { get; }
[Theory] [Theory]
[InlineData("application/xml,*/*;0.2")] [InlineData("application/xml,*/*;q=0.2")]
[InlineData("application/xml,*/*")] [InlineData("application/xml,*/*")]
public async Task AllMediaRangeAcceptHeader_FirstFormatterInListWritesResponse(string acceptHeader) public async Task AllMediaRangeAcceptHeader_FirstFormatterInListWritesResponse(string acceptHeader)
{ {
@ -43,7 +43,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
[ConditionalTheory] [ConditionalTheory]
// Mono issue - https://github.com/aspnet/External/issues/18 // Mono issue - https://github.com/aspnet/External/issues/18
[FrameworkSkipCondition(RuntimeFrameworks.Mono)] [FrameworkSkipCondition(RuntimeFrameworks.Mono)]
[InlineData("application/xml,*/*;0.2")] [InlineData("application/xml,*/*;q=0.2")]
[InlineData("application/xml,*/*")] [InlineData("application/xml,*/*")]
public async Task AllMediaRangeAcceptHeader_ProducesAttributeIsHonored(string acceptHeader) public async Task AllMediaRangeAcceptHeader_ProducesAttributeIsHonored(string acceptHeader)
{ {
@ -71,9 +71,41 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
[ConditionalTheory] [ConditionalTheory]
// Mono issue - https://github.com/aspnet/External/issues/18 // Mono issue - https://github.com/aspnet/External/issues/18
[FrameworkSkipCondition(RuntimeFrameworks.Mono)] [FrameworkSkipCondition(RuntimeFrameworks.Mono)]
[InlineData("application/xml,*/*;0.2")] [InlineData("application/xml,*/*;q=0.2")]
[InlineData("application/xml,*/*")] [InlineData("application/xml,*/*")]
public async Task AllMediaRangeAcceptHeader_WithContentTypeHeader_ContentTypeIsHonored(string acceptHeader) public async Task AllMediaRangeAcceptHeader_WithContentTypeHeader_ContentTypeIsIgnored(string acceptHeader)
{
// Arrange
var requestData =
"<RespectBrowserAcceptHeaderController.Employee xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\"" +
" xmlns=\"http://schemas.datacontract.org/2004/07/FormatterWebSite.Controllers\"><Id>35</Id><Name>Jimmy" +
"</Name></RespectBrowserAcceptHeaderController.Employee>";
var expectedResponseData = @"{""Id"":35,""Name"":""Jimmy""}";
var request = RequestWithAccept("http://localhost/RespectBrowserAcceptHeader/CreateEmployee", acceptHeader);
request.Content = new StringContent(requestData, Encoding.UTF8, "application/xml");
request.Method = HttpMethod.Post;
// Act
var response = await Client.SendAsync(request);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
Assert.NotNull(response.Content.Headers.ContentType);
// Site uses default output formatter (ignores Accept header) because that header contained a wildcard match.
Assert.Equal("application/json; charset=utf-8", response.Content.Headers.ContentType.ToString());
var responseData = await response.Content.ReadAsStringAsync();
Assert.Equal(expectedResponseData, responseData);
}
[ConditionalTheory]
// Mono issue - https://github.com/aspnet/External/issues/18
[FrameworkSkipCondition(RuntimeFrameworks.Mono)]
[InlineData("application/xml,application/json;q=0.2")]
[InlineData("application/xml,application/json")]
public async Task AllMediaRangeAcceptHeader_WithExactMatch_ReturnsExpectedContent(string acceptHeader)
{ {
// Arrange // Arrange
var requestData = var requestData =

View File

@ -29,7 +29,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
var request = new HttpRequestMessage( var request = new HttpRequestMessage(
HttpMethod.Post, HttpMethod.Post,
"http://localhost/Home/GetDummyClass?sampleInput=10"); "http://localhost/Home/GetDummyClass?sampleInput=10");
request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/xml;charset=utf-8")); request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/xml"));
// Act // Act
var response = await Client.SendAsync(request); var response = await Client.SendAsync(request);
@ -50,7 +50,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
var request = new HttpRequestMessage( var request = new HttpRequestMessage(
HttpMethod.Post, HttpMethod.Post,
"http://localhost/XmlSerializer/GetDummyClass?sampleInput=10"); "http://localhost/XmlSerializer/GetDummyClass?sampleInput=10");
request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/xml;charset=utf-8")); request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/xml"));
// Act // Act
var response = await Client.SendAsync(request); var response = await Client.SendAsync(request);
@ -72,7 +72,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
var request = new HttpRequestMessage( var request = new HttpRequestMessage(
HttpMethod.Post, HttpMethod.Post,
"http://localhost/DataContractSerializer/GetPerson?name=HelloWorld"); "http://localhost/DataContractSerializer/GetPerson?name=HelloWorld");
request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/xml;charset=utf-8")); request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/xml"));
// Act // Act
var response = await Client.SendAsync(request); var response = await Client.SendAsync(request);
@ -93,7 +93,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
var request = new HttpRequestMessage( var request = new HttpRequestMessage(
HttpMethod.Post, HttpMethod.Post,
"http://localhost/XmlSerializer/GetDerivedDummyClass?sampleInput=10"); "http://localhost/XmlSerializer/GetDerivedDummyClass?sampleInput=10");
request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/xml;charset=utf-8")); request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/xml"));
// Act // Act
var response = await Client.SendAsync(request); var response = await Client.SendAsync(request);
@ -116,7 +116,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
var request = new HttpRequestMessage( var request = new HttpRequestMessage(
HttpMethod.Post, HttpMethod.Post,
"http://localhost/Home/GetDerivedDummyClass?sampleInput=10"); "http://localhost/Home/GetDerivedDummyClass?sampleInput=10");
request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/xml;charset=utf-8")); request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/xml"));
// Act // Act
var response = await Client.SendAsync(request); var response = await Client.SendAsync(request);
@ -137,7 +137,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
var request = new HttpRequestMessage( var request = new HttpRequestMessage(
HttpMethod.Post, HttpMethod.Post,
"http://localhost/XmlSerializer/GetDictionary"); "http://localhost/XmlSerializer/GetDictionary");
request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/xml;charset=utf-8")); request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/xml"));
// Act // Act
var response = await Client.SendAsync(request); var response = await Client.SendAsync(request);