Remove runtime dependency usage of MediaTypeHeaderValue.
Removes usage of MediaTypeHeaderValue in ApiExplorer, InputFormatters and OutputFormatters Public interface changes with stub implementation.
This commit is contained in:
parent
32d15186a0
commit
830fd410f5
|
|
@ -2,7 +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 Microsoft.Net.Http.Headers;
|
using Microsoft.Extensions.Primitives;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Formatters
|
namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
{
|
{
|
||||||
|
|
@ -20,7 +20,7 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
/// and expect to see the same value provided in
|
/// and expect to see the same value provided in
|
||||||
/// <see cref="IOutputFormatter.WriteAsync(OutputFormatterWriteContext)"/>
|
/// <see cref="IOutputFormatter.WriteAsync(OutputFormatterWriteContext)"/>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public virtual MediaTypeHeaderValue ContentType { get; set; }
|
public virtual StringSegment ContentType { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating that content-negotiation could not find a formatter based on the
|
/// Gets or sets a value indicating that content-negotiation could not find a formatter based on the
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
// 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 Microsoft.AspNet.Mvc.Formatters;
|
using Microsoft.AspNet.Mvc.Formatters;
|
||||||
using Microsoft.Net.Http.Headers;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ApiExplorer
|
namespace Microsoft.AspNet.Mvc.ApiExplorer
|
||||||
{
|
{
|
||||||
|
|
@ -19,6 +18,6 @@ namespace Microsoft.AspNet.Mvc.ApiExplorer
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The media type of the response.
|
/// The media type of the response.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public MediaTypeHeaderValue MediaType { get; set; }
|
public string MediaType { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -15,7 +15,6 @@ using Microsoft.AspNet.Routing;
|
||||||
using Microsoft.AspNet.Routing.Template;
|
using Microsoft.AspNet.Routing.Template;
|
||||||
using Microsoft.Extensions.Internal;
|
using Microsoft.Extensions.Internal;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Microsoft.Net.Http.Headers;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ApiExplorer
|
namespace Microsoft.AspNet.Mvc.ApiExplorer
|
||||||
{
|
{
|
||||||
|
|
@ -311,7 +310,7 @@ namespace Microsoft.AspNet.Mvc.ApiExplorer
|
||||||
|
|
||||||
// Walk through all 'filter' attributes in order, and allow each one to see or override
|
// Walk through all 'filter' attributes in order, and allow each one to see or override
|
||||||
// the results of the previous ones. This is similar to the execution path for content-negotiation.
|
// the results of the previous ones. This is similar to the execution path for content-negotiation.
|
||||||
var contentTypes = new List<MediaTypeHeaderValue>();
|
var contentTypes = new MediaTypeCollection();
|
||||||
if (responseMetadataAttributes != null)
|
if (responseMetadataAttributes != null)
|
||||||
{
|
{
|
||||||
foreach (var metadataAttribute in responseMetadataAttributes)
|
foreach (var metadataAttribute in responseMetadataAttributes)
|
||||||
|
|
@ -322,7 +321,7 @@ namespace Microsoft.AspNet.Mvc.ApiExplorer
|
||||||
|
|
||||||
if (contentTypes.Count == 0)
|
if (contentTypes.Count == 0)
|
||||||
{
|
{
|
||||||
contentTypes.Add(null);
|
contentTypes.Add((string)null);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var contentType in contentTypes)
|
foreach (var contentType in contentTypes)
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.Net.Http.Headers;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ApiExplorer
|
namespace Microsoft.AspNet.Mvc.ApiExplorer
|
||||||
{
|
{
|
||||||
|
|
@ -28,8 +27,8 @@ namespace Microsoft.AspNet.Mvc.ApiExplorer
|
||||||
/// The <see cref="Type"/> for which the supported content types are desired.
|
/// The <see cref="Type"/> for which the supported content types are desired.
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <returns>Content types which are supported by the <see cref="Formatters.IOutputFormatter"/>.</returns>
|
/// <returns>Content types which are supported by the <see cref="Formatters.IOutputFormatter"/>.</returns>
|
||||||
IReadOnlyList<MediaTypeHeaderValue> GetSupportedContentTypes(
|
IReadOnlyList<string> GetSupportedContentTypes(
|
||||||
MediaTypeHeaderValue contentType,
|
string contentType,
|
||||||
Type objectType);
|
Type objectType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2,8 +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.Collections.Generic;
|
using Microsoft.AspNet.Mvc.Formatters;
|
||||||
using Microsoft.Net.Http.Headers;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ApiExplorer
|
namespace Microsoft.AspNet.Mvc.ApiExplorer
|
||||||
{
|
{
|
||||||
|
|
@ -20,6 +19,6 @@ namespace Microsoft.AspNet.Mvc.ApiExplorer
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Configures a collection of allowed content types which can be produced by the action.
|
/// Configures a collection of allowed content types which can be produced by the action.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void SetContentTypes(IList<MediaTypeHeaderValue> contentTypes);
|
void SetContentTypes(MediaTypeCollection contentTypes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8,6 +8,8 @@ using Microsoft.AspNet.Mvc.Abstractions;
|
||||||
using Microsoft.AspNet.Mvc.ActionConstraints;
|
using Microsoft.AspNet.Mvc.ActionConstraints;
|
||||||
using Microsoft.AspNet.Mvc.Core;
|
using Microsoft.AspNet.Mvc.Core;
|
||||||
using Microsoft.AspNet.Mvc.Filters;
|
using Microsoft.AspNet.Mvc.Filters;
|
||||||
|
using Microsoft.AspNet.Mvc.Formatters;
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc
|
||||||
|
|
@ -30,6 +32,15 @@ namespace Microsoft.AspNet.Mvc
|
||||||
throw new ArgumentNullException(nameof(contentType));
|
throw new ArgumentNullException(nameof(contentType));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We want to ensure that the given provided content types are valid values, so
|
||||||
|
// we validate them using the semantics of MediaTypeHeaderValue.
|
||||||
|
MediaTypeHeaderValue.Parse(contentType);
|
||||||
|
|
||||||
|
for (var i = 0; i < otherContentTypes.Length; i++)
|
||||||
|
{
|
||||||
|
MediaTypeHeaderValue.Parse(otherContentTypes[i]);
|
||||||
|
}
|
||||||
|
|
||||||
ContentTypes = GetContentTypes(contentType, otherContentTypes);
|
ContentTypes = GetContentTypes(contentType, otherContentTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -39,7 +50,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
int IActionConstraint.Order { get; } = ConsumesActionConstraintOrder;
|
int IActionConstraint.Order { get; } = ConsumesActionConstraintOrder;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IList<MediaTypeHeaderValue> ContentTypes { get; set; }
|
public MediaTypeCollection ContentTypes { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void OnResourceExecuting(ResourceExecutingContext context)
|
public void OnResourceExecuting(ResourceExecutingContext context)
|
||||||
|
|
@ -53,13 +64,12 @@ namespace Microsoft.AspNet.Mvc
|
||||||
// Ignore all other filters. This is to ensure we have a overriding behavior.
|
// Ignore all other filters. This is to ensure we have a overriding behavior.
|
||||||
if (IsApplicable(context.ActionDescriptor))
|
if (IsApplicable(context.ActionDescriptor))
|
||||||
{
|
{
|
||||||
MediaTypeHeaderValue requestContentType = null;
|
var requestContentType = context.HttpContext.Request.ContentType;
|
||||||
MediaTypeHeaderValue.TryParse(context.HttpContext.Request.ContentType, out requestContentType);
|
|
||||||
|
|
||||||
// Confirm the request's content type is more specific than a media type this action supports e.g. OK
|
// 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 client sent "text/plain" data and this action supports "text/*".
|
||||||
if (requestContentType != null &&
|
if (requestContentType != null &&
|
||||||
!ContentTypes.Any(contentType => requestContentType.IsSubsetOf(contentType)))
|
!ContentTypes.Any(contentType => MediaTypeComparisons.IsSubsetOf(contentType, requestContentType)))
|
||||||
{
|
{
|
||||||
context.Result = new UnsupportedMediaTypeResult();
|
context.Result = new UnsupportedMediaTypeResult();
|
||||||
}
|
}
|
||||||
|
|
@ -86,8 +96,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaTypeHeaderValue requestContentType = null;
|
var requestContentType = context.RouteContext.HttpContext.Request.ContentType;
|
||||||
MediaTypeHeaderValue.TryParse(context.RouteContext.HttpContext.Request.ContentType, out requestContentType);
|
|
||||||
|
|
||||||
// If the request content type is null we need to act like pass through.
|
// If the request content type is null we need to act like pass through.
|
||||||
// In case there is a single candidate with a constraint it should be selected.
|
// In case there is a single candidate with a constraint it should be selected.
|
||||||
|
|
@ -104,7 +113,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
// Confirm the request's content type is more specific than a media type this action supports e.g. OK
|
// 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 client sent "text/plain" data and this action supports "text/*".
|
||||||
if (ContentTypes.Any(contentType => requestContentType.IsSubsetOf(contentType)))
|
if (ContentTypes.Any(contentType => MediaTypeComparisons.IsSubsetOf(contentType, requestContentType)))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -164,22 +173,22 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<MediaTypeHeaderValue> GetContentTypes(string firstArg, string[] args)
|
private MediaTypeCollection GetContentTypes(string firstArg, string[] args)
|
||||||
{
|
{
|
||||||
var completeArgs = new List<string>();
|
var completeArgs = new List<string>();
|
||||||
completeArgs.Add(firstArg);
|
completeArgs.Add(firstArg);
|
||||||
completeArgs.AddRange(args);
|
completeArgs.AddRange(args);
|
||||||
var contentTypes = new List<MediaTypeHeaderValue>();
|
var contentTypes = new MediaTypeCollection();
|
||||||
foreach (var arg in completeArgs)
|
foreach (var arg in completeArgs)
|
||||||
{
|
{
|
||||||
var contentType = MediaTypeHeaderValue.Parse(arg);
|
if (MediaTypeComparisons.MatchesAllSubtypes(arg) ||
|
||||||
if (contentType.MatchesAllSubTypes || contentType.MatchesAllTypes)
|
MediaTypeComparisons.MatchesAllTypes(arg))
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException(
|
throw new InvalidOperationException(
|
||||||
Resources.FormatMatchAllContentTypeIsNotAllowed(arg));
|
Resources.FormatMatchAllContentTypeIsNotAllowed(arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
contentTypes.Add(contentType);
|
contentTypes.Add(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
return contentTypes;
|
return contentTypes;
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,10 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
public class ContentResult : ActionResult
|
public class ContentResult : ActionResult
|
||||||
{
|
{
|
||||||
private readonly MediaTypeHeaderValue DefaultContentType = new MediaTypeHeaderValue("text/plain")
|
private readonly string DefaultContentType = new MediaTypeHeaderValue("text/plain")
|
||||||
{
|
{
|
||||||
Encoding = Encoding.UTF8
|
Encoding = Encoding.UTF8
|
||||||
};
|
}.ToString();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or set the content representing the body of the response.
|
/// Gets or set the content representing the body of the response.
|
||||||
|
|
@ -27,9 +27,9 @@ namespace Microsoft.AspNet.Mvc
|
||||||
public string Content { get; set; }
|
public string Content { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the <see cref="MediaTypeHeaderValue"/> representing the Content-Type header of the response.
|
/// Gets or sets the Content-Type header for the response.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public MediaTypeHeaderValue ContentType { get; set; }
|
public string ContentType { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the HTTP status code.
|
/// Gets or sets the HTTP status code.
|
||||||
|
|
|
||||||
|
|
@ -271,7 +271,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
var result = new ContentResult
|
var result = new ContentResult
|
||||||
{
|
{
|
||||||
Content = content,
|
Content = content,
|
||||||
ContentType = contentType
|
ContentType = contentType?.ToString()
|
||||||
};
|
};
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
|
||||||
|
|
@ -31,10 +31,6 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(fileContents));
|
throw new ArgumentNullException(nameof(fileContents));
|
||||||
}
|
}
|
||||||
if (contentType == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(contentType));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -45,18 +41,13 @@ namespace Microsoft.AspNet.Mvc
|
||||||
/// <param name="fileContents">The bytes that represent the file contents.</param>
|
/// <param name="fileContents">The bytes that represent the file contents.</param>
|
||||||
/// <param name="contentType">The Content-Type header of the response.</param>
|
/// <param name="contentType">The Content-Type header of the response.</param>
|
||||||
public FileContentResult(byte[] fileContents, MediaTypeHeaderValue contentType)
|
public FileContentResult(byte[] fileContents, MediaTypeHeaderValue contentType)
|
||||||
: base(contentType)
|
: base(contentType?.ToString())
|
||||||
{
|
{
|
||||||
if (fileContents == null)
|
if (fileContents == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(fileContents));
|
throw new ArgumentNullException(nameof(fileContents));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (contentType == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(contentType));
|
|
||||||
}
|
|
||||||
|
|
||||||
FileContents = fileContents;
|
FileContents = fileContents;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ using Microsoft.AspNet.Http;
|
||||||
using Microsoft.AspNet.Mvc.Logging;
|
using Microsoft.AspNet.Mvc.Logging;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc
|
||||||
|
|
@ -24,7 +25,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
/// the provided <paramref name="contentType"/>.
|
/// the provided <paramref name="contentType"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="contentType">The Content-Type header of the response.</param>
|
/// <param name="contentType">The Content-Type header of the response.</param>
|
||||||
protected FileResult(MediaTypeHeaderValue contentType)
|
protected FileResult(string contentType)
|
||||||
{
|
{
|
||||||
if (contentType == null)
|
if (contentType == null)
|
||||||
{
|
{
|
||||||
|
|
@ -35,9 +36,9 @@ namespace Microsoft.AspNet.Mvc
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the <see cref="MediaTypeHeaderValue"/> representing the Content-Type header of the response.
|
/// Gets the Content-Type header for the response.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public MediaTypeHeaderValue ContentType { get; }
|
public string ContentType { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the file name that will be used in the Content-Disposition header of the response.
|
/// Gets the file name that will be used in the Content-Disposition header of the response.
|
||||||
|
|
|
||||||
|
|
@ -42,18 +42,13 @@ namespace Microsoft.AspNet.Mvc
|
||||||
/// <param name="fileStream">The stream with the file.</param>
|
/// <param name="fileStream">The stream with the file.</param>
|
||||||
/// <param name="contentType">The Content-Type header of the response.</param>
|
/// <param name="contentType">The Content-Type header of the response.</param>
|
||||||
public FileStreamResult(Stream fileStream, MediaTypeHeaderValue contentType)
|
public FileStreamResult(Stream fileStream, MediaTypeHeaderValue contentType)
|
||||||
: base(contentType)
|
: base(contentType?.ToString())
|
||||||
{
|
{
|
||||||
if (fileStream == null)
|
if (fileStream == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(fileStream));
|
throw new ArgumentNullException(nameof(fileStream));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (contentType == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(contentType));
|
|
||||||
}
|
|
||||||
|
|
||||||
FileStream = fileStream;
|
FileStream = fileStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,10 @@
|
||||||
// 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.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.AspNet.Mvc.ApiExplorer;
|
using Microsoft.AspNet.Mvc.ApiExplorer;
|
||||||
using Microsoft.AspNet.Mvc.Filters;
|
using Microsoft.AspNet.Mvc.Filters;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Microsoft.Net.Http.Headers;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Formatters
|
namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
{
|
{
|
||||||
|
|
@ -78,7 +76,7 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
|
|
||||||
// Determine media types this action supports.
|
// Determine media types this action supports.
|
||||||
var responseTypeFilters = context.Filters.OfType<IApiResponseMetadataProvider>();
|
var responseTypeFilters = context.Filters.OfType<IApiResponseMetadataProvider>();
|
||||||
var supportedMediaTypes = new List<MediaTypeHeaderValue>();
|
var supportedMediaTypes = new MediaTypeCollection();
|
||||||
foreach (var filter in responseTypeFilters)
|
foreach (var filter in responseTypeFilters)
|
||||||
{
|
{
|
||||||
filter.SetContentTypes(supportedMediaTypes);
|
filter.SetContentTypes(supportedMediaTypes);
|
||||||
|
|
@ -91,7 +89,7 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
// request's format and IApiResponseMetadataProvider-provided content types similarly to an Accept
|
// request's format and IApiResponseMetadataProvider-provided content types similarly to an Accept
|
||||||
// header and an output formatter's SupportedMediaTypes: Confirm action supports a more specific media
|
// 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".
|
// type than requested e.g. OK if "text/*" requested and action supports "text/plain".
|
||||||
if (!supportedMediaTypes.Any(c => c.IsSubsetOf(contentType)))
|
if (!supportedMediaTypes.Any(c => MediaTypeComparisons.IsSubsetOf(contentType, c)))
|
||||||
{
|
{
|
||||||
context.Result = new HttpNotFoundResult();
|
context.Result = new HttpNotFoundResult();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,24 +4,46 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.AspNet.Mvc.Core;
|
using Microsoft.AspNet.Mvc.Core;
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Formatters
|
namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used to specify mapping between the URL Format and corresponding <see cref="MediaTypeHeaderValue"/>.
|
/// Used to specify mapping between the URL Format and corresponding media type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class FormatterMappings
|
public class FormatterMappings
|
||||||
{
|
{
|
||||||
private readonly Dictionary<string, MediaTypeHeaderValue> _map =
|
private readonly Dictionary<string, string> _map =
|
||||||
new Dictionary<string, MediaTypeHeaderValue>(StringComparer.OrdinalIgnoreCase);
|
new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets mapping for the format to specified <see cref="MediaTypeHeaderValue"/>.
|
/// Sets mapping for the format to specified media type.
|
||||||
/// If the format already exists, the <see cref="MediaTypeHeaderValue"/> will be overwritten with the new value.
|
/// If the format already exists, the media type will be overwritten with the new value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="format">The format value.</param>
|
/// <param name="format">The format value.</param>
|
||||||
/// <param name="contentType">The <see cref="MediaTypeHeaderValue"/> for the format value.</param>
|
/// <param name="contentType">The media type for the format value.</param>
|
||||||
|
public void SetMediaTypeMappingForFormat(string format, string contentType)
|
||||||
|
{
|
||||||
|
if (format == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(format));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contentType == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(contentType));
|
||||||
|
}
|
||||||
|
|
||||||
|
SetMediaTypeMappingForFormat(format, MediaTypeHeaderValue.Parse(contentType));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets mapping for the format to specified media type.
|
||||||
|
/// If the format already exists, the media type will be overwritten with the new value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="format">The format value.</param>
|
||||||
|
/// <param name="contentType">The media type for the format value.</param>
|
||||||
public void SetMediaTypeMappingForFormat(string format, MediaTypeHeaderValue contentType)
|
public void SetMediaTypeMappingForFormat(string format, MediaTypeHeaderValue contentType)
|
||||||
{
|
{
|
||||||
if (format == null)
|
if (format == null)
|
||||||
|
|
@ -36,31 +58,34 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
|
|
||||||
ValidateContentType(contentType);
|
ValidateContentType(contentType);
|
||||||
format = RemovePeriodIfPresent(format);
|
format = RemovePeriodIfPresent(format);
|
||||||
_map[format] = contentType.CopyAsReadOnly();
|
_map[format] = contentType.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets <see cref="MediaTypeHeaderValue"/> for the specified format.
|
/// Gets the media type for the specified format.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="format">The format value.</param>
|
/// <param name="format">The format value.</param>
|
||||||
/// <returns>The <see cref="MediaTypeHeaderValue"/> for input format.</returns>
|
/// <returns>The media type for input format.</returns>
|
||||||
public MediaTypeHeaderValue GetMediaTypeMappingForFormat(string format)
|
public string GetMediaTypeMappingForFormat(string format)
|
||||||
{
|
{
|
||||||
if (format == null)
|
if (string.IsNullOrEmpty(format))
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(format));
|
var message = Resources.FormatFormatFormatterMappings_GetMediaTypeMappingForFormat_InvalidFormat(
|
||||||
|
nameof(format));
|
||||||
|
|
||||||
|
throw new ArgumentException(message, nameof(format));
|
||||||
}
|
}
|
||||||
|
|
||||||
format = RemovePeriodIfPresent(format);
|
format = RemovePeriodIfPresent(format);
|
||||||
|
|
||||||
MediaTypeHeaderValue value = null;
|
string value = null;
|
||||||
_map.TryGetValue(format, out value);
|
_map.TryGetValue(format, out value);
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Clears the <see cref="MediaTypeHeaderValue"/> mapping for the format.
|
/// Clears the media type mapping for the format.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="format">The format value.</param>
|
/// <param name="format">The format value.</param>
|
||||||
/// <returns><c>true</c> if the format is successfully found and cleared; otherwise, <c>false</c>.</returns>
|
/// <returns><c>true</c> if the format is successfully found and cleared; otherwise, <c>false</c>.</returns>
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Mvc.Core;
|
using Microsoft.AspNet.Mvc.Core;
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Formatters
|
namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
|
|
@ -37,10 +38,10 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
public IList<Encoding> SupportedEncodings { get; } = new List<Encoding>();
|
public IList<Encoding> SupportedEncodings { get; } = new List<Encoding>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the mutable collection of <see cref="MediaTypeHeaderValue"/> elements supported by
|
/// Gets the mutable collection of media type elements supported by
|
||||||
/// this <see cref="InputFormatter"/>.
|
/// this <see cref="InputFormatter"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IList<MediaTypeHeaderValue> SupportedMediaTypes { get; } = new List<MediaTypeHeaderValue>();
|
public MediaTypeCollection SupportedMediaTypes { get; } = new MediaTypeCollection();
|
||||||
|
|
||||||
protected object GetDefaultValueForType(Type modelType)
|
protected object GetDefaultValueForType(Type modelType)
|
||||||
{
|
{
|
||||||
|
|
@ -61,8 +62,7 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
}
|
}
|
||||||
|
|
||||||
var contentType = context.HttpContext.Request.ContentType;
|
var contentType = context.HttpContext.Request.ContentType;
|
||||||
MediaTypeHeaderValue requestContentType;
|
if (string.IsNullOrEmpty(contentType))
|
||||||
if (!MediaTypeHeaderValue.TryParse(contentType, out requestContentType))
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -71,7 +71,7 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
// client sent "text/plain" data and this formatter supports "text/*".
|
// client sent "text/plain" data and this formatter supports "text/*".
|
||||||
return SupportedMediaTypes.Any(supportedMediaType =>
|
return SupportedMediaTypes.Any(supportedMediaType =>
|
||||||
{
|
{
|
||||||
return requestContentType.IsSubsetOf(supportedMediaType);
|
return MediaTypeComparisons.IsSubsetOf(supportedMediaType, contentType);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -107,27 +107,28 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns an <see cref="Encoding"/> based on <paramref name="context"/>'s
|
/// Returns an <see cref="Encoding"/> based on <paramref name="context"/>'s
|
||||||
/// <see cref="MediaTypeHeaderValue.Charset"/>.
|
/// character set.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="context">The <see cref="InputFormatterContext"/>.</param>
|
/// <param name="context">The <see cref="InputFormatterContext"/>.</param>
|
||||||
/// <returns>
|
/// <returns>
|
||||||
/// An <see cref="Encoding"/> based on <paramref name="context"/>'s
|
/// An <see cref="Encoding"/> based on <paramref name="context"/>'s
|
||||||
/// <see cref="MediaTypeHeaderValue.Charset"/>. <c>null</c> if no supported encoding was found.
|
/// character set. <c>null</c> if no supported encoding was found.
|
||||||
/// </returns>
|
/// </returns>
|
||||||
protected Encoding SelectCharacterEncoding(InputFormatterContext context)
|
protected Encoding SelectCharacterEncoding(InputFormatterContext context)
|
||||||
{
|
{
|
||||||
var request = context.HttpContext.Request;
|
var request = context.HttpContext.Request;
|
||||||
|
|
||||||
MediaTypeHeaderValue contentType;
|
if (request.ContentType != null)
|
||||||
MediaTypeHeaderValue.TryParse(request.ContentType, out contentType);
|
|
||||||
if (contentType != null)
|
|
||||||
{
|
{
|
||||||
var charset = contentType.Charset;
|
var encoding = MediaTypeEncoding.GetEncoding(request.ContentType);
|
||||||
if (!string.IsNullOrEmpty(charset))
|
if (encoding != null)
|
||||||
{
|
{
|
||||||
foreach (var supportedEncoding in SupportedEncodings)
|
foreach (var supportedEncoding in SupportedEncodings)
|
||||||
{
|
{
|
||||||
if (string.Equals(charset, supportedEncoding.WebName, StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(
|
||||||
|
encoding.WebName,
|
||||||
|
supportedEncoding.WebName,
|
||||||
|
StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return supportedEncoding;
|
return supportedEncoding;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using Microsoft.Net.Http.Headers;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A collection of media types.
|
||||||
|
/// </summary>
|
||||||
|
public class MediaTypeCollection : Collection<string>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of <see cref="MediaTypeCollection"/>.
|
||||||
|
/// </summary>
|
||||||
|
public MediaTypeCollection()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds an object to the end of the <see cref="MediaTypeCollection"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">The media type to be added to the end of the <see cref="MediaTypeCollection"/>.</param>
|
||||||
|
public void Add(MediaTypeHeaderValue item)
|
||||||
|
{
|
||||||
|
if (item == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
Add(item.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Inserts an element into the <see cref="MediaTypeCollection"/> at the specified index.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">The zero-based index at which <paramref name="item"/> should be inserted.</param>
|
||||||
|
/// <param name="item">The media type to insert.</param>
|
||||||
|
public void Insert(int index, MediaTypeHeaderValue item)
|
||||||
|
{
|
||||||
|
if (index < 0 || index > Count)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
Insert(index, item.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes the first occurrence of a specific media type from the <see cref="MediaTypeCollection"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item"></param>
|
||||||
|
/// <returns><code>true</code> if <paramref name="item"/> is successfully removed; otherwise, <code>false</code>.
|
||||||
|
/// This method also returns <code>false</code> if <paramref name="item"/> was not found in the original
|
||||||
|
/// <see cref="MediaTypeCollection"/>.</returns>
|
||||||
|
public bool Remove(MediaTypeHeaderValue item)
|
||||||
|
{
|
||||||
|
if (item == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Remove(item.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,120 @@
|
||||||
|
// 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 Microsoft.Extensions.Primitives;
|
||||||
|
using Microsoft.Net.Http.Headers;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Different types of tests against media type values.
|
||||||
|
/// </summary>
|
||||||
|
public static class MediaTypeComparisons
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Determines if the <paramref name="subset" /> media type is a subset of the <paramref name="set" /> media type
|
||||||
|
/// without taking into account the quality parameter.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="set">The more general media type.</param>
|
||||||
|
/// <param name="subset">The more specific media type.</param>
|
||||||
|
/// <returns><code>true</code> if <paramref name="set" /> is a more general media type than <paramref name="subset"/>;
|
||||||
|
/// otherwise <code>false</code>.</returns>
|
||||||
|
public static bool IsSubsetOf(StringSegment set, string subset)
|
||||||
|
{
|
||||||
|
return IsSubsetOf(set, new StringSegment(subset));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines if the <paramref name="subset" /> media type is a subset of the <paramref name="set" /> media type
|
||||||
|
/// without taking into account the quality parameter.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="set">The more general media type.</param>
|
||||||
|
/// <param name="subset">The more specific media type.</param>
|
||||||
|
/// <returns><code>true</code> if <paramref name="set" /> is a more general media type than <paramref name="subset"/>;
|
||||||
|
/// otherwise <code>false</code>.</returns>
|
||||||
|
public static bool IsSubsetOf(string set, string subset)
|
||||||
|
{
|
||||||
|
return IsSubsetOf(new StringSegment(set), new StringSegment(subset));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines if the <paramref name="subset" /> media type is a subset of the <paramref name="set" /> media type.
|
||||||
|
/// Two media types are compatible if one is a subset of the other ignoring any charset
|
||||||
|
/// parameter.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="set">The more general media type.</param>
|
||||||
|
/// <param name="subset">The more specific media type.</param>
|
||||||
|
/// <param name="ignoreQuality">Whether or not we should skip checking the quality parameter.</param>
|
||||||
|
/// <returns><code>true</code> if <paramref name="set" /> is a more general media type than <paramref name="subset"/>;
|
||||||
|
/// otherwise <code>false</code>.</returns>
|
||||||
|
public static bool IsSubsetOf(StringSegment set, StringSegment subset)
|
||||||
|
{
|
||||||
|
if (!set.HasValue || !subset.HasValue)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MediaTypeHeaderValue setMediaType;
|
||||||
|
MediaTypeHeaderValue subSetMediaType;
|
||||||
|
|
||||||
|
return MediaTypeHeaderValue.TryParse(set.Value, out setMediaType) &&
|
||||||
|
MediaTypeHeaderValue.TryParse(subset.Value, out subSetMediaType) &&
|
||||||
|
subSetMediaType.IsSubsetOf(setMediaType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines if the type of a given <paramref name="mediaType" /> matches all types, E.g, */*.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mediaType">The media type to check</param>
|
||||||
|
/// <returns><code>true</code> if the <paramref name="mediaType" /> matches all subtypes; otherwise <code>false</code>.</returns>
|
||||||
|
public static bool MatchesAllTypes(string mediaType)
|
||||||
|
{
|
||||||
|
return MatchesAllTypes(new StringSegment(mediaType));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines if the type of a given <paramref name="mediaType" /> matches all types, E.g, */*.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mediaType">The media type to check</param>
|
||||||
|
/// <returns><code>true</code> if the <paramref name="mediaType" /> matches all subtypes; otherwise <code>false</code>.</returns>
|
||||||
|
public static bool MatchesAllTypes(StringSegment mediaType)
|
||||||
|
{
|
||||||
|
if (!mediaType.HasValue)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MediaTypeHeaderValue parsedMediaType;
|
||||||
|
return MediaTypeHeaderValue.TryParse(mediaType.Value, out parsedMediaType) &&
|
||||||
|
parsedMediaType.MatchesAllTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines if the given <paramref name="mediaType" /> matches all subtypes, E.g, text/*.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mediaType">The media type to check</param>
|
||||||
|
/// <returns><code>true</code> if the <paramref name="mediaType" /> matches all subtypes; otherwise <code>false</code>.</returns>
|
||||||
|
public static bool MatchesAllSubtypes(string mediaType)
|
||||||
|
{
|
||||||
|
return MatchesAllSubtypes(new StringSegment(mediaType));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines if the given <paramref name="mediaType" /> matches all subtypes, E.g, text/*.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mediaType">The media type to check</param>
|
||||||
|
/// <returns><code>true</code> if the <paramref name="mediaType" /> matches all subtypes; otherwise <code>false</code>.</returns>
|
||||||
|
public static bool MatchesAllSubtypes(StringSegment mediaType)
|
||||||
|
{
|
||||||
|
if (!mediaType.HasValue)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MediaTypeHeaderValue parsedMediaType;
|
||||||
|
return MediaTypeHeaderValue.TryParse(mediaType.Value, out parsedMediaType) &&
|
||||||
|
parsedMediaType.MatchesAllSubTypes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,99 @@
|
||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
|
using Microsoft.Net.Http.Headers;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A set of operations to manipulate the encoding of a media type value.
|
||||||
|
/// </summary>
|
||||||
|
public class MediaTypeEncoding
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="Encoding"/> for the given <see cref="mediaType"/> if it exists.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mediaType">The media type from which to get the charset parameter.</param>
|
||||||
|
/// <returns>The <see cref="Encoding"/> of the media type if it exists; otherwise <code>null</code>.</returns>
|
||||||
|
public static Encoding GetEncoding(StringSegment mediaType)
|
||||||
|
{
|
||||||
|
var charset = GetCharsetParameter(mediaType);
|
||||||
|
return GetEncodingFromCharset(charset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="Encoding"/> for the given <see cref="mediaType"/> if it exists.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mediaType">The media type from which to get the charset parameter.</param>
|
||||||
|
/// <returns>The <see cref="Encoding"/> of the media type if it exists or a <see cref="StringSegment"/> without value if not.</returns>
|
||||||
|
public static Encoding GetEncoding(string mediaType)
|
||||||
|
{
|
||||||
|
var charset = GetCharsetParameter(new StringSegment(mediaType));
|
||||||
|
return GetEncodingFromCharset(charset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the charset parameter of the given <paramref name="mediaType"/> if it exists.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mediaType">The media type from which to get the charset parameter.</param>
|
||||||
|
/// <returns>The charset of the media type if it exists or a <see cref="StringSegment"/> without value if not.</returns>
|
||||||
|
public static StringSegment GetCharsetParameter(StringSegment mediaType)
|
||||||
|
{
|
||||||
|
MediaTypeHeaderValue parsedMediaType;
|
||||||
|
if (MediaTypeHeaderValue.TryParse(mediaType.Value, out parsedMediaType))
|
||||||
|
{
|
||||||
|
return new StringSegment(parsedMediaType.Charset);
|
||||||
|
}
|
||||||
|
return new StringSegment();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Replaces the encoding of the given <paramref name="mediaType"/> with the provided
|
||||||
|
/// <paramref name="encoding"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mediaType">The media type whose encoding will be replaced.</param>
|
||||||
|
/// <param name="encoding">The encoding that will replace the encoding in the <paramref name="mediaType"/></param>
|
||||||
|
/// <returns>A media type with the replaced encoding.</returns>
|
||||||
|
public static string ReplaceEncoding(string mediaType, Encoding encoding)
|
||||||
|
{
|
||||||
|
return ReplaceEncoding(new StringSegment(mediaType), encoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Replaces the encoding of the given <paramref name="mediaType"/> with the provided
|
||||||
|
/// <paramref name="encoding"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mediaType">The media type whose encoding will be replaced.</param>
|
||||||
|
/// <param name="encoding">The encoding that will replace the encoding in the <paramref name="mediaType"/></param>
|
||||||
|
/// <returns>A media type with the replaced encoding.</returns>
|
||||||
|
public static string ReplaceEncoding(StringSegment mediaType, Encoding encoding)
|
||||||
|
{
|
||||||
|
var parsedMediaType = MediaTypeHeaderValue.Parse(mediaType.Value);
|
||||||
|
parsedMediaType.Encoding = encoding;
|
||||||
|
|
||||||
|
return parsedMediaType.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Encoding GetEncodingFromCharset(StringSegment charset)
|
||||||
|
{
|
||||||
|
if (charset.Equals("utf-8", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
// This is an optimization for utf-8 that prevents the Substring caused by
|
||||||
|
// charset.Value
|
||||||
|
return Encoding.UTF8;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// charset.Value might be an invalid encoding name as in charset=invalid.
|
||||||
|
// For that reason, we catch the exception thrown by Encoding.GetEncoding
|
||||||
|
// and return null instead.
|
||||||
|
return charset.HasValue ? Encoding.GetEncoding(charset.Value) : null;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A media type with its associated quality.
|
||||||
|
/// </summary>
|
||||||
|
public struct MediaTypeSegmentWithQuality
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes an instance of <see cref="MediaTypeSegmentWithQuality"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mediaType">The <see cref="StringSegment"/> containing the media type.</param>
|
||||||
|
/// <param name="quality">The quality parameter of the media type or 1 in the case it does not exist.</param>
|
||||||
|
public MediaTypeSegmentWithQuality(StringSegment mediaType, double quality)
|
||||||
|
{
|
||||||
|
MediaType = mediaType;
|
||||||
|
Quality = quality;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the media type of this <see cref="MediaTypeSegmentWithQuality"/>.
|
||||||
|
/// </summary>
|
||||||
|
public StringSegment MediaType { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the quality of this <see cref="MediaTypeSegmentWithQuality"/>.
|
||||||
|
/// </summary>
|
||||||
|
public double Quality { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
// For logging purposes
|
||||||
|
return MediaType.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,6 +8,7 @@ using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Http;
|
using Microsoft.AspNet.Http;
|
||||||
using Microsoft.AspNet.Mvc.ApiExplorer;
|
using Microsoft.AspNet.Mvc.ApiExplorer;
|
||||||
using Microsoft.AspNet.Mvc.Core;
|
using Microsoft.AspNet.Mvc.Core;
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Formatters
|
namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
|
|
@ -17,16 +18,13 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class OutputFormatter : IOutputFormatter, IApiResponseFormatMetadataProvider
|
public abstract class OutputFormatter : IOutputFormatter, IApiResponseFormatMetadataProvider
|
||||||
{
|
{
|
||||||
// using a field so we can return it as both IList and IReadOnlyList
|
|
||||||
private readonly List<MediaTypeHeaderValue> _supportedMediaTypes;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="OutputFormatter"/> class.
|
/// Initializes a new instance of the <see cref="OutputFormatter"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected OutputFormatter()
|
protected OutputFormatter()
|
||||||
{
|
{
|
||||||
SupportedEncodings = new List<Encoding>();
|
SupportedEncodings = new List<Encoding>();
|
||||||
_supportedMediaTypes = new List<MediaTypeHeaderValue>();
|
SupportedMediaTypes = new MediaTypeCollection();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -37,13 +35,10 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
public IList<Encoding> SupportedEncodings { get; }
|
public IList<Encoding> SupportedEncodings { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the mutable collection of <see cref="MediaTypeHeaderValue"/> elements supported by
|
/// Gets the mutable collection of media type elements supported by
|
||||||
/// this <see cref="OutputFormatter"/>.
|
/// this <see cref="OutputFormatter"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IList<MediaTypeHeaderValue> SupportedMediaTypes
|
public MediaTypeCollection SupportedMediaTypes { get; }
|
||||||
{
|
|
||||||
get { return _supportedMediaTypes; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a value indicating whether or not the given type can be written by this serializer.
|
/// Returns a value indicating whether or not the given type can be written by this serializer.
|
||||||
|
|
@ -56,8 +51,8 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual IReadOnlyList<MediaTypeHeaderValue> GetSupportedContentTypes(
|
public virtual IReadOnlyList<string> GetSupportedContentTypes(
|
||||||
MediaTypeHeaderValue contentType,
|
string contentType,
|
||||||
Type objectType)
|
Type objectType)
|
||||||
{
|
{
|
||||||
if (!CanWriteType(objectType))
|
if (!CanWriteType(objectType))
|
||||||
|
|
@ -68,21 +63,21 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
if (contentType == null)
|
if (contentType == null)
|
||||||
{
|
{
|
||||||
// If contentType is null, then any type we support is valid.
|
// If contentType is null, then any type we support is valid.
|
||||||
return _supportedMediaTypes.Count > 0 ? _supportedMediaTypes : null;
|
return SupportedMediaTypes.Count > 0 ? SupportedMediaTypes : null;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
List<MediaTypeHeaderValue> mediaTypes = null;
|
List<string> mediaTypes = null;
|
||||||
|
|
||||||
// Confirm this formatter supports a more specific media type than requested e.g. OK if "text/*"
|
// 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.
|
// 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 (MediaTypeComparisons.IsSubsetOf(new StringSegment(contentType), mediaType))
|
||||||
{
|
{
|
||||||
if (mediaTypes == null)
|
if (mediaTypes == null)
|
||||||
{
|
{
|
||||||
mediaTypes = new List<MediaTypeHeaderValue>();
|
mediaTypes = new List<string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
mediaTypes.Add(mediaType);
|
mediaTypes.Add(mediaType);
|
||||||
|
|
@ -114,15 +109,19 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
return encoding;
|
return encoding;
|
||||||
}
|
}
|
||||||
|
|
||||||
var charset = context.ContentType?.Charset;
|
if (context.ContentType.HasValue)
|
||||||
if (charset != null)
|
|
||||||
{
|
{
|
||||||
for (var i = 0; i < SupportedEncodings.Count; i++)
|
var contentTypeEncoding = MediaTypeEncoding.GetCharsetParameter(context.ContentType);
|
||||||
|
if (contentTypeEncoding.HasValue)
|
||||||
{
|
{
|
||||||
if (string.Equals(charset, SupportedEncodings[i].WebName, StringComparison.OrdinalIgnoreCase))
|
for (var i = 0; i < SupportedEncodings.Count; i++)
|
||||||
{
|
{
|
||||||
// This is supported.
|
var supportedEncoding = SupportedEncodings[i];
|
||||||
return context.ContentType.Encoding;
|
if (contentTypeEncoding.Equals(supportedEncoding.WebName, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
// This is supported.
|
||||||
|
return SupportedEncodings[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -138,19 +137,19 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(context));
|
throw new ArgumentNullException(nameof(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CanWriteType(context.ObjectType))
|
if (!CanWriteType(context.ObjectType))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context.ContentType == null)
|
if (!context.ContentType.HasValue)
|
||||||
{
|
{
|
||||||
// If the desired content type is set to null, then the current formatter can write anything
|
// If the desired content type is set to null, then the current formatter can write anything
|
||||||
// it wants.
|
// it wants.
|
||||||
if (SupportedMediaTypes.Count > 0)
|
if (SupportedMediaTypes.Count > 0)
|
||||||
{
|
{
|
||||||
context.ContentType = SupportedMediaTypes[0];
|
context.ContentType = new StringSegment(SupportedMediaTypes[0]);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -163,12 +162,13 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
// Confirm this formatter supports a more specific media type than requested e.g. OK if "text/*"
|
// Confirm this formatter supports a more specific media type than requested e.g. OK if "text/*"
|
||||||
// requested and formatter supports "text/plain". contentType is typically what we got in an Accept
|
// requested and formatter supports "text/plain". contentType is typically what we got in an Accept
|
||||||
// header.
|
// header.
|
||||||
|
var contentType = context.ContentType;
|
||||||
for (var i = 0; i < SupportedMediaTypes.Count; i++)
|
for (var i = 0; i < SupportedMediaTypes.Count; i++)
|
||||||
{
|
{
|
||||||
var mediaType = SupportedMediaTypes[i];
|
var supportedMediaType = SupportedMediaTypes[i];
|
||||||
if (mediaType.IsSubsetOf(context.ContentType))
|
if (MediaTypeComparisons.IsSubsetOf(contentType, supportedMediaType))
|
||||||
{
|
{
|
||||||
context.ContentType = mediaType;
|
context.ContentType = new StringSegment(SupportedMediaTypes[i]);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -186,12 +186,12 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
}
|
}
|
||||||
|
|
||||||
var selectedMediaType = context.ContentType;
|
var selectedMediaType = context.ContentType;
|
||||||
if (selectedMediaType == null)
|
if (!selectedMediaType.HasValue)
|
||||||
{
|
{
|
||||||
// If content type is not set then set it based on supported media types.
|
// If content type is not set then set it based on supported media types.
|
||||||
if (SupportedEncodings.Count > 0)
|
if (SupportedEncodings.Count > 0)
|
||||||
{
|
{
|
||||||
selectedMediaType = SupportedMediaTypes[0];
|
selectedMediaType = new StringSegment(SupportedMediaTypes[0]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -199,9 +199,6 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy the media type as it may be a 'frozen' instance.
|
|
||||||
selectedMediaType = selectedMediaType.Copy();
|
|
||||||
|
|
||||||
// Note: 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.
|
||||||
//
|
//
|
||||||
|
|
@ -215,7 +212,8 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
if (selectedEncoding != null)
|
if (selectedEncoding != null)
|
||||||
{
|
{
|
||||||
// Override the content type value even if one already existed.
|
// Override the content type value even if one already existed.
|
||||||
selectedMediaType.Encoding = selectedEncoding;
|
var mediaTypeWithCharset = GetMediaTypeWithCharset(selectedMediaType.Value, selectedEncoding);
|
||||||
|
selectedMediaType = new StringSegment(mediaTypeWithCharset);
|
||||||
}
|
}
|
||||||
|
|
||||||
context.ContentType = selectedMediaType;
|
context.ContentType = selectedMediaType;
|
||||||
|
|
@ -236,7 +234,7 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
}
|
}
|
||||||
|
|
||||||
var response = context.HttpContext.Response;
|
var response = context.HttpContext.Response;
|
||||||
response.ContentType = context.ContentType?.ToString();
|
response.ContentType = context.ContentType.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -246,6 +244,33 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
/// <returns>A task which can write the response body.</returns>
|
/// <returns>A task which can write the response body.</returns>
|
||||||
public abstract Task WriteResponseBodyAsync(OutputFormatterWriteContext context);
|
public abstract Task WriteResponseBodyAsync(OutputFormatterWriteContext context);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds or replaces the charset parameter in a given <paramref name="mediaType"/> with the
|
||||||
|
/// given <paramref name="encoding"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mediaType">The <see cref="StringSegment"/> with the media type.</param>
|
||||||
|
/// <param name="encoding">
|
||||||
|
/// The <see cref="Encoding"/> to add or replace in the <paramref name="mediaType"/>.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>The mediaType with the given encoding.</returns>
|
||||||
|
protected string GetMediaTypeWithCharset(string mediaType, Encoding encoding)
|
||||||
|
{
|
||||||
|
var mediaTypeEncoding = MediaTypeEncoding.GetEncoding(mediaType);
|
||||||
|
if (mediaTypeEncoding == encoding)
|
||||||
|
{
|
||||||
|
return mediaType;
|
||||||
|
}
|
||||||
|
else if (mediaTypeEncoding == null)
|
||||||
|
{
|
||||||
|
return CreateMediaTypeWithEncoding(mediaType, encoding);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// This can happen if the user has overriden SelectCharacterEncoding
|
||||||
|
return MediaTypeEncoding.ReplaceEncoding(mediaType, encoding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Encoding MatchAcceptCharacterEncoding(IList<StringWithQualityHeaderValue> acceptCharsetHeaders)
|
private Encoding MatchAcceptCharacterEncoding(IList<StringWithQualityHeaderValue> acceptCharsetHeaders)
|
||||||
{
|
{
|
||||||
if (acceptCharsetHeaders != null && acceptCharsetHeaders.Count > 0)
|
if (acceptCharsetHeaders != null && acceptCharsetHeaders.Count > 0)
|
||||||
|
|
@ -329,5 +354,15 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
sorted.Reverse();
|
sorted.Reverse();
|
||||||
return sorted;
|
return sorted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string CreateMediaTypeWithEncoding(string mediaType, Encoding encoding)
|
||||||
|
{
|
||||||
|
return CreateMediaTypeWithEncoding(new StringSegment(mediaType), encoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string CreateMediaTypeWithEncoding(StringSegment mediaType, Encoding encoding)
|
||||||
|
{
|
||||||
|
return $"{mediaType.Value}; charset={encoding.WebName}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Http;
|
using Microsoft.AspNet.Http;
|
||||||
using Microsoft.AspNet.Mvc.Internal;
|
using Microsoft.AspNet.Mvc.Internal;
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Formatters
|
namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
|
|
@ -19,7 +20,7 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
{
|
{
|
||||||
SupportedEncodings.Add(Encoding.UTF8);
|
SupportedEncodings.Add(Encoding.UTF8);
|
||||||
SupportedEncodings.Add(Encoding.Unicode);
|
SupportedEncodings.Add(Encoding.Unicode);
|
||||||
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/plain").CopyAsReadOnly());
|
SupportedMediaTypes.Add("text/plain");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool CanWriteResult(OutputFormatterCanWriteContext context)
|
public override bool CanWriteResult(OutputFormatterCanWriteContext context)
|
||||||
|
|
@ -33,7 +34,7 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
// always return it as a text/plain format.
|
// always return it as a text/plain format.
|
||||||
if (context.ObjectType == typeof(string) || context.Object is string)
|
if (context.ObjectType == typeof(string) || context.Object is string)
|
||||||
{
|
{
|
||||||
context.ContentType = SupportedMediaTypes[0];
|
context.ContentType = new StringSegment(SupportedMediaTypes[0]);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -55,7 +56,9 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
|
|
||||||
var response = context.HttpContext.Response;
|
var response = context.HttpContext.Response;
|
||||||
|
|
||||||
return response.WriteAsync(valueAsString, context.ContentType?.Encoding ?? Encoding.UTF8);
|
return response.WriteAsync(
|
||||||
|
valueAsString,
|
||||||
|
MediaTypeEncoding.GetEncoding(context.ContentType) ?? Encoding.UTF8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ using Microsoft.AspNet.Mvc.Internal;
|
||||||
using Microsoft.AspNet.Mvc.Logging;
|
using Microsoft.AspNet.Mvc.Logging;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Infrastructure
|
namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
|
|
@ -98,10 +99,10 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
{
|
{
|
||||||
if (result.ContentTypes == null)
|
if (result.ContentTypes == null)
|
||||||
{
|
{
|
||||||
result.ContentTypes = new List<MediaTypeHeaderValue>();
|
result.ContentTypes = new MediaTypeCollection();
|
||||||
}
|
}
|
||||||
|
|
||||||
result.ContentTypes.Add(MediaTypeHeaderValue.Parse(responseContentType));
|
result.ContentTypes.Add(responseContentType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -157,7 +158,7 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
/// </returns>
|
/// </returns>
|
||||||
protected virtual IOutputFormatter SelectFormatter(
|
protected virtual IOutputFormatter SelectFormatter(
|
||||||
OutputFormatterWriteContext formatterContext,
|
OutputFormatterWriteContext formatterContext,
|
||||||
IList<MediaTypeHeaderValue> contentTypes,
|
MediaTypeCollection contentTypes,
|
||||||
IList<IOutputFormatter> formatters)
|
IList<IOutputFormatter> formatters)
|
||||||
{
|
{
|
||||||
if (formatterContext == null)
|
if (formatterContext == null)
|
||||||
|
|
@ -185,14 +186,14 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
}
|
}
|
||||||
|
|
||||||
var request = formatterContext.HttpContext.Request;
|
var request = formatterContext.HttpContext.Request;
|
||||||
var acceptValues = PrepareAcceptValues(request.GetTypedHeaders().Accept);
|
|
||||||
|
|
||||||
|
var mediaTypes = GetMediaTypes(contentTypes, request);
|
||||||
IOutputFormatter selectedFormatter = null;
|
IOutputFormatter selectedFormatter = null;
|
||||||
if (contentTypes == null || contentTypes.Count == 0)
|
if (contentTypes.Count == 0)
|
||||||
{
|
{
|
||||||
// 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. Let the formatter choose the Content-Type.
|
// which can write the type. Let the formatter choose the Content-Type.
|
||||||
if (acceptValues == null || acceptValues.Count == 0)
|
if (!(mediaTypes.Count > 0))
|
||||||
{
|
{
|
||||||
Logger.NoAcceptForNegotiation();
|
Logger.NoAcceptForNegotiation();
|
||||||
|
|
||||||
|
|
@ -207,13 +208,13 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
selectedFormatter = SelectFormatterUsingSortedAcceptHeaders(
|
selectedFormatter = SelectFormatterUsingSortedAcceptHeaders(
|
||||||
formatterContext,
|
formatterContext,
|
||||||
formatters,
|
formatters,
|
||||||
acceptValues);
|
mediaTypes);
|
||||||
|
|
||||||
// 2. No formatter was found based on Accept header. Fallback to the first formatter which can write
|
// 2. No formatter was found based on Accept header. Fallback to the first formatter which can write
|
||||||
// the type. Let the formatter choose the Content-Type.
|
// the type. Let the formatter choose the Content-Type.
|
||||||
if (selectedFormatter == null)
|
if (selectedFormatter == null)
|
||||||
{
|
{
|
||||||
Logger.NoFormatterFromNegotiation(acceptValues);
|
Logger.NoFormatterFromNegotiation(mediaTypes);
|
||||||
|
|
||||||
// Set this flag to indicate that content-negotiation has failed to let formatters decide
|
// Set this flag to indicate that content-negotiation has failed to let formatters decide
|
||||||
// if they want to write the response or not.
|
// if they want to write the response or not.
|
||||||
|
|
@ -224,32 +225,12 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (acceptValues != null && acceptValues.Count > 0)
|
if (mediaTypes.Count > 0)
|
||||||
{
|
{
|
||||||
// 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".
|
|
||||||
for (var i = acceptValues.Count - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
var isCompatible = false;
|
|
||||||
for (var j = 0; j < contentTypes.Count; j++)
|
|
||||||
{
|
|
||||||
if (contentTypes[j].IsSubsetOf(acceptValues[i]))
|
|
||||||
{
|
|
||||||
isCompatible = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isCompatible)
|
|
||||||
{
|
|
||||||
acceptValues.RemoveAt(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
selectedFormatter = SelectFormatterUsingSortedAcceptHeaders(
|
selectedFormatter = SelectFormatterUsingSortedAcceptHeaders(
|
||||||
formatterContext,
|
formatterContext,
|
||||||
formatters,
|
formatters,
|
||||||
acceptValues);
|
mediaTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selectedFormatter == null)
|
if (selectedFormatter == null)
|
||||||
|
|
@ -270,6 +251,58 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
return selectedFormatter;
|
return selectedFormatter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<MediaTypeSegmentWithQuality> GetMediaTypes(
|
||||||
|
MediaTypeCollection contentTypes,
|
||||||
|
HttpRequest request)
|
||||||
|
{
|
||||||
|
var result = new List<MediaTypeSegmentWithQuality>();
|
||||||
|
var parsedHeaders = request.GetTypedHeaders().Accept;
|
||||||
|
for (var i = 0; i < parsedHeaders?.Count; i++)
|
||||||
|
{
|
||||||
|
result.Add(new MediaTypeSegmentWithQuality(
|
||||||
|
new StringSegment(parsedHeaders[i].ToString()),
|
||||||
|
parsedHeaders[i].Quality ?? 1.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < result.Count; i++)
|
||||||
|
{
|
||||||
|
if (!RespectBrowserAcceptHeader &&
|
||||||
|
MediaTypeComparisons.MatchesAllTypes(result[i].MediaType) &&
|
||||||
|
MediaTypeComparisons.MatchesAllSubtypes(result[i].MediaType))
|
||||||
|
{
|
||||||
|
result.Clear();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!InAcceptableMediaTypes(result[i].MediaType, contentTypes))
|
||||||
|
{
|
||||||
|
result.RemoveAt(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Sort((left, right) => left.Quality > right.Quality ? -1 : (left.Quality == right.Quality ? 0 : 1));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool InAcceptableMediaTypes(StringSegment mediaType, MediaTypeCollection acceptableMediaTypes)
|
||||||
|
{
|
||||||
|
if (acceptableMediaTypes.Count == 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < acceptableMediaTypes.Count; i++)
|
||||||
|
{
|
||||||
|
if (MediaTypeComparisons.IsSubsetOf(mediaType, acceptableMediaTypes[i]))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Selects the <see cref="IOutputFormatter"/> to write the response. The first formatter which
|
/// Selects the <see cref="IOutputFormatter"/> to write the response. The first formatter which
|
||||||
/// can write the response should be chosen without any consideration for content type.
|
/// can write the response should be chosen without any consideration for content type.
|
||||||
|
|
@ -297,7 +330,7 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
|
|
||||||
foreach (var formatter in formatters)
|
foreach (var formatter in formatters)
|
||||||
{
|
{
|
||||||
formatterContext.ContentType = null;
|
formatterContext.ContentType = new StringSegment();
|
||||||
if (formatter.CanWriteResult(formatterContext))
|
if (formatter.CanWriteResult(formatterContext))
|
||||||
{
|
{
|
||||||
return formatter;
|
return formatter;
|
||||||
|
|
@ -324,7 +357,7 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
protected virtual IOutputFormatter SelectFormatterUsingSortedAcceptHeaders(
|
protected virtual IOutputFormatter SelectFormatterUsingSortedAcceptHeaders(
|
||||||
OutputFormatterWriteContext formatterContext,
|
OutputFormatterWriteContext formatterContext,
|
||||||
IList<IOutputFormatter> formatters,
|
IList<IOutputFormatter> formatters,
|
||||||
IList<MediaTypeHeaderValue> sortedAcceptHeaders)
|
IList<MediaTypeSegmentWithQuality> sortedAcceptHeaders)
|
||||||
{
|
{
|
||||||
if (formatterContext == null)
|
if (formatterContext == null)
|
||||||
{
|
{
|
||||||
|
|
@ -341,11 +374,13 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
throw new ArgumentNullException(nameof(sortedAcceptHeaders));
|
throw new ArgumentNullException(nameof(sortedAcceptHeaders));
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var contentType in sortedAcceptHeaders)
|
for (var i = 0; i < sortedAcceptHeaders.Count; i++)
|
||||||
{
|
{
|
||||||
foreach (var formatter in formatters)
|
var mediaType = sortedAcceptHeaders[i];
|
||||||
|
formatterContext.ContentType = mediaType.MediaType;
|
||||||
|
for(var j = 0;j < formatters.Count;j++)
|
||||||
{
|
{
|
||||||
formatterContext.ContentType = contentType;
|
var formatter = formatters[j];
|
||||||
if (formatter.CanWriteResult(formatterContext))
|
if (formatter.CanWriteResult(formatterContext))
|
||||||
{
|
{
|
||||||
return formatter;
|
return formatter;
|
||||||
|
|
@ -373,7 +408,7 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
protected virtual IOutputFormatter SelectFormatterUsingAnyAcceptableContentType(
|
protected virtual IOutputFormatter SelectFormatterUsingAnyAcceptableContentType(
|
||||||
OutputFormatterWriteContext formatterContext,
|
OutputFormatterWriteContext formatterContext,
|
||||||
IList<IOutputFormatter> formatters,
|
IList<IOutputFormatter> formatters,
|
||||||
IList<MediaTypeHeaderValue> acceptableContentTypes)
|
MediaTypeCollection acceptableContentTypes)
|
||||||
{
|
{
|
||||||
if (formatterContext == null)
|
if (formatterContext == null)
|
||||||
{
|
{
|
||||||
|
|
@ -394,7 +429,7 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
{
|
{
|
||||||
foreach (var contentType in acceptableContentTypes)
|
foreach (var contentType in acceptableContentTypes)
|
||||||
{
|
{
|
||||||
formatterContext.ContentType = contentType;
|
formatterContext.ContentType = new StringSegment(contentType);
|
||||||
if (formatter.CanWriteResult(formatterContext))
|
if (formatter.CanWriteResult(formatterContext))
|
||||||
{
|
{
|
||||||
return formatter;
|
return formatter;
|
||||||
|
|
@ -405,90 +440,7 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// There's no allocation-free way to sort an IList so we're going to have to live with the
|
private void ValidateContentTypes(MediaTypeCollection contentTypes)
|
||||||
// copy + insertion sort.
|
|
||||||
private IList<MediaTypeHeaderValue> PrepareAcceptValues(IList<MediaTypeHeaderValue> values)
|
|
||||||
{
|
|
||||||
if (values == null || values.Count == 0)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// By default we want to ignore considering accept headers for content negotiation when
|
|
||||||
// they have a media type like */* in them. Browsers typically have these media types.
|
|
||||||
// In these cases we would want the first formatter in the list of output formatters to
|
|
||||||
// write the response. This default behavior can be changed through options, so checking here.
|
|
||||||
if (!RespectBrowserAcceptHeader)
|
|
||||||
{
|
|
||||||
for (var i = 0; i < values.Count; i++)
|
|
||||||
{
|
|
||||||
if (values[i].MatchesAllTypes)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Degenerate case, we can avoid copying anything.
|
|
||||||
if (values.Count == 1)
|
|
||||||
{
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
|
|
||||||
var sortNeeded = false;
|
|
||||||
var count = 0;
|
|
||||||
|
|
||||||
for (var i = 0; i < values.Count; i++)
|
|
||||||
{
|
|
||||||
var value = values[i];
|
|
||||||
if (value.Quality == HeaderQuality.NoMatch)
|
|
||||||
{
|
|
||||||
// Exclude this one
|
|
||||||
}
|
|
||||||
else if (value.Quality != null)
|
|
||||||
{
|
|
||||||
count++;
|
|
||||||
sortNeeded = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!sortNeeded)
|
|
||||||
{
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
|
|
||||||
var sorted = new List<MediaTypeHeaderValue>(count);
|
|
||||||
for (var i = 0; i < values.Count; i++)
|
|
||||||
{
|
|
||||||
var value = values[i];
|
|
||||||
if (value.Quality == HeaderQuality.NoMatch)
|
|
||||||
{
|
|
||||||
// Exclude this one
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var position = sorted.BinarySearch(value, MediaTypeHeaderValueComparer.QualityComparer);
|
|
||||||
if (position >= 0)
|
|
||||||
{
|
|
||||||
sorted.Insert(position + 1, value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sorted.Insert(~position, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We want a descending sort, but BinarySearch does ascending
|
|
||||||
sorted.Reverse();
|
|
||||||
return sorted;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ValidateContentTypes(IList<MediaTypeHeaderValue> contentTypes)
|
|
||||||
{
|
{
|
||||||
if (contentTypes == null)
|
if (contentTypes == null)
|
||||||
{
|
{
|
||||||
|
|
@ -498,7 +450,8 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
for (var i = 0; i < contentTypes.Count; i++)
|
for (var i = 0; i < contentTypes.Count; i++)
|
||||||
{
|
{
|
||||||
var contentType = contentTypes[i];
|
var contentType = contentTypes[i];
|
||||||
if (contentType.MatchesAllTypes || contentType.MatchesAllSubTypes)
|
if (MediaTypeComparisons.MatchesAllTypes(contentType) ||
|
||||||
|
MediaTypeComparisons.MatchesAllSubtypes(contentType))
|
||||||
{
|
{
|
||||||
var message = Resources.FormatObjectResult_MatchAllContentType(
|
var message = Resources.FormatObjectResult_MatchAllContentType(
|
||||||
contentType,
|
contentType,
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,7 @@
|
||||||
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.AspNet.Mvc.Formatters;
|
||||||
using Microsoft.AspNet.Http;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Internal
|
namespace Microsoft.AspNet.Mvc.Internal
|
||||||
{
|
{
|
||||||
|
|
@ -30,44 +29,47 @@ namespace Microsoft.AspNet.Mvc.Internal
|
||||||
/// <param name="resolvedContentType">The content type to be used for the response content type header</param>
|
/// <param name="resolvedContentType">The content type to be used for the response content type header</param>
|
||||||
/// <param name="resolvedContentTypeEncoding">Encoding to be used for writing the response</param>
|
/// <param name="resolvedContentTypeEncoding">Encoding to be used for writing the response</param>
|
||||||
public static void ResolveContentTypeAndEncoding(
|
public static void ResolveContentTypeAndEncoding(
|
||||||
MediaTypeHeaderValue actionResultContentType,
|
string actionResultContentType,
|
||||||
string httpResponseContentType,
|
string httpResponseContentType,
|
||||||
MediaTypeHeaderValue defaultContentType,
|
string defaultContentType,
|
||||||
out string resolvedContentType,
|
out string resolvedContentType,
|
||||||
out Encoding resolvedContentTypeEncoding)
|
out Encoding resolvedContentTypeEncoding)
|
||||||
{
|
{
|
||||||
Debug.Assert(defaultContentType != null);
|
Debug.Assert(defaultContentType != null);
|
||||||
Debug.Assert(defaultContentType.Encoding != null);
|
|
||||||
|
var defaultContentTypeEncoding = MediaTypeEncoding.GetEncoding(defaultContentType);
|
||||||
|
Debug.Assert(defaultContentTypeEncoding != null);
|
||||||
|
|
||||||
// 1. User sets the ContentType property on the action result
|
// 1. User sets the ContentType property on the action result
|
||||||
if (actionResultContentType != null)
|
if (actionResultContentType != null)
|
||||||
{
|
{
|
||||||
resolvedContentType = actionResultContentType.ToString();
|
resolvedContentType = actionResultContentType;
|
||||||
resolvedContentTypeEncoding = actionResultContentType.Encoding ?? defaultContentType.Encoding;
|
var actionResultEncoding = MediaTypeEncoding.GetEncoding(actionResultContentType);
|
||||||
|
resolvedContentTypeEncoding = actionResultEncoding ?? defaultContentTypeEncoding;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. User sets the ContentType property on the http response directly
|
// 2. User sets the ContentType property on the http response directly
|
||||||
if (!string.IsNullOrEmpty(httpResponseContentType))
|
if (!string.IsNullOrEmpty(httpResponseContentType))
|
||||||
{
|
{
|
||||||
MediaTypeHeaderValue mediaType;
|
var mediaTypeEncoding = MediaTypeEncoding.GetEncoding(httpResponseContentType);
|
||||||
if (MediaTypeHeaderValue.TryParse(httpResponseContentType, out mediaType))
|
if (mediaTypeEncoding != null)
|
||||||
{
|
{
|
||||||
resolvedContentType = httpResponseContentType;
|
resolvedContentType = httpResponseContentType;
|
||||||
resolvedContentTypeEncoding = mediaType.Encoding ?? defaultContentType.Encoding;
|
resolvedContentTypeEncoding = mediaTypeEncoding;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
resolvedContentType = httpResponseContentType;
|
resolvedContentType = httpResponseContentType;
|
||||||
resolvedContentTypeEncoding = defaultContentType.Encoding;
|
resolvedContentTypeEncoding = defaultContentTypeEncoding;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Fall-back to the default content type
|
// 3. Fall-back to the default content type
|
||||||
resolvedContentType = defaultContentType.ToString();
|
resolvedContentType = defaultContentType;
|
||||||
resolvedContentTypeEncoding = defaultContentType.Encoding;
|
resolvedContentTypeEncoding = defaultContentTypeEncoding;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.AspNet.Mvc.Formatters;
|
using Microsoft.AspNet.Mvc.Formatters;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Logging
|
namespace Microsoft.AspNet.Mvc.Logging
|
||||||
|
|
@ -16,7 +17,7 @@ namespace Microsoft.AspNet.Mvc.Logging
|
||||||
private static readonly Action<ILogger, IOutputFormatter, string, Exception> _formatterSelected;
|
private static readonly Action<ILogger, IOutputFormatter, string, Exception> _formatterSelected;
|
||||||
private static readonly Action<ILogger, string, Exception> _skippedContentNegotiation;
|
private static readonly Action<ILogger, string, Exception> _skippedContentNegotiation;
|
||||||
private static readonly Action<ILogger, string, Exception> _noAcceptForNegotiation;
|
private static readonly Action<ILogger, string, Exception> _noAcceptForNegotiation;
|
||||||
private static readonly Action<ILogger, IEnumerable<MediaTypeHeaderValue>, Exception> _noFormatterFromNegotiation;
|
private static readonly Action<ILogger, IEnumerable<MediaTypeSegmentWithQuality>, Exception> _noFormatterFromNegotiation;
|
||||||
|
|
||||||
static ObjectResultExecutorLoggerExtensions()
|
static ObjectResultExecutorLoggerExtensions()
|
||||||
{
|
{
|
||||||
|
|
@ -40,7 +41,7 @@ namespace Microsoft.AspNet.Mvc.Logging
|
||||||
LogLevel.Debug,
|
LogLevel.Debug,
|
||||||
4,
|
4,
|
||||||
"No information found on request to perform content negotiation.");
|
"No information found on request to perform content negotiation.");
|
||||||
_noFormatterFromNegotiation = LoggerMessage.Define<IEnumerable<MediaTypeHeaderValue>>(
|
_noFormatterFromNegotiation = LoggerMessage.Define<IEnumerable<MediaTypeSegmentWithQuality>>(
|
||||||
LogLevel.Debug,
|
LogLevel.Debug,
|
||||||
5,
|
5,
|
||||||
"Could not find an output formatter based on content negotiation. Accepted types were ({AcceptTypes})");
|
"Could not find an output formatter based on content negotiation. Accepted types were ({AcceptTypes})");
|
||||||
|
|
@ -67,9 +68,9 @@ namespace Microsoft.AspNet.Mvc.Logging
|
||||||
_formatterSelected(logger, outputFormatter, contentType, null);
|
_formatterSelected(logger, outputFormatter, contentType, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SkippedContentNegotiation(this ILogger logger, MediaTypeHeaderValue contentType)
|
public static void SkippedContentNegotiation(this ILogger logger, string contentType)
|
||||||
{
|
{
|
||||||
_skippedContentNegotiation(logger, Convert.ToString(contentType), null);
|
_skippedContentNegotiation(logger, contentType, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void NoAcceptForNegotiation(this ILogger logger)
|
public static void NoAcceptForNegotiation(this ILogger logger)
|
||||||
|
|
@ -77,7 +78,7 @@ namespace Microsoft.AspNet.Mvc.Logging
|
||||||
_noAcceptForNegotiation(logger, null, null);
|
_noAcceptForNegotiation(logger, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void NoFormatterFromNegotiation(this ILogger logger, IEnumerable<MediaTypeHeaderValue> acceptTypes)
|
public static void NoFormatterFromNegotiation(this ILogger logger, IList<MediaTypeSegmentWithQuality> acceptTypes)
|
||||||
{
|
{
|
||||||
_noFormatterFromNegotiation(logger, acceptTypes, null);
|
_noFormatterFromNegotiation(logger, acceptTypes, null);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,8 +53,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
public FilterCollection Filters { get; }
|
public FilterCollection Filters { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used to specify mapping between the URL Format and corresponding
|
/// Used to specify mapping between the URL Format and corresponding media type.
|
||||||
/// <see cref="Net.Http.Headers.MediaTypeHeaderValue"/>.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public FormatterMappings FormatterMappings { get; }
|
public FormatterMappings FormatterMappings { get; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,10 @@
|
||||||
// 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.Generic;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Mvc.Formatters;
|
using Microsoft.AspNet.Mvc.Formatters;
|
||||||
using Microsoft.AspNet.Mvc.Infrastructure;
|
using Microsoft.AspNet.Mvc.Infrastructure;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Net.Http.Headers;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
|
|
@ -17,14 +15,14 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
Value = value;
|
Value = value;
|
||||||
Formatters = new FormatterCollection<IOutputFormatter>();
|
Formatters = new FormatterCollection<IOutputFormatter>();
|
||||||
ContentTypes = new List<MediaTypeHeaderValue>();
|
ContentTypes = new MediaTypeCollection();
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Value { get; set; }
|
public object Value { get; set; }
|
||||||
|
|
||||||
public FormatterCollection<IOutputFormatter> Formatters { get; set; }
|
public FormatterCollection<IOutputFormatter> Formatters { get; set; }
|
||||||
|
|
||||||
public IList<MediaTypeHeaderValue> ContentTypes { get; set; }
|
public MediaTypeCollection ContentTypes { get; set; }
|
||||||
|
|
||||||
public Type DeclaredType { get; set; }
|
public Type DeclaredType { get; set; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,10 +34,6 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(fileName));
|
throw new ArgumentNullException(nameof(fileName));
|
||||||
}
|
}
|
||||||
if (contentType == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(contentType));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -47,18 +43,13 @@ namespace Microsoft.AspNet.Mvc
|
||||||
/// <param name="fileName">The path to the file. The path must be an absolute path.</param>
|
/// <param name="fileName">The path to the file. The path must be an absolute path.</param>
|
||||||
/// <param name="contentType">The Content-Type header of the response.</param>
|
/// <param name="contentType">The Content-Type header of the response.</param>
|
||||||
public PhysicalFileResult(string fileName, MediaTypeHeaderValue contentType)
|
public PhysicalFileResult(string fileName, MediaTypeHeaderValue contentType)
|
||||||
: base(contentType)
|
: base(contentType?.ToString())
|
||||||
{
|
{
|
||||||
if (fileName == null)
|
if (fileName == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(fileName));
|
throw new ArgumentNullException(nameof(fileName));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (contentType == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(contentType));
|
|
||||||
}
|
|
||||||
|
|
||||||
FileName = fileName;
|
FileName = fileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ using Microsoft.AspNet.Mvc.ApiExplorer;
|
||||||
using Microsoft.AspNet.Mvc.Core;
|
using Microsoft.AspNet.Mvc.Core;
|
||||||
using Microsoft.AspNet.Mvc.Filters;
|
using Microsoft.AspNet.Mvc.Filters;
|
||||||
using Microsoft.AspNet.Mvc.Formatters;
|
using Microsoft.AspNet.Mvc.Formatters;
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc
|
||||||
|
|
@ -31,7 +32,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
}
|
}
|
||||||
|
|
||||||
Type = type;
|
Type = type;
|
||||||
ContentTypes = new List<MediaTypeHeaderValue>();
|
ContentTypes = new MediaTypeCollection();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -46,12 +47,21 @@ namespace Microsoft.AspNet.Mvc
|
||||||
throw new ArgumentNullException(nameof(contentType));
|
throw new ArgumentNullException(nameof(contentType));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We want to ensure that the given provided content types are valid values, so
|
||||||
|
// we validate them using the semantics of MediaTypeHeaderValue.
|
||||||
|
MediaTypeHeaderValue.Parse(contentType);
|
||||||
|
|
||||||
|
for (var i = 0; i < additionalContentTypes.Length; i++)
|
||||||
|
{
|
||||||
|
MediaTypeHeaderValue.Parse(additionalContentTypes[i]);
|
||||||
|
}
|
||||||
|
|
||||||
ContentTypes = GetContentTypes(contentType, additionalContentTypes);
|
ContentTypes = GetContentTypes(contentType, additionalContentTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Type Type { get; set; }
|
public Type Type { get; set; }
|
||||||
|
|
||||||
public IList<MediaTypeHeaderValue> ContentTypes { get; set; }
|
public MediaTypeCollection ContentTypes { get; set; }
|
||||||
|
|
||||||
public override void OnResultExecuting(ResultExecutingContext context)
|
public override void OnResultExecuting(ResultExecutingContext context)
|
||||||
{
|
{
|
||||||
|
|
@ -74,16 +84,17 @@ namespace Microsoft.AspNet.Mvc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<MediaTypeHeaderValue> GetContentTypes(string firstArg, string[] args)
|
private MediaTypeCollection GetContentTypes(string firstArg, string[] args)
|
||||||
{
|
{
|
||||||
var completeArgs = new List<string>();
|
var completeArgs = new List<string>();
|
||||||
completeArgs.Add(firstArg);
|
completeArgs.Add(firstArg);
|
||||||
completeArgs.AddRange(args);
|
completeArgs.AddRange(args);
|
||||||
var contentTypes = new List<MediaTypeHeaderValue>();
|
var contentTypes = new MediaTypeCollection();
|
||||||
foreach (var arg in completeArgs)
|
foreach (var arg in completeArgs)
|
||||||
{
|
{
|
||||||
var contentType = MediaTypeHeaderValue.Parse(arg);
|
var contentType = arg;
|
||||||
if (contentType.MatchesAllSubTypes || contentType.MatchesAllTypes)
|
if (MediaTypeComparisons.MatchesAllSubtypes(contentType)||
|
||||||
|
MediaTypeComparisons.MatchesAllTypes(contentType))
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException(
|
throw new InvalidOperationException(
|
||||||
Resources.FormatMatchAllContentTypeIsNotAllowed(arg));
|
Resources.FormatMatchAllContentTypeIsNotAllowed(arg));
|
||||||
|
|
@ -95,7 +106,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
return contentTypes;
|
return contentTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetContentTypes(IList<MediaTypeHeaderValue> contentTypes)
|
public void SetContentTypes(MediaTypeCollection contentTypes)
|
||||||
{
|
{
|
||||||
contentTypes.Clear();
|
contentTypes.Clear();
|
||||||
foreach (var contentType in ContentTypes)
|
foreach (var contentType in ContentTypes)
|
||||||
|
|
|
||||||
|
|
@ -1034,6 +1034,22 @@ namespace Microsoft.AspNet.Mvc.Core
|
||||||
return GetString("HttpResponseStreamWriter_StreamNotWritable");
|
return GetString("HttpResponseStreamWriter_StreamNotWritable");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The argument '{0}' is invalid. Empty or null formats are not supported.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatFormatterMappings_GetMediaTypeMappingForFormat_InvalidFormat
|
||||||
|
{
|
||||||
|
get { return GetString("FormatFormatterMappings_GetMediaTypeMappingForFormat_InvalidFormat"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The argument '{0}' is invalid. Empty or null formats are not supported.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatFormatFormatterMappings_GetMediaTypeMappingForFormat_InvalidFormat(object p0)
|
||||||
|
{
|
||||||
|
return string.Format(CultureInfo.CurrentCulture, GetString("FormatFormatterMappings_GetMediaTypeMappingForFormat_InvalidFormat"), p0);
|
||||||
|
}
|
||||||
|
|
||||||
private static string GetString(string name, params string[] formatterNames)
|
private static string GetString(string name, params string[] formatterNames)
|
||||||
{
|
{
|
||||||
var value = _resourceManager.GetString(name);
|
var value = _resourceManager.GetString(name);
|
||||||
|
|
|
||||||
|
|
@ -319,4 +319,7 @@
|
||||||
<data name="HttpResponseStreamWriter_StreamNotWritable" xml:space="preserve">
|
<data name="HttpResponseStreamWriter_StreamNotWritable" xml:space="preserve">
|
||||||
<value>The stream must support writing.</value>
|
<value>The stream must support writing.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="FormatFormatterMappings_GetMediaTypeMappingForFormat_InvalidFormat" xml:space="preserve">
|
||||||
|
<value>The argument '{0}' is invalid. Empty or null formats are not supported.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|
@ -37,10 +37,6 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(fileName));
|
throw new ArgumentNullException(nameof(fileName));
|
||||||
}
|
}
|
||||||
if (contentType == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(contentType));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -51,18 +47,13 @@ namespace Microsoft.AspNet.Mvc
|
||||||
/// <param name="fileName">The path to the file. The path must be relative/virtual.</param>
|
/// <param name="fileName">The path to the file. The path must be relative/virtual.</param>
|
||||||
/// <param name="contentType">The Content-Type header of the response.</param>
|
/// <param name="contentType">The Content-Type header of the response.</param>
|
||||||
public VirtualFileResult(string fileName, MediaTypeHeaderValue contentType)
|
public VirtualFileResult(string fileName, MediaTypeHeaderValue contentType)
|
||||||
: base(contentType)
|
: base(contentType?.ToString())
|
||||||
{
|
{
|
||||||
if (fileName == null)
|
if (fileName == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(fileName));
|
throw new ArgumentNullException(nameof(fileName));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (contentType == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(contentType));
|
|
||||||
}
|
|
||||||
|
|
||||||
FileName = fileName;
|
FileName = fileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,10 +18,10 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class JsonResultExecutor
|
public class JsonResultExecutor
|
||||||
{
|
{
|
||||||
private static readonly MediaTypeHeaderValue DefaultContentType = new MediaTypeHeaderValue("application/json")
|
private static readonly string DefaultContentType = new MediaTypeHeaderValue("application/json")
|
||||||
{
|
{
|
||||||
Encoding = Encoding.UTF8
|
Encoding = Encoding.UTF8
|
||||||
}.CopyAsReadOnly();
|
}.ToString();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new <see cref="JsonResultExecutor"/>.
|
/// Creates a new <see cref="JsonResultExecutor"/>.
|
||||||
|
|
|
||||||
|
|
@ -140,7 +140,7 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
}
|
}
|
||||||
|
|
||||||
var response = context.HttpContext.Response;
|
var response = context.HttpContext.Response;
|
||||||
var selectedEncoding = context.ContentType?.Encoding ?? Encoding.UTF8;
|
var selectedEncoding = MediaTypeEncoding.GetEncoding(context.ContentType) ?? Encoding.UTF8;
|
||||||
|
|
||||||
using (var writer = context.WriterFactory(response.Body, selectedEncoding))
|
using (var writer = context.WriterFactory(response.Body, selectedEncoding))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the <see cref="MediaTypeHeaderValue"/> representing the Content-Type header of the response.
|
/// Gets or sets the <see cref="MediaTypeHeaderValue"/> representing the Content-Type header of the response.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public MediaTypeHeaderValue ContentType { get; set; }
|
public string ContentType { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the <see cref="JsonSerializerSettings"/>.
|
/// Gets or sets the <see cref="JsonSerializerSettings"/>.
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ using System.Xml;
|
||||||
using Microsoft.AspNet.Mvc.Formatters.Xml;
|
using Microsoft.AspNet.Mvc.Formatters.Xml;
|
||||||
using Microsoft.AspNet.Mvc.Formatters.Xml.Internal;
|
using Microsoft.AspNet.Mvc.Formatters.Xml.Internal;
|
||||||
using Microsoft.AspNet.Mvc.Internal;
|
using Microsoft.AspNet.Mvc.Internal;
|
||||||
|
using Microsoft.Net.Http.Headers;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Formatters
|
namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
{
|
{
|
||||||
|
|
@ -187,7 +188,7 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
}
|
}
|
||||||
|
|
||||||
var writerSettings = WriterSettings.Clone();
|
var writerSettings = WriterSettings.Clone();
|
||||||
writerSettings.Encoding = context.ContentType?.Encoding ?? Encoding.UTF8;
|
writerSettings.Encoding = MediaTypeEncoding.GetEncoding(context.ContentType) ?? Encoding.UTF8;
|
||||||
|
|
||||||
// Wrap the object only if there is a wrapping type.
|
// Wrap the object only if there is a wrapping type.
|
||||||
var value = context.Object;
|
var value = context.Object;
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ using System.Xml.Serialization;
|
||||||
using Microsoft.AspNet.Mvc.Formatters.Xml;
|
using Microsoft.AspNet.Mvc.Formatters.Xml;
|
||||||
using Microsoft.AspNet.Mvc.Formatters.Xml.Internal;
|
using Microsoft.AspNet.Mvc.Formatters.Xml.Internal;
|
||||||
using Microsoft.AspNet.Mvc.Internal;
|
using Microsoft.AspNet.Mvc.Internal;
|
||||||
|
using Microsoft.Net.Http.Headers;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Formatters
|
namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
{
|
{
|
||||||
|
|
@ -164,7 +165,7 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
var response = context.HttpContext.Response;
|
var response = context.HttpContext.Response;
|
||||||
|
|
||||||
var writerSettings = WriterSettings.Clone();
|
var writerSettings = WriterSettings.Clone();
|
||||||
writerSettings.Encoding = context.ContentType.Encoding ?? Encoding.UTF8;
|
writerSettings.Encoding = MediaTypeEncoding.GetEncoding(context.ContentType) ?? Encoding.UTF8;
|
||||||
|
|
||||||
// Wrap the object only if there is a wrapping type.
|
// Wrap the object only if there is a wrapping type.
|
||||||
var value = context.Object;
|
var value = context.Object;
|
||||||
|
|
|
||||||
|
|
@ -46,9 +46,9 @@ namespace Microsoft.AspNet.Mvc
|
||||||
public IViewEngine ViewEngine { get; set; }
|
public IViewEngine ViewEngine { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the <see cref="MediaTypeHeaderValue"/> representing the Content-Type header of the response.
|
/// Gets or sets the Content-Type header for the response.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public MediaTypeHeaderValue ContentType { get; set; }
|
public string ContentType { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override async Task ExecuteResultAsync(ActionContext context)
|
public override async Task ExecuteResultAsync(ActionContext context)
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@ using Microsoft.AspNet.Mvc.ViewFeatures.Internal;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Microsoft.Net.Http.Headers;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
|
|
@ -31,9 +30,9 @@ namespace Microsoft.AspNet.Mvc
|
||||||
public object Arguments { get; set; }
|
public object Arguments { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the <see cref="MediaTypeHeaderValue"/> representing the Content-Type header of the response.
|
/// Gets or sets the Content-Type header for the response.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public MediaTypeHeaderValue ContentType { get; set; }
|
public string ContentType { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the HTTP status code.
|
/// Gets or sets the HTTP status code.
|
||||||
|
|
|
||||||
|
|
@ -23,12 +23,9 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
||||||
public class ViewExecutor
|
public class ViewExecutor
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The default content-type header value for views, <c>text/html; charset=utf8</c>.
|
/// The default content-type header value for views, <c>text/html; charset=utf-8</c>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly MediaTypeHeaderValue DefaultContentType = new MediaTypeHeaderValue("text/html")
|
public static readonly string DefaultContentType = "text/html; charset=utf-8";
|
||||||
{
|
|
||||||
Encoding = Encoding.UTF8
|
|
||||||
}.CopyAsReadOnly();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new <see cref="ViewExecutor"/>.
|
/// Creates a new <see cref="ViewExecutor"/>.
|
||||||
|
|
@ -122,7 +119,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
||||||
IView view,
|
IView view,
|
||||||
ViewDataDictionary viewData,
|
ViewDataDictionary viewData,
|
||||||
ITempDataDictionary tempData,
|
ITempDataDictionary tempData,
|
||||||
MediaTypeHeaderValue contentType,
|
string contentType,
|
||||||
int? statusCode)
|
int? statusCode)
|
||||||
{
|
{
|
||||||
if (actionContext == null)
|
if (actionContext == null)
|
||||||
|
|
|
||||||
|
|
@ -51,9 +51,9 @@ namespace Microsoft.AspNet.Mvc
|
||||||
public IViewEngine ViewEngine { get; set; }
|
public IViewEngine ViewEngine { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the <see cref="MediaTypeHeaderValue"/> representing the Content-Type header of the response.
|
/// Gets or sets the Content-Type header for the response.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public MediaTypeHeaderValue ContentType { get; set; }
|
public string ContentType { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override async Task ExecuteResultAsync(ActionContext context)
|
public override async Task ExecuteResultAsync(ActionContext context)
|
||||||
|
|
|
||||||
|
|
@ -409,10 +409,7 @@ namespace System.Web.Http
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = new JsonResult(content, serializerSettings);
|
var result = new JsonResult(content, serializerSettings);
|
||||||
result.ContentType = new MediaTypeHeaderValue("application/json")
|
result.ContentType = $"application/json; charset={encoding.WebName}";
|
||||||
{
|
|
||||||
Encoding = encoding
|
|
||||||
};
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ using Microsoft.AspNet.Mvc.Routing;
|
||||||
using Microsoft.AspNet.Routing;
|
using Microsoft.AspNet.Routing;
|
||||||
using Microsoft.AspNet.Routing.Constraints;
|
using Microsoft.AspNet.Routing.Constraints;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
@ -1385,14 +1386,14 @@ namespace Microsoft.AspNet.Mvc.Description
|
||||||
{
|
{
|
||||||
public ContentTypeAttribute(string mediaType)
|
public ContentTypeAttribute(string mediaType)
|
||||||
{
|
{
|
||||||
ContentTypes.Add(MediaTypeHeaderValue.Parse(mediaType));
|
ContentTypes.Add(mediaType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<MediaTypeHeaderValue> ContentTypes { get; } = new List<MediaTypeHeaderValue>();
|
public MediaTypeCollection ContentTypes { get; } = new MediaTypeCollection();
|
||||||
|
|
||||||
public Type Type { get; set; }
|
public Type Type { get; set; }
|
||||||
|
|
||||||
public void SetContentTypes(IList<MediaTypeHeaderValue> contentTypes)
|
public void SetContentTypes(MediaTypeCollection contentTypes)
|
||||||
{
|
{
|
||||||
contentTypes.Clear();
|
contentTypes.Clear();
|
||||||
foreach (var contentType in ContentTypes)
|
foreach (var contentType in ContentTypes)
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ using Microsoft.AspNet.Http;
|
||||||
using Microsoft.AspNet.Http.Features;
|
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.TestCommon;
|
||||||
using Microsoft.AspNet.Mvc.ViewComponents;
|
using Microsoft.AspNet.Mvc.ViewComponents;
|
||||||
using Microsoft.AspNet.Routing;
|
using Microsoft.AspNet.Routing;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
@ -32,7 +34,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
ContentType = new MediaTypeHeaderValue("text/plain")
|
ContentType = new MediaTypeHeaderValue("text/plain")
|
||||||
{
|
{
|
||||||
Encoding = Encoding.UTF7
|
Encoding = Encoding.UTF7
|
||||||
}
|
}.ToString()
|
||||||
};
|
};
|
||||||
var httpContext = GetHttpContext();
|
var httpContext = GetHttpContext();
|
||||||
var actionContext = GetActionContext(httpContext);
|
var actionContext = GetActionContext(httpContext);
|
||||||
|
|
@ -41,7 +43,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
await contentResult.ExecuteResultAsync(actionContext);
|
await contentResult.ExecuteResultAsync(actionContext);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal("text/plain; charset=utf-7", httpContext.Response.ContentType);
|
MediaTypeAssert.Equal("text/plain; charset=utf-7", httpContext.Response.ContentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -55,7 +57,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
ContentType = new MediaTypeHeaderValue("text/plain")
|
ContentType = new MediaTypeHeaderValue("text/plain")
|
||||||
{
|
{
|
||||||
Encoding = Encoding.ASCII
|
Encoding = Encoding.ASCII
|
||||||
}
|
}.ToString()
|
||||||
};
|
};
|
||||||
var httpContext = GetHttpContext();
|
var httpContext = GetHttpContext();
|
||||||
httpContext.Features.Set<IHttpBufferingFeature>(new TestBufferingFeature());
|
httpContext.Features.Set<IHttpBufferingFeature>(new TestBufferingFeature());
|
||||||
|
|
@ -153,7 +155,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
var contentResult = new ContentResult
|
var contentResult = new ContentResult
|
||||||
{
|
{
|
||||||
Content = content,
|
Content = content,
|
||||||
ContentType = contentType
|
ContentType = contentType?.ToString()
|
||||||
};
|
};
|
||||||
var httpContext = GetHttpContext();
|
var httpContext = GetHttpContext();
|
||||||
var memoryStream = new MemoryStream();
|
var memoryStream = new MemoryStream();
|
||||||
|
|
@ -165,7 +167,8 @@ namespace Microsoft.AspNet.Mvc
|
||||||
await contentResult.ExecuteResultAsync(actionContext);
|
await contentResult.ExecuteResultAsync(actionContext);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(expectedContentType, httpContext.Response.ContentType);
|
var finalResponseContentType = httpContext.Response.ContentType;
|
||||||
|
Assert.Equal(expectedContentType, finalResponseContentType);
|
||||||
Assert.Equal(expectedContentData, memoryStream.ToArray());
|
Assert.Equal(expectedContentData, memoryStream.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,10 @@ using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Http;
|
using Microsoft.AspNet.Http;
|
||||||
using Microsoft.AspNet.Http.Internal;
|
using Microsoft.AspNet.Http.Internal;
|
||||||
|
using Microsoft.AspNet.Mvc.Formatters;
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding.Validation;
|
using Microsoft.AspNet.Mvc.ModelBinding.Validation;
|
||||||
|
using Microsoft.AspNet.Mvc.TestCommon;
|
||||||
using Microsoft.AspNet.Routing;
|
using Microsoft.AspNet.Routing;
|
||||||
using Microsoft.AspNet.Testing;
|
using Microsoft.AspNet.Testing;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
|
|
@ -975,7 +977,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
||||||
// Assert
|
// Assert
|
||||||
Assert.IsType<ContentResult>(actualContentResult);
|
Assert.IsType<ContentResult>(actualContentResult);
|
||||||
Assert.Equal("TestContent", actualContentResult.Content);
|
Assert.Equal("TestContent", actualContentResult.Content);
|
||||||
Assert.Null(actualContentResult.ContentType.Encoding);
|
Assert.Null(MediaTypeEncoding.GetEncoding(actualContentResult.ContentType));
|
||||||
Assert.Equal("text/plain", actualContentResult.ContentType.ToString());
|
Assert.Equal("text/plain", actualContentResult.ContentType.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -991,7 +993,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
||||||
// Assert
|
// Assert
|
||||||
Assert.IsType<ContentResult>(actualContentResult);
|
Assert.IsType<ContentResult>(actualContentResult);
|
||||||
Assert.Equal("TestContent", actualContentResult.Content);
|
Assert.Equal("TestContent", actualContentResult.Content);
|
||||||
Assert.Same(Encoding.UTF8, actualContentResult.ContentType.Encoding);
|
Assert.Same(Encoding.UTF8, MediaTypeEncoding.GetEncoding(actualContentResult.ContentType));
|
||||||
Assert.Equal("text/plain; charset=utf-8", actualContentResult.ContentType.ToString());
|
Assert.Equal("text/plain; charset=utf-8", actualContentResult.ContentType.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1024,7 +1026,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
||||||
Assert.NotNull(contentResult.ContentType);
|
Assert.NotNull(contentResult.ContentType);
|
||||||
Assert.Equal(contentType, contentResult.ContentType.ToString());
|
Assert.Equal(contentType, contentResult.ContentType.ToString());
|
||||||
// The default encoding of ContentResult is used when this result is executed.
|
// The default encoding of ContentResult is used when this result is executed.
|
||||||
Assert.Null(contentResult.ContentType.Encoding);
|
Assert.Null(MediaTypeEncoding.GetEncoding(contentResult.ContentType));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -1032,13 +1034,13 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var contentController = new ContentController();
|
var contentController = new ContentController();
|
||||||
var contentType = MediaTypeHeaderValue.Parse("text/xml; charset=us-ascii; p1=p1-value");
|
var contentType = "text/xml; charset=us-ascii; p1=p1-value";
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var contentResult = (ContentResult)contentController.Content_WithEncodingInCharset_AndEncodingParameter();
|
var contentResult = (ContentResult)contentController.Content_WithEncodingInCharset_AndEncodingParameter();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(contentType, contentResult.ContentType);
|
MediaTypeAssert.Equal(contentType, contentResult.ContentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -1046,7 +1048,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var contentController = new ContentController();
|
var contentController = new ContentController();
|
||||||
var contentType = MediaTypeHeaderValue.Parse("text/xml; charset=us-ascii; p1=p1-value");
|
var contentType = "text/xml; charset=us-ascii; p1=p1-value";
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var contentResult = (ContentResult)contentController.Content_WithEncodingInCharset();
|
var contentResult = (ContentResult)contentController.Content_WithEncodingInCharset();
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,11 @@ using Microsoft.AspNet.Http;
|
||||||
using Microsoft.AspNet.Http.Features;
|
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.TestCommon;
|
||||||
using Microsoft.AspNet.Routing;
|
using Microsoft.AspNet.Routing;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Logging.Testing;
|
using Microsoft.Extensions.Logging.Testing;
|
||||||
using Microsoft.Net.Http.Headers;
|
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc
|
||||||
|
|
@ -37,14 +37,14 @@ namespace Microsoft.AspNet.Mvc
|
||||||
// Arrange
|
// Arrange
|
||||||
var fileContents = new byte[0];
|
var fileContents = new byte[0];
|
||||||
var contentType = "text/plain; charset=us-ascii; p1=p1-value";
|
var contentType = "text/plain; charset=us-ascii; p1=p1-value";
|
||||||
var expectedMediaType = MediaTypeHeaderValue.Parse(contentType);
|
var expectedMediaType = contentType;
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = new FileContentResult(fileContents, contentType);
|
var result = new FileContentResult(fileContents, contentType);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Same(fileContents, result.FileContents);
|
Assert.Same(fileContents, result.FileContents);
|
||||||
Assert.Equal(expectedMediaType, result.ContentType);
|
MediaTypeAssert.Equal(expectedMediaType, result.ContentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -83,7 +83,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
var context = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
|
var context = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
|
||||||
|
|
||||||
var result = new FileContentResult(buffer, MediaTypeHeaderValue.Parse(expectedContentType));
|
var result = new FileContentResult(buffer, expectedContentType);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await result.ExecuteResultAsync(context);
|
await result.ExecuteResultAsync(context);
|
||||||
|
|
@ -108,7 +108,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
var context = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
|
var context = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
|
||||||
|
|
||||||
var result = new FileContentResult(buffer, MediaTypeHeaderValue.Parse(expectedContentType));
|
var result = new FileContentResult(buffer, expectedContentType);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await result.ExecuteResultAsync(context);
|
await result.ExecuteResultAsync(context);
|
||||||
|
|
|
||||||
|
|
@ -274,12 +274,12 @@ namespace Microsoft.AspNet.Mvc
|
||||||
public bool WasWriteFileCalled;
|
public bool WasWriteFileCalled;
|
||||||
|
|
||||||
public EmptyFileResult()
|
public EmptyFileResult()
|
||||||
: base(MediaTypeHeaderValue.Parse("application/octet"))
|
: base("application/octet")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public EmptyFileResult(string contentType)
|
public EmptyFileResult(string contentType)
|
||||||
: base(MediaTypeHeaderValue.Parse(contentType))
|
: base(contentType)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,11 @@ using Microsoft.AspNet.Http;
|
||||||
using Microsoft.AspNet.Http.Features;
|
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.TestCommon;
|
||||||
using Microsoft.AspNet.Routing;
|
using Microsoft.AspNet.Routing;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Logging.Testing;
|
using Microsoft.Extensions.Logging.Testing;
|
||||||
using Microsoft.Net.Http.Headers;
|
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
@ -41,14 +41,14 @@ namespace Microsoft.AspNet.Mvc
|
||||||
// Arrange
|
// Arrange
|
||||||
var stream = Stream.Null;
|
var stream = Stream.Null;
|
||||||
var contentType = "text/plain; charset=us-ascii; p1=p1-value";
|
var contentType = "text/plain; charset=us-ascii; p1=p1-value";
|
||||||
var expectedMediaType = MediaTypeHeaderValue.Parse(contentType);
|
var expectedMediaType = contentType;
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = new FileStreamResult(stream, contentType);
|
var result = new FileStreamResult(stream, contentType);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(stream, result.FileStream);
|
Assert.Equal(stream, result.FileStream);
|
||||||
Assert.Equal(expectedMediaType, result.ContentType);
|
MediaTypeAssert.Equal(expectedMediaType, result.ContentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -130,7 +130,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
|
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
|
||||||
|
|
||||||
var result = new FileStreamResult(originalStream, MediaTypeHeaderValue.Parse(expectedContentType));
|
var result = new FileStreamResult(originalStream, expectedContentType);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await result.ExecuteResultAsync(actionContext);
|
await result.ExecuteResultAsync(actionContext);
|
||||||
|
|
@ -157,7 +157,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
httpContext.Response.Body = outStream;
|
httpContext.Response.Body = outStream;
|
||||||
|
|
||||||
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
|
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
|
||||||
var result = new FileStreamResult(originalStream, MediaTypeHeaderValue.Parse(expectedContentType));
|
var result = new FileStreamResult(originalStream, expectedContentType);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await result.ExecuteResultAsync(actionContext);
|
await result.ExecuteResultAsync(actionContext);
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,10 @@
|
||||||
using Microsoft.AspNet.Http;
|
using Microsoft.AspNet.Http;
|
||||||
using Microsoft.AspNet.Mvc.Abstractions;
|
using Microsoft.AspNet.Mvc.Abstractions;
|
||||||
using Microsoft.AspNet.Mvc.Filters;
|
using Microsoft.AspNet.Mvc.Filters;
|
||||||
using Microsoft.AspNet.Mvc.Infrastructure;
|
using Microsoft.AspNet.Mvc.TestCommon;
|
||||||
using Microsoft.AspNet.Routing;
|
using Microsoft.AspNet.Routing;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
@ -32,7 +33,7 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
string contentType)
|
string contentType)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var mediaType = MediaTypeHeaderValue.Parse("application/json");
|
var mediaType = new StringSegment("application/json");
|
||||||
var mockObjects = new MockObjects(format, place);
|
var mockObjects = new MockObjects(format, place);
|
||||||
|
|
||||||
var resultExecutingContext = mockObjects.CreateResultExecutingContext();
|
var resultExecutingContext = mockObjects.CreateResultExecutingContext();
|
||||||
|
|
@ -52,7 +53,7 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
// Assert
|
// Assert
|
||||||
var objectResult = Assert.IsType<ObjectResult>(resultExecutingContext.Result);
|
var objectResult = Assert.IsType<ObjectResult>(resultExecutingContext.Result);
|
||||||
Assert.Equal(1, objectResult.ContentTypes.Count);
|
Assert.Equal(1, objectResult.ContentTypes.Count);
|
||||||
AssertMediaTypesEqual(mediaType, objectResult.ContentTypes[0]);
|
MediaTypeAssert.Equal(mediaType, objectResult.ContentTypes[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -61,7 +62,7 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
// If the format is present in both route and query data, the one in route data wins
|
// If the format is present in both route and query data, the one in route data wins
|
||||||
|
|
||||||
// Arrange
|
// Arrange
|
||||||
var mediaType = MediaTypeHeaderValue.Parse("application/json");
|
var mediaType = new StringSegment("application/json");
|
||||||
var mockObjects = new MockObjects("json", FormatSource.RouteData);
|
var mockObjects = new MockObjects("json", FormatSource.RouteData);
|
||||||
var httpContext = new Mock<HttpContext>();
|
var httpContext = new Mock<HttpContext>();
|
||||||
httpContext.Setup(c => c.Response).Returns(new Mock<HttpResponse>().Object);
|
httpContext.Setup(c => c.Response).Returns(new Mock<HttpResponse>().Object);
|
||||||
|
|
@ -95,7 +96,7 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
// Assert
|
// Assert
|
||||||
var objectResult = Assert.IsType<ObjectResult>(resultExecutingContext.Result);
|
var objectResult = Assert.IsType<ObjectResult>(resultExecutingContext.Result);
|
||||||
Assert.Equal(1, objectResult.ContentTypes.Count);
|
Assert.Equal(1, objectResult.ContentTypes.Count);
|
||||||
AssertMediaTypesEqual(mediaType, objectResult.ContentTypes[0]);
|
MediaTypeAssert.Equal(mediaType, objectResult.ContentTypes[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
|
|
@ -108,7 +109,7 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
string contentType)
|
string contentType)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var mediaType = MediaTypeHeaderValue.Parse(contentType);
|
var mediaType = new StringSegment(contentType);
|
||||||
|
|
||||||
var mockObjects = new MockObjects(format, place);
|
var mockObjects = new MockObjects(format, place);
|
||||||
var resultExecutingContext = mockObjects.CreateResultExecutingContext();
|
var resultExecutingContext = mockObjects.CreateResultExecutingContext();
|
||||||
|
|
@ -127,7 +128,7 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
// Assert
|
// Assert
|
||||||
var objectResult = Assert.IsType<ObjectResult>(resultExecutingContext.Result);
|
var objectResult = Assert.IsType<ObjectResult>(resultExecutingContext.Result);
|
||||||
Assert.Equal(1, objectResult.ContentTypes.Count);
|
Assert.Equal(1, objectResult.ContentTypes.Count);
|
||||||
AssertMediaTypesEqual(mediaType, objectResult.ContentTypes[0]);
|
MediaTypeAssert.Equal(mediaType, objectResult.ContentTypes[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
|
|
@ -303,7 +304,7 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
public void FormatFilter_ExplicitContentType_SetOnObjectResult_TakesPrecedence()
|
public void FormatFilter_ExplicitContentType_SetOnObjectResult_TakesPrecedence()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var mediaType = MediaTypeHeaderValue.Parse("application/foo");
|
var mediaType = new StringSegment("application/foo");
|
||||||
var mockObjects = new MockObjects("json", FormatSource.QueryData);
|
var mockObjects = new MockObjects("json", FormatSource.QueryData);
|
||||||
var httpContext = new Mock<HttpContext>();
|
var httpContext = new Mock<HttpContext>();
|
||||||
httpContext.Setup(c => c.Response).Returns(new Mock<HttpResponse>().Object);
|
httpContext.Setup(c => c.Response).Returns(new Mock<HttpResponse>().Object);
|
||||||
|
|
@ -330,7 +331,7 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
// Assert
|
// Assert
|
||||||
var result = Assert.IsType<ObjectResult>(resultExecutingContext.Result);
|
var result = Assert.IsType<ObjectResult>(resultExecutingContext.Result);
|
||||||
Assert.Equal(1, result.ContentTypes.Count);
|
Assert.Equal(1, result.ContentTypes.Count);
|
||||||
AssertMediaTypesEqual(mediaType, result.ContentTypes[0]);
|
MediaTypeAssert.Equal(mediaType, result.ContentTypes[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -366,21 +367,6 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
Assert.Equal(0, result.ContentTypes.Count);
|
Assert.Equal(0, result.ContentTypes.Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AssertMediaTypesEqual(
|
|
||||||
MediaTypeHeaderValue expectedMediaType,
|
|
||||||
MediaTypeHeaderValue actualMediaType)
|
|
||||||
{
|
|
||||||
Assert.Equal(expectedMediaType.MediaType, actualMediaType.MediaType);
|
|
||||||
Assert.Equal(expectedMediaType.SubType, actualMediaType.SubType);
|
|
||||||
Assert.Equal(expectedMediaType.Charset, actualMediaType.Charset);
|
|
||||||
Assert.Equal(expectedMediaType.MatchesAllTypes, actualMediaType.MatchesAllTypes);
|
|
||||||
Assert.Equal(expectedMediaType.MatchesAllSubTypes, actualMediaType.MatchesAllSubTypes);
|
|
||||||
Assert.Equal(expectedMediaType.Parameters.Count, actualMediaType.Parameters.Count);
|
|
||||||
foreach (var item in expectedMediaType.Parameters)
|
|
||||||
{
|
|
||||||
Assert.Equal(item.Value, NameValueHeaderValue.Find(actualMediaType.Parameters, item.Name).Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class MockObjects
|
private class MockObjects
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
// 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 Microsoft.AspNet.Mvc.TestCommon;
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
@ -10,33 +12,44 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
{
|
{
|
||||||
public class FormatterMappingsTest
|
public class FormatterMappingsTest
|
||||||
{
|
{
|
||||||
|
[Theory]
|
||||||
|
[InlineData(null)]
|
||||||
|
[InlineData("")]
|
||||||
|
public void FormatterMappings_GetMediaTypeMappingForFormat_ThrowsForInvalidFormats(string format)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var options = new FormatterMappings();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
Assert.Throws<ArgumentException>("format", () => options.GetMediaTypeMappingForFormat(format));
|
||||||
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData(".xml", "application/xml", "xml")]
|
[InlineData(".xml", "application/xml", "xml")]
|
||||||
[InlineData("json", "application/json", "JSON")]
|
[InlineData("json", "application/json", "JSON")]
|
||||||
[InlineData(".foo", "text/foo", "Foo")]
|
[InlineData(".foo", "text/foo", "Foo")]
|
||||||
[InlineData(".Json", "application/json", "json")]
|
[InlineData(".Json", "application/json", "json")]
|
||||||
[InlineData("FOo", "text/foo", "FOO")]
|
[InlineData("FOo", "text/foo", "FOO")]
|
||||||
public void FormatterMappings_SetFormatMapping_DiffSetGetFormat(string setFormat, string contentType, string getFormat)
|
public void FormatterMappings_SetFormatMapping_DiffSetGetFormat(string setFormat, string contentType, string getFormat)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var mediaType = MediaTypeHeaderValue.Parse(contentType);
|
|
||||||
var options = new FormatterMappings();
|
var options = new FormatterMappings();
|
||||||
options.SetMediaTypeMappingForFormat(setFormat, mediaType);
|
options.SetMediaTypeMappingForFormat(setFormat, MediaTypeHeaderValue.Parse(contentType));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var returnMediaType = options.GetMediaTypeMappingForFormat(getFormat);
|
var returnMediaType = options.GetMediaTypeMappingForFormat(getFormat);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(mediaType, returnMediaType);
|
MediaTypeAssert.Equal(contentType, returnMediaType);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void FormatterMappings_Invalid_Period()
|
public void FormatterMappings_Invalid_Period()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var options = new FormatterMappings();
|
var options = new FormatterMappings();
|
||||||
var format = ".";
|
var format = ".";
|
||||||
var expected = string.Format(@"The format provided is invalid '{0}'. A format must be a non-empty file-" +
|
var expected = string.Format(@"The format provided is invalid '{0}'. A format must be a non-empty file-" +
|
||||||
"extension, optionally prefixed with a '.' character.", format);
|
"extension, optionally prefixed with a '.' character.", format);
|
||||||
|
|
||||||
// Act and assert
|
// Act and assert
|
||||||
|
|
@ -70,12 +83,12 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var options = new FormatterMappings();
|
var options = new FormatterMappings();
|
||||||
var expected = string.Format(@"The media type ""{0}"" is not valid. MediaTypes containing wildcards (*) " +
|
var expected = string.Format(@"The media type ""{0}"" is not valid. MediaTypes containing wildcards (*) " +
|
||||||
"are not allowed in formatter mappings.", format);
|
"are not allowed in formatter mappings.", format);
|
||||||
|
|
||||||
// Act and assert
|
// Act and assert
|
||||||
var exception = Assert.Throws<ArgumentException>(() => options.SetMediaTypeMappingForFormat(
|
var exception = Assert.Throws<ArgumentException>(() => options.SetMediaTypeMappingForFormat(
|
||||||
"star",
|
"star",
|
||||||
MediaTypeHeaderValue.Parse(format)));
|
MediaTypeHeaderValue.Parse(format)));
|
||||||
Assert.Equal(expected, exception.Message);
|
Assert.Equal(expected, exception.Message);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
|
{
|
||||||
|
public class MediaTypeComparisonsTest
|
||||||
|
{
|
||||||
|
[Theory]
|
||||||
|
[InlineData("application/json", "application/json", true)]
|
||||||
|
[InlineData("application/json", "application/json;charset=utf-8", true)]
|
||||||
|
[InlineData("application/json;charset=utf-8", "application/json", false)]
|
||||||
|
[InlineData("application/json;q=0.8", "application/json;q=0.9", true)]
|
||||||
|
[InlineData("application/json;q=0.8;charset=utf-7", "application/json;charset=utf-8;q=0.9", true)]
|
||||||
|
[InlineData("application/json;format=indent;charset=utf-8", "application/json", false)]
|
||||||
|
[InlineData("application/json", "application/json;format=indent;charset=utf-8", true)]
|
||||||
|
[InlineData("application/json;format=indent;charset=utf-8", "application/json;format=indent;charset=utf-8", true)]
|
||||||
|
[InlineData("application/json;charset=utf-8;format=indent", "application/json;format=indent;charset=utf-8", true)]
|
||||||
|
public void IsSubsetOf(string set, string subset, bool expectedResult)
|
||||||
|
{
|
||||||
|
// Arrange & Act
|
||||||
|
var result = MediaTypeComparisons.IsSubsetOf(
|
||||||
|
new StringSegment(set),
|
||||||
|
new StringSegment(subset));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(expectedResult, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("*/*", true)]
|
||||||
|
[InlineData("text/*", false)]
|
||||||
|
[InlineData("text/plain", false)]
|
||||||
|
public void MatchesAllTypes(string value, bool expectedResult)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var mediaType = new StringSegment(value);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = MediaTypeComparisons.MatchesAllTypes(mediaType);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(expectedResult, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("*/*", true)]
|
||||||
|
[InlineData("text/*", true)]
|
||||||
|
[InlineData("text/plain", false)]
|
||||||
|
public void MatchesAllSubtypes(string value, bool expectedResult)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var mediaType = new StringSegment(value);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = MediaTypeComparisons.MatchesAllSubtypes(mediaType);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(expectedResult, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Http;
|
using Microsoft.AspNet.Http;
|
||||||
using Microsoft.AspNet.Http.Internal;
|
using Microsoft.AspNet.Http.Internal;
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
@ -41,7 +42,7 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var type = declaredTypeAsString ? typeof(string) : typeof(object);
|
var type = declaredTypeAsString ? typeof(string) : typeof(object);
|
||||||
var contentType = useNonNullContentType ? MediaTypeHeaderValue.Parse("text/plain") : null;
|
var contentType = useNonNullContentType ? new StringSegment("text/plain") : new StringSegment();
|
||||||
|
|
||||||
var context = new OutputFormatterWriteContext(
|
var context = new OutputFormatterWriteContext(
|
||||||
new DefaultHttpContext(),
|
new DefaultHttpContext(),
|
||||||
|
|
@ -73,7 +74,7 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
declaredType,
|
declaredType,
|
||||||
"Something non null.")
|
"Something non null.")
|
||||||
{
|
{
|
||||||
ContentType = MediaTypeHeaderValue.Parse("text/plain"),
|
ContentType = new StringSegment("text/plain"),
|
||||||
};
|
};
|
||||||
|
|
||||||
var formatter = new HttpNoContentOutputFormatter();
|
var formatter = new HttpNoContentOutputFormatter();
|
||||||
|
|
@ -101,7 +102,7 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
typeof(string),
|
typeof(string),
|
||||||
value)
|
value)
|
||||||
{
|
{
|
||||||
ContentType = MediaTypeHeaderValue.Parse("text/plain"),
|
ContentType = new StringSegment("text/plain"),
|
||||||
};
|
};
|
||||||
|
|
||||||
var formatter = new HttpNoContentOutputFormatter()
|
var formatter = new HttpNoContentOutputFormatter()
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,10 @@ using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Http;
|
using Microsoft.AspNet.Http;
|
||||||
using Microsoft.AspNet.Http.Internal;
|
using Microsoft.AspNet.Http.Internal;
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
using Moq;
|
using Moq;
|
||||||
|
using Moq.Protected;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Formatters
|
namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
|
|
@ -59,7 +61,7 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
typeof(string),
|
typeof(string),
|
||||||
"someValue")
|
"someValue")
|
||||||
{
|
{
|
||||||
ContentType = MediaTypeHeaderValue.Parse(httpRequest.Headers[HeaderNames.Accept]),
|
ContentType = new StringSegment(httpRequest.Headers[HeaderNames.Accept]),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -69,17 +71,47 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
Assert.Equal(Encoding.GetEncoding(expectedEncoding), actualEncoding);
|
Assert.Equal(Encoding.GetEncoding(expectedEncoding), actualEncoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("application/json; charset=utf-16", "application/json; charset=utf-32")]
|
||||||
|
[InlineData("application/json; charset=utf-16; format=indent", "application/json; charset=utf-32; format=indent")]
|
||||||
|
public void WriteResponse_OverridesCharset_IfDifferentFromContentTypeCharset(
|
||||||
|
string contentType,
|
||||||
|
string expectedContentType)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var formatter = new Mock<OutputFormatter>();
|
||||||
|
|
||||||
|
formatter
|
||||||
|
.Setup(f => f.SelectCharacterEncoding(It.IsAny<OutputFormatterWriteContext>()))
|
||||||
|
.Returns(Encoding.UTF32);
|
||||||
|
|
||||||
|
var formatterContext = new OutputFormatterWriteContext(
|
||||||
|
new DefaultHttpContext(),
|
||||||
|
new TestHttpResponseStreamWriterFactory().CreateWriter,
|
||||||
|
objectType: null,
|
||||||
|
@object: null)
|
||||||
|
{
|
||||||
|
ContentType = new StringSegment(contentType),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
formatter.Object.WriteAsync(formatterContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(new StringSegment(expectedContentType), formatterContext.ContentType);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void WriteResponseContentHeaders_NoSupportedEncodings_NoEncodingIsSet()
|
public void WriteResponseContentHeaders_NoSupportedEncodings_NoEncodingIsSet()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var formatter = new TestOutputFormatter();
|
var formatter = new TestOutputFormatter();
|
||||||
|
|
||||||
var testContentType = MediaTypeHeaderValue.Parse("text/json");
|
var testContentType = new StringSegment("text/json");
|
||||||
|
|
||||||
formatter.SupportedEncodings.Clear();
|
formatter.SupportedEncodings.Clear();
|
||||||
formatter.SupportedMediaTypes.Clear();
|
formatter.SupportedMediaTypes.Clear();
|
||||||
formatter.SupportedMediaTypes.Add(testContentType);
|
formatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/json"));
|
||||||
|
|
||||||
var context = new OutputFormatterWriteContext(
|
var context = new OutputFormatterWriteContext(
|
||||||
new DefaultHttpContext(),
|
new DefaultHttpContext(),
|
||||||
|
|
@ -94,11 +126,11 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
formatter.WriteResponseHeaders(context);
|
formatter.WriteResponseHeaders(context);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Null(context.ContentType.Encoding);
|
Assert.Null(MediaTypeHeaderValue.Parse(context.ContentType.Value).Encoding);
|
||||||
Assert.Equal(testContentType, context.ContentType);
|
Assert.Equal(testContentType, context.ContentType);
|
||||||
|
|
||||||
// If we had set an encoding, it would be part of the content type header
|
// If we had set an encoding, it would be part of the content type header
|
||||||
Assert.Equal(testContentType, context.HttpContext.Response.GetTypedHeaders().ContentType);
|
Assert.Equal(MediaTypeHeaderValue.Parse(testContentType.Value), context.HttpContext.Response.GetTypedHeaders().ContentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -154,7 +186,9 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
formatter.SupportedTypes.Add(typeof(int));
|
formatter.SupportedTypes.Add(typeof(int));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var contentTypes = formatter.GetSupportedContentTypes(contentType: null, objectType: typeof(string));
|
var contentTypes = formatter.GetSupportedContentTypes(
|
||||||
|
contentType: null,
|
||||||
|
objectType: typeof(string));
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Null(contentTypes);
|
Assert.Null(contentTypes);
|
||||||
|
|
@ -174,7 +208,7 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
typeof(string),
|
typeof(string),
|
||||||
"Hello, world!")
|
"Hello, world!")
|
||||||
{
|
{
|
||||||
ContentType = formatter.SupportedMediaTypes[0],
|
ContentType = new StringSegment(formatter.SupportedMediaTypes[0].ToString()),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -194,7 +228,9 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
formatter.SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/xml"));
|
formatter.SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/xml"));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var contentTypes = formatter.GetSupportedContentTypes(contentType: null, objectType: typeof(string));
|
var contentTypes = formatter.GetSupportedContentTypes(
|
||||||
|
contentType: null,
|
||||||
|
objectType: typeof(string));
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(2, contentTypes.Count);
|
Assert.Equal(2, contentTypes.Count);
|
||||||
|
|
@ -214,7 +250,7 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var contentTypes = formatter.GetSupportedContentTypes(
|
var contentTypes = formatter.GetSupportedContentTypes(
|
||||||
MediaTypeHeaderValue.Parse("application/*"),
|
"application/*",
|
||||||
typeof(int));
|
typeof(int));
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
|
@ -234,7 +270,7 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var contentTypes = formatter.GetSupportedContentTypes(
|
var contentTypes = formatter.GetSupportedContentTypes(
|
||||||
MediaTypeHeaderValue.Parse("application/xml"),
|
"application/xml",
|
||||||
typeof(int));
|
typeof(int));
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
|
@ -251,7 +287,9 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
formatter.SupportedMediaTypes.Clear();
|
formatter.SupportedMediaTypes.Clear();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var contentTypes = formatter.GetSupportedContentTypes(contentType: null, objectType: typeof(int));
|
var contentTypes = formatter.GetSupportedContentTypes(
|
||||||
|
contentType: null,
|
||||||
|
objectType: typeof(int));
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Null(contentTypes);
|
Assert.Null(contentTypes);
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Http.Features;
|
using Microsoft.AspNet.Http.Features;
|
||||||
using Microsoft.AspNet.Http.Internal;
|
using Microsoft.AspNet.Http.Internal;
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
@ -21,7 +22,7 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var formatter = new StreamOutputFormatter();
|
var formatter = new StreamOutputFormatter();
|
||||||
var contentTypeHeader = contentType == null ? null : new MediaTypeHeaderValue(contentType);
|
var contentTypeHeader = new StringSegment(contentType);
|
||||||
|
|
||||||
var context = new OutputFormatterWriteContext(
|
var context = new OutputFormatterWriteContext(
|
||||||
new DefaultHttpContext(),
|
new DefaultHttpContext(),
|
||||||
|
|
@ -46,7 +47,7 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var formatter = new StreamOutputFormatter();
|
var formatter = new StreamOutputFormatter();
|
||||||
var contentTypeHeader = contentType == null ? null : new MediaTypeHeaderValue(contentType);
|
var contentTypeHeader = contentType == null ? new StringSegment() : new StringSegment(contentType);
|
||||||
|
|
||||||
var context = new OutputFormatterWriteContext(
|
var context = new OutputFormatterWriteContext(
|
||||||
new DefaultHttpContext(),
|
new DefaultHttpContext(),
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Http;
|
using Microsoft.AspNet.Http;
|
||||||
using Microsoft.AspNet.Http.Internal;
|
using Microsoft.AspNet.Http.Internal;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Extensions.Primitives;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
@ -35,9 +35,9 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
bool expectedCanWriteResult)
|
bool expectedCanWriteResult)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var expectedContentType = expectedCanWriteResult ?
|
var expectedContentType = expectedCanWriteResult ?
|
||||||
MediaTypeHeaderValue.Parse("text/plain") :
|
new StringSegment("text/plain") :
|
||||||
MediaTypeHeaderValue.Parse("application/json");
|
new StringSegment("application/json");
|
||||||
|
|
||||||
var formatter = new StringOutputFormatter();
|
var formatter = new StringOutputFormatter();
|
||||||
var type = useDeclaredTypeAsString ? typeof(string) : typeof(object);
|
var type = useDeclaredTypeAsString ? typeof(string) : typeof(object);
|
||||||
|
|
@ -47,7 +47,7 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
new TestHttpResponseStreamWriterFactory().CreateWriter,
|
new TestHttpResponseStreamWriterFactory().CreateWriter,
|
||||||
type,
|
type,
|
||||||
value);
|
value);
|
||||||
context.ContentType = MediaTypeHeaderValue.Parse("application/json");
|
context.ContentType = new StringSegment("application/json");
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = formatter.CanWriteResult(context);
|
var result = formatter.CanWriteResult(context);
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,12 @@ using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Http;
|
using Microsoft.AspNet.Http;
|
||||||
using Microsoft.AspNet.Http.Internal;
|
using Microsoft.AspNet.Http.Internal;
|
||||||
using Microsoft.AspNet.Mvc.Formatters;
|
using Microsoft.AspNet.Mvc.Formatters;
|
||||||
|
using Microsoft.AspNet.Mvc.TestCommon;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Logging.Testing;
|
using Microsoft.Extensions.Logging.Testing;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
@ -43,12 +45,12 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
// Act
|
// Act
|
||||||
var formatter = executor.SelectFormatter(
|
var formatter = executor.SelectFormatter(
|
||||||
context,
|
context,
|
||||||
new[] { new MediaTypeHeaderValue("application/json") },
|
new MediaTypeCollection { "application/json" },
|
||||||
formatters);
|
formatters);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Same(formatters[1], formatter);
|
Assert.Same(formatters[1], formatter);
|
||||||
Assert.Equal(new MediaTypeHeaderValue("application/json"), context.ContentType);
|
MediaTypeAssert.Equal("application/json", context.ContentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For this test case probably the most common use case is when there is a format mapping based
|
// For this test case probably the most common use case is when there is a format mapping based
|
||||||
|
|
@ -72,7 +74,7 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.IsType<TestStringOutputFormatter>(executor.SelectedOutputFormatter);
|
Assert.IsType<TestStringOutputFormatter>(executor.SelectedOutputFormatter);
|
||||||
Assert.Equal("text/plain; charset=utf-8", httpContext.Response.ContentType);
|
MediaTypeAssert.Equal("text/plain; charset=utf-8", httpContext.Response.ContentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -98,12 +100,12 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
// Act
|
// Act
|
||||||
var formatter = executor.SelectFormatter(
|
var formatter = executor.SelectFormatter(
|
||||||
context,
|
context,
|
||||||
new[] { new MediaTypeHeaderValue("application/json") },
|
new MediaTypeCollection { "application/json" },
|
||||||
formatters);
|
formatters);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Same(formatters[1], formatter);
|
Assert.Same(formatters[1], formatter);
|
||||||
Assert.Equal(new MediaTypeHeaderValue("application/json"), context.ContentType);
|
Assert.Equal(new StringSegment("application/json"), context.ContentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -149,7 +151,7 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
// Act
|
// Act
|
||||||
var formatter = executor.SelectFormatter(
|
var formatter = executor.SelectFormatter(
|
||||||
context,
|
context,
|
||||||
new[] { new MediaTypeHeaderValue("application/json") },
|
new MediaTypeCollection { "application/json" },
|
||||||
formatters);
|
formatters);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
|
@ -176,18 +178,18 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
}
|
}
|
||||||
|
|
||||||
// ObjectResult.ContentTypes, Accept header, expected content type
|
// ObjectResult.ContentTypes, Accept header, expected content type
|
||||||
public static TheoryData<string[], string, string> ContentTypes
|
public static TheoryData<MediaTypeCollection, string, string> ContentTypes
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
var contentTypes = new string[]
|
var contentTypes = new MediaTypeCollection
|
||||||
{
|
{
|
||||||
"text/plain",
|
"text/plain",
|
||||||
"text/xml",
|
"text/xml",
|
||||||
"application/json",
|
"application/json",
|
||||||
};
|
};
|
||||||
|
|
||||||
return new TheoryData<string[], string, string>()
|
return new TheoryData<MediaTypeCollection, string, string>()
|
||||||
{
|
{
|
||||||
// Empty accept header, should select based on ObjectResult.ContentTypes.
|
// Empty accept header, should select based on ObjectResult.ContentTypes.
|
||||||
{ contentTypes, "", "application/json" },
|
{ contentTypes, "", "application/json" },
|
||||||
|
|
@ -216,7 +218,7 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
[Theory]
|
[Theory]
|
||||||
[MemberData(nameof(ContentTypes))]
|
[MemberData(nameof(ContentTypes))]
|
||||||
public void SelectFormatter_WithMultipleProvidedContentTypes_DoesConneg(
|
public void SelectFormatter_WithMultipleProvidedContentTypes_DoesConneg(
|
||||||
IEnumerable<string> contentTypes,
|
MediaTypeCollection contentTypes,
|
||||||
string acceptHeader,
|
string acceptHeader,
|
||||||
string expectedContentType)
|
string expectedContentType)
|
||||||
{
|
{
|
||||||
|
|
@ -240,12 +242,12 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
// Act
|
// Act
|
||||||
var formatter = executor.SelectFormatter(
|
var formatter = executor.SelectFormatter(
|
||||||
context,
|
context,
|
||||||
contentTypes.Select(contentType => MediaTypeHeaderValue.Parse(contentType)).ToList(),
|
contentTypes,
|
||||||
formatters);
|
formatters);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Same(formatters[1], formatter);
|
Assert.Same(formatters[1], formatter);
|
||||||
Assert.Equal(new MediaTypeHeaderValue(expectedContentType), context.ContentType);
|
Assert.Equal(new StringSegment(expectedContentType), context.ContentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -270,12 +272,12 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
// Act
|
// Act
|
||||||
var formatter = executor.SelectFormatter(
|
var formatter = executor.SelectFormatter(
|
||||||
context,
|
context,
|
||||||
new List<MediaTypeHeaderValue>(),
|
new MediaTypeCollection(),
|
||||||
formatters);
|
formatters);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Same(formatters[1], formatter);
|
Assert.Same(formatters[1], formatter);
|
||||||
Assert.Equal(new MediaTypeHeaderValue("application/json"), context.ContentType);
|
Assert.Equal(new StringSegment("application/json"), context.ContentType);
|
||||||
Assert.Null(context.FailedContentNegotiation);
|
Assert.Null(context.FailedContentNegotiation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -297,17 +299,17 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
objectType: null,
|
objectType: null,
|
||||||
@object: null);
|
@object: null);
|
||||||
|
|
||||||
context.HttpContext.Request.Headers[HeaderNames.Accept] = "text/custom, application/custom";
|
context.HttpContext.Request.Headers[HeaderNames.Accept] = "text/custom,application/custom";
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var formatter = executor.SelectFormatter(
|
var formatter = executor.SelectFormatter(
|
||||||
context,
|
context,
|
||||||
new MediaTypeHeaderValue[] { },
|
new MediaTypeCollection { },
|
||||||
formatters);
|
formatters);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Same(formatters[0], formatter);
|
Assert.Same(formatters[0], formatter);
|
||||||
Assert.Equal(new MediaTypeHeaderValue("application/xml"), context.ContentType);
|
Assert.Equal(new StringSegment("application/xml"), context.ContentType);
|
||||||
Assert.True(context.FailedContentNegotiation);
|
Assert.True(context.FailedContentNegotiation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -373,9 +375,14 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var result = new ObjectResult("input");
|
var result = new ObjectResult("input");
|
||||||
result.ContentTypes = contentTypes
|
|
||||||
.Select(contentType => MediaTypeHeaderValue.Parse(contentType))
|
var mediaTypes = new MediaTypeCollection();
|
||||||
.ToList();
|
foreach (var contentType in contentTypes)
|
||||||
|
{
|
||||||
|
mediaTypes.Add(contentType);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.ContentTypes = mediaTypes;
|
||||||
|
|
||||||
var executor = CreateExecutor();
|
var executor = CreateExecutor();
|
||||||
|
|
||||||
|
|
@ -395,7 +402,7 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
// Chrome & Opera
|
// Chrome & Opera
|
||||||
[InlineData("text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", "application/json; charset=utf-8")]
|
[InlineData("text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", "application/json; charset=utf-8")]
|
||||||
// IE
|
// IE
|
||||||
[InlineData("text/html, application/xhtml+xml, */*", "application/json; charset=utf-8")]
|
[InlineData("text/html,application/xhtml+xml,*/*", "application/json; charset=utf-8")]
|
||||||
// Firefox & Safari
|
// Firefox & Safari
|
||||||
[InlineData("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "application/json; charset=utf-8")]
|
[InlineData("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "application/json; charset=utf-8")]
|
||||||
// Misc
|
// Misc
|
||||||
|
|
@ -432,7 +439,7 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
// Chrome & Opera
|
// Chrome & Opera
|
||||||
[InlineData("text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", "application/xml; charset=utf-8")]
|
[InlineData("text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", "application/xml; charset=utf-8")]
|
||||||
// IE
|
// IE
|
||||||
[InlineData("text/html, application/xhtml+xml, */*", "application/json; charset=utf-8")]
|
[InlineData("text/html,application/xhtml+xml,*/*", "application/json; charset=utf-8")]
|
||||||
// Firefox & Safari
|
// Firefox & Safari
|
||||||
[InlineData("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "application/xml; charset=utf-8")]
|
[InlineData("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "application/xml; charset=utf-8")]
|
||||||
// Misc
|
// Misc
|
||||||
|
|
@ -462,7 +469,8 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
await executor.ExecuteAsync(actionContext, result);
|
await executor.ExecuteAsync(actionContext, result);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(expectedContentType, actionContext.HttpContext.Response.Headers[HeaderNames.ContentType]);
|
var responseContentType = actionContext.HttpContext.Response.Headers[HeaderNames.ContentType];
|
||||||
|
MediaTypeAssert.Equal(expectedContentType, responseContentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IServiceCollection CreateServices()
|
private static IServiceCollection CreateServices()
|
||||||
|
|
@ -572,7 +580,7 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
|
|
||||||
new public IOutputFormatter SelectFormatter(
|
new public IOutputFormatter SelectFormatter(
|
||||||
OutputFormatterWriteContext formatterContext,
|
OutputFormatterWriteContext formatterContext,
|
||||||
IList<MediaTypeHeaderValue> contentTypes,
|
MediaTypeCollection contentTypes,
|
||||||
IList<IOutputFormatter> formatters)
|
IList<IOutputFormatter> formatters)
|
||||||
{
|
{
|
||||||
return base.SelectFormatter(formatterContext, contentTypes, formatters);
|
return base.SelectFormatter(formatterContext, contentTypes, formatters);
|
||||||
|
|
@ -593,7 +601,7 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
|
|
||||||
protected override IOutputFormatter SelectFormatter(
|
protected override IOutputFormatter SelectFormatter(
|
||||||
OutputFormatterWriteContext formatterContext,
|
OutputFormatterWriteContext formatterContext,
|
||||||
IList<MediaTypeHeaderValue> contentTypes,
|
MediaTypeCollection contentTypes,
|
||||||
IList<IOutputFormatter> formatters)
|
IList<IOutputFormatter> formatters)
|
||||||
{
|
{
|
||||||
SelectedOutputFormatter = base.SelectFormatter(formatterContext, contentTypes, formatters);
|
SelectedOutputFormatter = base.SelectFormatter(formatterContext, contentTypes, formatters);
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
// 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.Text;
|
using System.Text;
|
||||||
|
using Microsoft.AspNet.Mvc.Formatters;
|
||||||
|
using Microsoft.AspNet.Mvc.TestCommon;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
@ -102,13 +104,13 @@ namespace Microsoft.AspNet.Mvc.Internal
|
||||||
string expectedContentType)
|
string expectedContentType)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var defaultContentType = MediaTypeHeaderValue.Parse("text/default; p1=p1-value; charset=utf-8");
|
var defaultContentType = "text/default; p1=p1-value; charset=utf-8";
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
string resolvedContentType = null;
|
string resolvedContentType = null;
|
||||||
Encoding resolvedContentTypeEncoding = null;
|
Encoding resolvedContentTypeEncoding = null;
|
||||||
ResponseContentTypeHelper.ResolveContentTypeAndEncoding(
|
ResponseContentTypeHelper.ResolveContentTypeAndEncoding(
|
||||||
contentType,
|
contentType?.ToString(),
|
||||||
responseContentType,
|
responseContentType,
|
||||||
defaultContentType,
|
defaultContentType,
|
||||||
out resolvedContentType,
|
out resolvedContentType,
|
||||||
|
|
@ -123,7 +125,7 @@ namespace Microsoft.AspNet.Mvc.Internal
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var expectedContentType = "invalid-content-type";
|
var expectedContentType = "invalid-content-type";
|
||||||
var defaultContentType = MediaTypeHeaderValue.Parse("text/plain; charset=utf-8");
|
var defaultContentType = "text/plain; charset=utf-8";
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
string resolvedContentType = null;
|
string resolvedContentType = null;
|
||||||
|
|
@ -136,6 +138,7 @@ namespace Microsoft.AspNet.Mvc.Internal
|
||||||
out resolvedContentTypeEncoding);
|
out resolvedContentTypeEncoding);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
|
||||||
Assert.Equal(expectedContentType, resolvedContentType);
|
Assert.Equal(expectedContentType, resolvedContentType);
|
||||||
Assert.Equal(Encoding.UTF8, resolvedContentTypeEncoding);
|
Assert.Equal(Encoding.UTF8, resolvedContentTypeEncoding);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
|
using Microsoft.Net.Http.Headers;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
|
{
|
||||||
|
public class MediaTypeCollectionTest
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void Add_MediaTypeHeaderValue_AddsTheStringSegmentRepresentationOfTheMediaType()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var mediaTypeHeaderValue = MediaTypeHeaderValue.Parse("application/json;charset=utf-16");
|
||||||
|
var collection = new MediaTypeCollection();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
collection.Add(mediaTypeHeaderValue);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Contains("application/json; charset=utf-16", collection);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Insert_MediaTypeHeaderValue_AddsTheStringSegmentRepresentationOfTheMediaTypeOnTheGivenIndex()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var mediaTypeHeaderValue = MediaTypeHeaderValue.Parse("application/json;charset=utf-16");
|
||||||
|
var collection = new MediaTypeCollection
|
||||||
|
{
|
||||||
|
MediaTypeHeaderValue.Parse("text/plain"),
|
||||||
|
MediaTypeHeaderValue.Parse("text/xml")
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
collection.Insert(1, mediaTypeHeaderValue);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1, collection.IndexOf("application/json; charset=utf-16"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Remove_MediaTypeHeaderValue_RemovesTheStringSegmentRepresentationOfTheMediaType()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var collection = new MediaTypeCollection
|
||||||
|
{
|
||||||
|
MediaTypeHeaderValue.Parse("text/plain"),
|
||||||
|
MediaTypeHeaderValue.Parse("text/xml")
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
collection.Remove(MediaTypeHeaderValue.Parse("text/xml"));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.DoesNotContain("text/xml", collection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -10,11 +10,11 @@ using Microsoft.AspNet.Http;
|
||||||
using Microsoft.AspNet.Http.Features;
|
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.TestCommon;
|
||||||
using Microsoft.AspNet.Routing;
|
using Microsoft.AspNet.Routing;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Logging.Testing;
|
using Microsoft.Extensions.Logging.Testing;
|
||||||
using Microsoft.Net.Http.Headers;
|
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
@ -41,14 +41,14 @@ namespace Microsoft.AspNet.Mvc
|
||||||
// Arrange
|
// Arrange
|
||||||
var path = Path.GetFullPath("helllo.txt");
|
var path = Path.GetFullPath("helllo.txt");
|
||||||
var contentType = "text/plain; charset=us-ascii; p1=p1-value";
|
var contentType = "text/plain; charset=us-ascii; p1=p1-value";
|
||||||
var expectedMediaType = MediaTypeHeaderValue.Parse(contentType);
|
var expectedMediaType = contentType;
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = new PhysicalFileResult(path, contentType);
|
var result = new PhysicalFileResult(path, contentType);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(path, result.FileName);
|
Assert.Equal(path, result.FileName);
|
||||||
Assert.Equal(expectedMediaType, result.ContentType);
|
MediaTypeAssert.Equal(expectedMediaType, result.ContentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -99,7 +99,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
// Arrange
|
// Arrange
|
||||||
var expectedContentType = "text/foo; charset=us-ascii";
|
var expectedContentType = "text/foo; charset=us-ascii";
|
||||||
var path = Path.GetFullPath(Path.Combine(".", "TestFiles", "FilePathResultTestFile_ASCII.txt"));
|
var path = Path.GetFullPath(Path.Combine(".", "TestFiles", "FilePathResultTestFile_ASCII.txt"));
|
||||||
var result = new TestPhysicalFileResult(path, MediaTypeHeaderValue.Parse(expectedContentType))
|
var result = new TestPhysicalFileResult(path, expectedContentType)
|
||||||
{
|
{
|
||||||
IsAscii = true
|
IsAscii = true
|
||||||
};
|
};
|
||||||
|
|
@ -205,11 +205,6 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public TestPhysicalFileResult(string filePath, MediaTypeHeaderValue contentType)
|
|
||||||
: base(filePath, contentType)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsAscii { get; set; } = false;
|
public bool IsAscii { get; set; } = false;
|
||||||
|
|
||||||
protected override Stream GetFileStream(string path)
|
protected override Stream GetFileStream(string path)
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,9 @@ using Microsoft.AspNet.Http.Internal;
|
||||||
using Microsoft.AspNet.Mvc.Abstractions;
|
using Microsoft.AspNet.Mvc.Abstractions;
|
||||||
using Microsoft.AspNet.Mvc.Filters;
|
using Microsoft.AspNet.Mvc.Filters;
|
||||||
using Microsoft.AspNet.Mvc.Formatters;
|
using Microsoft.AspNet.Mvc.Formatters;
|
||||||
|
using Microsoft.AspNet.Mvc.TestCommon;
|
||||||
using Microsoft.AspNet.Routing;
|
using Microsoft.AspNet.Routing;
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
@ -21,8 +23,8 @@ namespace Microsoft.AspNet.Mvc.Test
|
||||||
public async Task ProducesAttribute_SetsContentType()
|
public async Task ProducesAttribute_SetsContentType()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var mediaType1 = MediaTypeHeaderValue.Parse("application/json");
|
var mediaType1 = new StringSegment("application/json");
|
||||||
var mediaType2 = MediaTypeHeaderValue.Parse("text/json;charset=utf-8");
|
var mediaType2 = new StringSegment("text/json;charset=utf-8");
|
||||||
var producesContentAttribute = new ProducesAttribute("application/json", "text/json;charset=utf-8");
|
var producesContentAttribute = new ProducesAttribute("application/json", "text/json;charset=utf-8");
|
||||||
var resultExecutingContext = CreateResultExecutingContext(new IFilterMetadata[] { producesContentAttribute });
|
var resultExecutingContext = CreateResultExecutingContext(new IFilterMetadata[] { producesContentAttribute });
|
||||||
var next = new ResultExecutionDelegate(
|
var next = new ResultExecutionDelegate(
|
||||||
|
|
@ -34,8 +36,8 @@ namespace Microsoft.AspNet.Mvc.Test
|
||||||
// Assert
|
// Assert
|
||||||
var objectResult = resultExecutingContext.Result as ObjectResult;
|
var objectResult = resultExecutingContext.Result as ObjectResult;
|
||||||
Assert.Equal(2, objectResult.ContentTypes.Count);
|
Assert.Equal(2, objectResult.ContentTypes.Count);
|
||||||
ValidateMediaType(mediaType1, objectResult.ContentTypes[0]);
|
MediaTypeAssert.Equal(mediaType1, objectResult.ContentTypes[0]);
|
||||||
ValidateMediaType(mediaType2, objectResult.ContentTypes[1]);
|
MediaTypeAssert.Equal(mediaType2, objectResult.ContentTypes[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -153,20 +155,6 @@ namespace Microsoft.AspNet.Mvc.Test
|
||||||
Assert.Empty(producesAttribute.ContentTypes);
|
Assert.Empty(producesAttribute.ContentTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ValidateMediaType(MediaTypeHeaderValue expectedMediaType, MediaTypeHeaderValue actualMediaType)
|
|
||||||
{
|
|
||||||
Assert.Equal(expectedMediaType.MediaType, actualMediaType.MediaType);
|
|
||||||
Assert.Equal(expectedMediaType.SubType, actualMediaType.SubType);
|
|
||||||
Assert.Equal(expectedMediaType.Charset, actualMediaType.Charset);
|
|
||||||
Assert.Equal(expectedMediaType.MatchesAllTypes, actualMediaType.MatchesAllTypes);
|
|
||||||
Assert.Equal(expectedMediaType.MatchesAllSubTypes, actualMediaType.MatchesAllSubTypes);
|
|
||||||
Assert.Equal(expectedMediaType.Parameters.Count, actualMediaType.Parameters.Count);
|
|
||||||
foreach (var item in expectedMediaType.Parameters)
|
|
||||||
{
|
|
||||||
Assert.Equal(item.Value, NameValueHeaderValue.Find(actualMediaType.Parameters, item.Name).Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ResultExecutedContext CreateResultExecutedContext(ResultExecutingContext context)
|
private static ResultExecutedContext CreateResultExecutedContext(ResultExecutingContext context)
|
||||||
{
|
{
|
||||||
return new ResultExecutedContext(context, context.Filters, context.Result, context.Controller);
|
return new ResultExecutedContext(context, context.Filters, context.Result, context.Controller);
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,11 @@ using Microsoft.AspNet.Http;
|
||||||
using Microsoft.AspNet.Http.Features;
|
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.TestCommon;
|
||||||
using Microsoft.AspNet.Routing;
|
using Microsoft.AspNet.Routing;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Logging.Testing;
|
using Microsoft.Extensions.Logging.Testing;
|
||||||
using Microsoft.Net.Http.Headers;
|
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
@ -42,14 +42,14 @@ namespace Microsoft.AspNet.Mvc
|
||||||
// Arrange
|
// Arrange
|
||||||
var path = Path.GetFullPath("helllo.txt");
|
var path = Path.GetFullPath("helllo.txt");
|
||||||
var contentType = "text/plain; charset=us-ascii; p1=p1-value";
|
var contentType = "text/plain; charset=us-ascii; p1=p1-value";
|
||||||
var expectedMediaType = MediaTypeHeaderValue.Parse(contentType);
|
var expectedMediaType = contentType;
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = new VirtualFileResult(path, contentType);
|
var result = new VirtualFileResult(path, contentType);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(path, result.FileName);
|
Assert.Equal(path, result.FileName);
|
||||||
Assert.Equal(expectedMediaType, result.ContentType);
|
MediaTypeAssert.Equal(expectedMediaType, result.ContentType);
|
||||||
|
|
||||||
}
|
}
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -137,7 +137,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
// Arrange
|
// Arrange
|
||||||
var expectedContentType = "text/foo; charset=us-ascii";
|
var expectedContentType = "text/foo; charset=us-ascii";
|
||||||
var result = new TestVirtualFileResult(
|
var result = new TestVirtualFileResult(
|
||||||
"FilePathResultTestFile_ASCII.txt", MediaTypeHeaderValue.Parse(expectedContentType))
|
"FilePathResultTestFile_ASCII.txt", expectedContentType)
|
||||||
{
|
{
|
||||||
FileProvider = GetFileProvider("FilePathResultTestFile_ASCII.txt"),
|
FileProvider = GetFileProvider("FilePathResultTestFile_ASCII.txt"),
|
||||||
IsAscii = true,
|
IsAscii = true,
|
||||||
|
|
@ -347,11 +347,6 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public TestVirtualFileResult(string filePath, MediaTypeHeaderValue contentType)
|
|
||||||
: base(filePath, contentType)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsAscii { get; set; } = false;
|
public bool IsAscii { get; set; } = false;
|
||||||
|
|
||||||
protected override Stream GetFileStream(IFileInfo fileInfo)
|
protected override Stream GetFileStream(IFileInfo fileInfo)
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
var context = GetActionContext();
|
var context = GetActionContext();
|
||||||
|
|
||||||
var result = new JsonResult(new { foo = "abcd" });
|
var result = new JsonResult(new { foo = "abcd" });
|
||||||
result.ContentType = new MediaTypeHeaderValue("text/json");
|
result.ContentType = "text/json";
|
||||||
var executor = CreateExcutor();
|
var executor = CreateExcutor();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -74,7 +74,7 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
result.ContentType = new MediaTypeHeaderValue("text/json")
|
result.ContentType = new MediaTypeHeaderValue("text/json")
|
||||||
{
|
{
|
||||||
Encoding = Encoding.ASCII
|
Encoding = Encoding.ASCII
|
||||||
};
|
}.ToString();
|
||||||
var executor = CreateExcutor();
|
var executor = CreateExcutor();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ using Microsoft.AspNet.Routing;
|
||||||
using Microsoft.AspNet.Testing;
|
using Microsoft.AspNet.Testing;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Logging.Testing;
|
using Microsoft.Extensions.Logging.Testing;
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
@ -262,7 +263,7 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
typeof(string),
|
typeof(string),
|
||||||
content)
|
content)
|
||||||
{
|
{
|
||||||
ContentType = mediaType,
|
ContentType = new StringSegment(mediaType.ToString()),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -313,7 +314,7 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
||||||
outputType,
|
outputType,
|
||||||
outputValue)
|
outputValue)
|
||||||
{
|
{
|
||||||
ContentType = mediaTypeHeaderValue,
|
ContentType = new StringSegment(contentType),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ using Microsoft.AspNet.Http;
|
||||||
using Microsoft.AspNet.Http.Internal;
|
using Microsoft.AspNet.Http.Internal;
|
||||||
using Microsoft.AspNet.Mvc.Formatters.Xml.Internal;
|
using Microsoft.AspNet.Mvc.Formatters.Xml.Internal;
|
||||||
using Microsoft.AspNet.Testing.xunit;
|
using Microsoft.AspNet.Testing.xunit;
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
@ -123,7 +124,7 @@ namespace Microsoft.AspNet.Mvc.Formatters.Xml
|
||||||
var formatter = new TestXmlDataContractSerializerOutputFormatter();
|
var formatter = new TestXmlDataContractSerializerOutputFormatter();
|
||||||
|
|
||||||
var context = GetOutputFormatterContext(input, typeof(DummyClass));
|
var context = GetOutputFormatterContext(input, typeof(DummyClass));
|
||||||
context.ContentType = MediaTypeHeaderValue.Parse("application/xml");
|
context.ContentType = new StringSegment("application/xml");
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
formatter.CanWriteResult(context);
|
formatter.CanWriteResult(context);
|
||||||
|
|
@ -382,7 +383,7 @@ namespace Microsoft.AspNet.Mvc.Formatters.Xml
|
||||||
// Arrange
|
// Arrange
|
||||||
var formatter = new XmlDataContractSerializerOutputFormatter();
|
var formatter = new XmlDataContractSerializerOutputFormatter();
|
||||||
var outputFormatterContext = GetOutputFormatterContext(input, declaredType);
|
var outputFormatterContext = GetOutputFormatterContext(input, declaredType);
|
||||||
outputFormatterContext.ContentType = MediaTypeHeaderValue.Parse("application/xml");
|
outputFormatterContext.ContentType = new StringSegment("application/xml");
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = formatter.CanWriteResult(outputFormatterContext);
|
var result = formatter.CanWriteResult(outputFormatterContext);
|
||||||
|
|
@ -412,7 +413,7 @@ namespace Microsoft.AspNet.Mvc.Formatters.Xml
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = formatter.GetSupportedContentTypes(
|
var result = formatter.GetSupportedContentTypes(
|
||||||
MediaTypeHeaderValue.Parse("application/xml"),
|
"application/xml",
|
||||||
type);
|
type);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ using System.Xml.Serialization;
|
||||||
using Microsoft.AspNet.Http;
|
using Microsoft.AspNet.Http;
|
||||||
using Microsoft.AspNet.Http.Internal;
|
using Microsoft.AspNet.Http.Internal;
|
||||||
using Microsoft.AspNet.Mvc.Formatters.Xml.Internal;
|
using Microsoft.AspNet.Mvc.Formatters.Xml.Internal;
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
@ -76,7 +77,7 @@ namespace Microsoft.AspNet.Mvc.Formatters.Xml
|
||||||
var formatter = new TestXmlSerializerOutputFormatter();
|
var formatter = new TestXmlSerializerOutputFormatter();
|
||||||
|
|
||||||
var context = GetOutputFormatterContext(input, typeof(DummyClass));
|
var context = GetOutputFormatterContext(input, typeof(DummyClass));
|
||||||
context.ContentType = MediaTypeHeaderValue.Parse("application/xml");
|
context.ContentType = new StringSegment("application/xml");
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
formatter.CanWriteResult(context);
|
formatter.CanWriteResult(context);
|
||||||
|
|
@ -300,7 +301,7 @@ namespace Microsoft.AspNet.Mvc.Formatters.Xml
|
||||||
// Arrange
|
// Arrange
|
||||||
var formatter = new XmlSerializerOutputFormatter();
|
var formatter = new XmlSerializerOutputFormatter();
|
||||||
var outputFormatterContext = GetOutputFormatterContext(input, declaredType);
|
var outputFormatterContext = GetOutputFormatterContext(input, declaredType);
|
||||||
outputFormatterContext.ContentType = MediaTypeHeaderValue.Parse("application/xml");
|
outputFormatterContext.ContentType = new StringSegment("application/xml");
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = formatter.CanWriteResult(outputFormatterContext);
|
var result = formatter.CanWriteResult(outputFormatterContext);
|
||||||
|
|
@ -342,7 +343,7 @@ namespace Microsoft.AspNet.Mvc.Formatters.Xml
|
||||||
var formatter = new XmlSerializerOutputFormatter();
|
var formatter = new XmlSerializerOutputFormatter();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = formatter.GetSupportedContentTypes(MediaTypeHeaderValue.Parse("application/xml"), type);
|
var result = formatter.GetSupportedContentTypes("application/xml", type);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
if (expectedOutput != null)
|
if (expectedOutput != null)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
using System;
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
|
using Microsoft.Net.Http.Headers;
|
||||||
|
using Xunit.Sdk;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.TestCommon
|
||||||
|
{
|
||||||
|
public class MediaTypeAssert
|
||||||
|
{
|
||||||
|
public static void Equal(string left, string right)
|
||||||
|
{
|
||||||
|
Equal(new StringSegment(left), new StringSegment(right));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Equal(string left, StringSegment right)
|
||||||
|
{
|
||||||
|
Equal(new StringSegment(left), right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Equal(StringSegment left, string right)
|
||||||
|
{
|
||||||
|
Equal(left, new StringSegment(right));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Equal(StringSegment left, StringSegment right)
|
||||||
|
{
|
||||||
|
if (!left.HasValue && !right.HasValue)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (!left.HasValue || !right.HasValue)
|
||||||
|
{
|
||||||
|
throw new EqualException(left.ToString(), right.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
MediaTypeHeaderValue leftMediaType = null;
|
||||||
|
MediaTypeHeaderValue rightMediaType = null;
|
||||||
|
|
||||||
|
if (!MediaTypeHeaderValue.TryParse(left.Value, out leftMediaType) ||
|
||||||
|
!MediaTypeHeaderValue.TryParse(right.Value, out rightMediaType) ||
|
||||||
|
!leftMediaType.Equals(rightMediaType))
|
||||||
|
{
|
||||||
|
throw new EqualException(left.ToString(), right.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,6 +8,7 @@ using System.Text;
|
||||||
using Microsoft.AspNet.Http;
|
using Microsoft.AspNet.Http;
|
||||||
using Microsoft.AspNet.Http.Internal;
|
using Microsoft.AspNet.Http.Internal;
|
||||||
using Microsoft.AspNet.Mvc.Controllers;
|
using Microsoft.AspNet.Mvc.Controllers;
|
||||||
|
using Microsoft.AspNet.Mvc.Formatters;
|
||||||
using Microsoft.AspNet.Routing;
|
using Microsoft.AspNet.Routing;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
@ -90,7 +91,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
var contentResult = Assert.IsType<ContentResult>(result);
|
var contentResult = Assert.IsType<ContentResult>(result);
|
||||||
Assert.Equal(content, contentResult.Content);
|
Assert.Equal(content, contentResult.Content);
|
||||||
Assert.Equal("text/asp; charset=us-ascii", contentResult.ContentType.ToString());
|
Assert.Equal("text/asp; charset=us-ascii", contentResult.ContentType.ToString());
|
||||||
Assert.Equal(encoding, contentResult.ContentType.Encoding);
|
Assert.Equal(encoding, MediaTypeEncoding.GetEncoding(contentResult.ContentType));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,11 @@ using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Http;
|
using Microsoft.AspNet.Http;
|
||||||
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.Infrastructure;
|
using Microsoft.AspNet.Mvc.Infrastructure;
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
using Microsoft.AspNet.Mvc.Rendering;
|
using Microsoft.AspNet.Mvc.Rendering;
|
||||||
|
using Microsoft.AspNet.Mvc.TestCommon;
|
||||||
using Microsoft.AspNet.Mvc.ViewComponents;
|
using Microsoft.AspNet.Mvc.ViewComponents;
|
||||||
using Microsoft.AspNet.Mvc.ViewFeatures;
|
using Microsoft.AspNet.Mvc.ViewFeatures;
|
||||||
using Microsoft.AspNet.Mvc.ViewFeatures.Buffer;
|
using Microsoft.AspNet.Mvc.ViewFeatures.Buffer;
|
||||||
|
|
@ -367,26 +369,26 @@ namespace Microsoft.AspNet.Mvc
|
||||||
Assert.Equal(404, actionContext.HttpContext.Response.StatusCode);
|
Assert.Equal(404, actionContext.HttpContext.Response.StatusCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TheoryData<MediaTypeHeaderValue, string> ViewComponentResultContentTypeData
|
public static TheoryData<string, string> ViewComponentResultContentTypeData
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return new TheoryData<MediaTypeHeaderValue, string>
|
return new TheoryData<string, string>
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
null,
|
null,
|
||||||
"text/html; charset=utf-8"
|
"text/html; charset=utf-8"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
new MediaTypeHeaderValue("text/foo"),
|
"text/foo",
|
||||||
"text/foo"
|
"text/foo"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
MediaTypeHeaderValue.Parse("text/foo;p1=p1-value"),
|
"text/foo;p1=p1-value",
|
||||||
"text/foo; p1=p1-value"
|
"text/foo; p1=p1-value"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
new MediaTypeHeaderValue("text/foo") { Encoding = Encoding.ASCII },
|
new MediaTypeHeaderValue("text/foo") { Encoding = Encoding.ASCII }.ToString(),
|
||||||
"text/foo; charset=us-ascii"
|
"text/foo; charset=us-ascii"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -396,8 +398,8 @@ namespace Microsoft.AspNet.Mvc
|
||||||
[Theory]
|
[Theory]
|
||||||
[MemberData(nameof(ViewComponentResultContentTypeData))]
|
[MemberData(nameof(ViewComponentResultContentTypeData))]
|
||||||
public async Task ViewComponentResult_SetsContentTypeHeader(
|
public async Task ViewComponentResult_SetsContentTypeHeader(
|
||||||
MediaTypeHeaderValue contentType,
|
string contentType,
|
||||||
string expectedContentTypeHeaderValue)
|
string expectedContentType)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var descriptor = new ViewComponentDescriptor()
|
var descriptor = new ViewComponentDescriptor()
|
||||||
|
|
@ -424,13 +426,14 @@ namespace Microsoft.AspNet.Mvc
|
||||||
await viewComponentResult.ExecuteResultAsync(actionContext);
|
await viewComponentResult.ExecuteResultAsync(actionContext);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(expectedContentTypeHeaderValue, actionContext.HttpContext.Response.ContentType);
|
var resultContentType = actionContext.HttpContext.Response.ContentType;
|
||||||
|
MediaTypeAssert.Equal(expectedContentType, resultContentType);
|
||||||
|
|
||||||
// Check if the original instance provided by the user has not changed.
|
// Check if the original instance provided by the user has not changed.
|
||||||
// Since we do not have access to the new instance created within the view executor,
|
// Since we do not have access to the new instance created within the view executor,
|
||||||
// check if at least the content is the same.
|
// check if at least the content is the same.
|
||||||
var contentTypeAfterViewResultExecution = contentType?.ToString();
|
var contentTypeAfterViewResultExecution = contentType?.ToString();
|
||||||
Assert.Equal(contentTypeBeforeViewResultExecution, contentTypeAfterViewResultExecution);
|
MediaTypeAssert.Equal(contentTypeBeforeViewResultExecution, contentTypeAfterViewResultExecution);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -454,7 +457,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
Arguments = new { name = "World!" },
|
Arguments = new { name = "World!" },
|
||||||
ViewComponentName = "Text",
|
ViewComponentName = "Text",
|
||||||
ContentType = new MediaTypeHeaderValue("text/html") { Encoding = Encoding.UTF8 },
|
ContentType = new MediaTypeHeaderValue("text/html") { Encoding = Encoding.UTF8 }.ToString(),
|
||||||
TempData = _tempDataDictionary,
|
TempData = _tempDataDictionary,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
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.ModelBinding;
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
using Microsoft.AspNet.Mvc.ViewEngines;
|
using Microsoft.AspNet.Mvc.ViewEngines;
|
||||||
using Microsoft.AspNet.Routing;
|
using Microsoft.AspNet.Routing;
|
||||||
|
|
@ -262,7 +263,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
||||||
var context = GetActionContext();
|
var context = GetActionContext();
|
||||||
var executor = GetViewExecutor();
|
var executor = GetViewExecutor();
|
||||||
|
|
||||||
var contentType = MediaTypeHeaderValue.Parse("application/x-my-content-type");
|
var contentType = "application/x-my-content-type";
|
||||||
|
|
||||||
var viewResult = new PartialViewResult
|
var viewResult = new PartialViewResult
|
||||||
{
|
{
|
||||||
|
|
@ -281,7 +282,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
||||||
// Check if the original instance provided by the user has not changed.
|
// Check if the original instance provided by the user has not changed.
|
||||||
// Since we do not have access to the new instance created within the view executor,
|
// Since we do not have access to the new instance created within the view executor,
|
||||||
// check if at least the content is the same.
|
// check if at least the content is the same.
|
||||||
Assert.Null(contentType.Encoding);
|
Assert.Null(MediaTypeEncoding.GetEncoding(contentType));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,10 @@ using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Http;
|
using Microsoft.AspNet.Http;
|
||||||
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.ModelBinding;
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
using Microsoft.AspNet.Mvc.Rendering;
|
using Microsoft.AspNet.Mvc.Rendering;
|
||||||
|
using Microsoft.AspNet.Mvc.TestCommon;
|
||||||
using Microsoft.AspNet.Mvc.ViewEngines;
|
using Microsoft.AspNet.Mvc.ViewEngines;
|
||||||
using Microsoft.AspNet.Routing;
|
using Microsoft.AspNet.Routing;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
@ -115,11 +117,11 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
||||||
view,
|
view,
|
||||||
viewData,
|
viewData,
|
||||||
Mock.Of<ITempDataDictionary>(),
|
Mock.Of<ITempDataDictionary>(),
|
||||||
contentType,
|
contentType?.ToString(),
|
||||||
statusCode: null);
|
statusCode: null);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(expectedContentType, context.Response.ContentType);
|
MediaTypeAssert.Equal(expectedContentType, context.Response.ContentType);
|
||||||
Assert.Equal("abcd", Encoding.UTF8.GetString(memoryStream.ToArray()));
|
Assert.Equal("abcd", Encoding.UTF8.GetString(memoryStream.ToArray()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
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.ModelBinding;
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
using Microsoft.AspNet.Mvc.ViewEngines;
|
using Microsoft.AspNet.Mvc.ViewEngines;
|
||||||
using Microsoft.AspNet.Routing;
|
using Microsoft.AspNet.Routing;
|
||||||
|
|
@ -258,7 +259,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
||||||
var context = GetActionContext();
|
var context = GetActionContext();
|
||||||
var executor = GetViewExecutor();
|
var executor = GetViewExecutor();
|
||||||
|
|
||||||
var contentType = MediaTypeHeaderValue.Parse("application/x-my-content-type");
|
var contentType = "application/x-my-content-type";
|
||||||
|
|
||||||
var viewResult = new ViewResult
|
var viewResult = new ViewResult
|
||||||
{
|
{
|
||||||
|
|
@ -273,11 +274,6 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal("application/x-my-content-type", context.HttpContext.Response.ContentType);
|
Assert.Equal("application/x-my-content-type", context.HttpContext.Response.ContentType);
|
||||||
|
|
||||||
// Check if the original instance provided by the user has not changed.
|
|
||||||
// Since we do not have access to the new instance created within the view executor,
|
|
||||||
// check if at least the content is the same.
|
|
||||||
Assert.Null(contentType.Encoding);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ using Microsoft.AspNet.Http;
|
||||||
using Microsoft.AspNet.Http.Internal;
|
using Microsoft.AspNet.Http.Internal;
|
||||||
using Microsoft.AspNet.Mvc;
|
using Microsoft.AspNet.Mvc;
|
||||||
using Microsoft.AspNet.Mvc.Controllers;
|
using Microsoft.AspNet.Mvc.Controllers;
|
||||||
|
using Microsoft.AspNet.Mvc.Formatters;
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
using Microsoft.AspNet.Routing;
|
using Microsoft.AspNet.Routing;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
@ -264,7 +265,7 @@ namespace System.Web.Http
|
||||||
var jsonResult = Assert.IsType<JsonResult>(result);
|
var jsonResult = Assert.IsType<JsonResult>(result);
|
||||||
Assert.Same(product, jsonResult.Value);
|
Assert.Same(product, jsonResult.Value);
|
||||||
|
|
||||||
Assert.Same(Encoding.UTF8, jsonResult.ContentType.Encoding);
|
Assert.Same(Encoding.UTF8, MediaTypeEncoding.GetEncoding(jsonResult.ContentType));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ namespace BasicWebSite.Controllers
|
||||||
public JsonResult CustomContentType()
|
public JsonResult CustomContentType()
|
||||||
{
|
{
|
||||||
var result = new JsonResult(new { Message = "hello" });
|
var result = new JsonResult(new { Message = "hello" });
|
||||||
result.ContentType = MediaTypeHeaderValue.Parse("application/message+json");
|
result.ContentType = "application/message+json";
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,9 +38,11 @@ namespace BasicWebSite.Formatters
|
||||||
builder.AppendLine();
|
builder.AppendLine();
|
||||||
builder.AppendLine("END:VCARD");
|
builder.AppendLine("END:VCARD");
|
||||||
|
|
||||||
|
var selectedEncoding = MediaTypeEncoding.GetEncoding(context.ContentType) ?? Encoding.UTF8;
|
||||||
|
|
||||||
await context.HttpContext.Response.WriteAsync(
|
await context.HttpContext.Response.WriteAsync(
|
||||||
builder.ToString(),
|
builder.ToString(),
|
||||||
context.ContentType?.Encoding ?? Encoding.UTF8);
|
selectedEncoding);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -41,9 +41,11 @@ namespace BasicWebSite.Formatters
|
||||||
builder.AppendLine();
|
builder.AppendLine();
|
||||||
builder.AppendLine("END:VCARD");
|
builder.AppendLine("END:VCARD");
|
||||||
|
|
||||||
|
var selectedEncoding = MediaTypeEncoding.GetEncoding(context.ContentType) ?? Encoding.UTF8;
|
||||||
|
|
||||||
await context.HttpContext.Response.WriteAsync(
|
await context.HttpContext.Response.WriteAsync(
|
||||||
builder.ToString(),
|
builder.ToString(),
|
||||||
context.ContentType?.Encoding ?? Encoding.UTF8);
|
selectedEncoding);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -14,7 +14,7 @@ namespace FiltersWebSite
|
||||||
context.Result = new ContentResult()
|
context.Result = new ContentResult()
|
||||||
{
|
{
|
||||||
Content = "4",
|
Content = "4",
|
||||||
ContentType = new MediaTypeHeaderValue("text/plain")
|
ContentType = "text/plain"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ namespace FiltersWebSite
|
||||||
context.Result = new ContentResult
|
context.Result = new ContentResult
|
||||||
{
|
{
|
||||||
Content = "The Action was never executed",
|
Content = "The Action was never executed",
|
||||||
ContentType = new MediaTypeHeaderValue("text/plain")
|
ContentType = "text/plain"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ namespace FiltersWebSite
|
||||||
return new ContentResult()
|
return new ContentResult()
|
||||||
{
|
{
|
||||||
Content = content,
|
Content = content,
|
||||||
ContentType = new MediaTypeHeaderValue("text/plain"),
|
ContentType = "text/plain",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue