600 lines
29 KiB
C#
600 lines
29 KiB
C#
//// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
|
|
|
using Microsoft.Owin;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.Diagnostics.Contracts;
|
|
using System.Linq;
|
|
using System.Net.Http;
|
|
using System.Net.Http.Formatting;
|
|
using System.Net.Http.Headers;
|
|
using System.Text;
|
|
using System.Web.Http;
|
|
|
|
namespace Microsoft.AspNet.Mvc
|
|
{
|
|
/// <summary>
|
|
/// Class that selects a <see cref="MediaTypeFormatter"/> for an <see cref="HttpRequestMessage"/>
|
|
/// or <see cref="HttpResponseMessage"/>.
|
|
/// </summary>
|
|
public class DefaultContentNegotiator : IOwinContentNegotiator
|
|
{
|
|
// public DefaultContentNegotiator()
|
|
// : this(false)
|
|
// {
|
|
// }
|
|
|
|
// /// <summary>
|
|
// /// Initializes a new instance of the <see cref="DefaultContentNegotiator"/> with
|
|
// /// the given setting for <paramref name="excludeMatchOnTypeOnly"/>.
|
|
// /// </summary>
|
|
// /// <param name="excludeMatchOnTypeOnly">
|
|
// /// If ExcludeMatchOnTypeOnly is true then we don't match on type only which means
|
|
// /// that we return null if we can't match on anything in the request. This is useful
|
|
// /// for generating 406 (Not Acceptable) status codes.
|
|
// /// </param>
|
|
// public DefaultContentNegotiator(bool excludeMatchOnTypeOnly)
|
|
// {
|
|
// ExcludeMatchOnTypeOnly = excludeMatchOnTypeOnly;
|
|
// }
|
|
|
|
// /// <summary>
|
|
// /// If ExcludeMatchOnTypeOnly is true then we don't match on type only which means
|
|
// /// that we return null if we can't match on anything in the request. This is useful
|
|
// /// for generating 406 (Not Acceptable) status codes.
|
|
// /// </summary>
|
|
// public bool ExcludeMatchOnTypeOnly { get; private set; }
|
|
|
|
// /// <summary>
|
|
// /// Performs content negotiating by selecting the most appropriate <see cref="MediaTypeFormatter"/> out of the passed in
|
|
// /// <paramref name="formatters"/> for the given <paramref name="request"/> that can serialize an object of the given
|
|
// /// <paramref name="type"/>.
|
|
// /// </summary>
|
|
// /// <param name="type">The type to be serialized.</param>
|
|
// /// <param name="request">The request.</param>
|
|
// /// <param name="formatters">The set of <see cref="MediaTypeFormatter"/> objects from which to choose.</param>
|
|
// /// <returns>The result of the negotiation containing the most appropriate <see cref="MediaTypeFormatter"/> instance,
|
|
// /// or <c>null</c> if there is no appropriate formatter.</returns>
|
|
// public virtual ContentNegotiationResult Negotiate(Type type, IOwinContext context, IEnumerable<MediaTypeFormatter> formatters)
|
|
// {
|
|
// // Performance-sensitive
|
|
// if (type == null)
|
|
// {
|
|
// throw new ArgumentNullException("type");
|
|
// }
|
|
// if (context == null)
|
|
// {
|
|
// throw new ArgumentNullException("context");
|
|
// }
|
|
// if (formatters == null)
|
|
// {
|
|
// throw new ArgumentNullException("formatters");
|
|
// }
|
|
|
|
// var request = context.Request;
|
|
|
|
// // Go through each formatter to compute how well it matches.
|
|
// Collection<MediaTypeFormatterMatch> matches = ComputeFormatterMatches(type, request, formatters);
|
|
|
|
// // Select best formatter match among the matches
|
|
// MediaTypeFormatterMatch bestFormatterMatch = SelectResponseMediaTypeFormatter(matches);
|
|
|
|
// // We found a best formatter
|
|
// if (bestFormatterMatch != null)
|
|
// {
|
|
// // Find the best character encoding for the selected formatter
|
|
// Encoding bestEncodingMatch = SelectResponseCharacterEncoding(request, bestFormatterMatch.Formatter);
|
|
// if (bestEncodingMatch != null)
|
|
// {
|
|
// bestFormatterMatch.MediaType.CharSet = bestEncodingMatch.WebName;
|
|
// }
|
|
|
|
// MediaTypeHeaderValue bestMediaType = bestFormatterMatch.MediaType;
|
|
// MediaTypeFormatter bestFormatter = bestFormatterMatch.Formatter; // this is OData only scenario at the moment: .GetPerRequestFormatterInstance(type, request, bestMediaType);
|
|
// return new ContentNegotiationResult(bestFormatter, bestMediaType);
|
|
// }
|
|
|
|
// return null;
|
|
// }
|
|
|
|
// /// <summary>
|
|
// /// Determine how well each formatter matches by associating a <see cref="MediaTypeFormatterMatchRanking"/> value
|
|
// /// with the formatter. Then associate the quality of the match based on q-factors and other parameters. The result of this
|
|
// /// method is a collection of the matches found categorized and assigned a quality value.
|
|
// /// </summary>
|
|
// /// <param name="type">The type to be serialized.</param>
|
|
// /// <param name="request">The request.</param>
|
|
// /// <param name="formatters">The set of <see cref="MediaTypeFormatter"/> objects from which to choose.</param>
|
|
// /// <returns>A collection containing all the matches.</returns>
|
|
// protected virtual Collection<MediaTypeFormatterMatch> ComputeFormatterMatches(Type type, IOwinRequest request, IEnumerable<MediaTypeFormatter> formatters)
|
|
// {
|
|
// // Performance-sensitive
|
|
// if (type == null)
|
|
// {
|
|
// throw new ArgumentNullException("type");
|
|
// }
|
|
// if (request == null)
|
|
// {
|
|
// throw new ArgumentNullException("request");
|
|
// }
|
|
// if (formatters == null)
|
|
// {
|
|
// throw new ArgumentNullException("formatters");
|
|
// }
|
|
|
|
// IEnumerable<MediaTypeWithQualityHeaderValue> sortedAcceptValues = null;
|
|
|
|
// // Go through each formatter to find how well it matches.
|
|
// List<MediaTypeFormatterMatch> matches = new List<MediaTypeFormatterMatch>();
|
|
// MediaTypeFormatter[] writingFormatters = GetWritingFormatters(formatters);
|
|
// for (int i = 0; i < writingFormatters.Length; i++)
|
|
// {
|
|
// MediaTypeFormatter formatter = writingFormatters[i];
|
|
// MediaTypeFormatterMatch match = null;
|
|
|
|
// // Check first that formatter can write the actual type
|
|
// if (!formatter.CanWriteType(type))
|
|
// {
|
|
// // Formatter can't even write the type so no match at all
|
|
// continue;
|
|
// }
|
|
|
|
// // Match against media type mapping.
|
|
// if ((match = MatchMediaTypeMapping(request, formatter)) != null)
|
|
// {
|
|
// matches.Add(match);
|
|
// continue;
|
|
// }
|
|
|
|
// // Match against the accept header values.
|
|
// if (sortedAcceptValues == null)
|
|
// {
|
|
// // Sort the Accept header values in descending order based on q-factor
|
|
// sortedAcceptValues = SortMediaTypeWithQualityHeaderValuesByQFactor(request.Headers.Accept);
|
|
// }
|
|
// if ((match = MatchAcceptHeader(sortedAcceptValues, formatter)) != null)
|
|
// {
|
|
// matches.Add(match);
|
|
// continue;
|
|
// }
|
|
|
|
// // Match against request's media type if any
|
|
// if ((match = MatchRequestMediaType(request, formatter)) != null)
|
|
// {
|
|
// matches.Add(match);
|
|
// continue;
|
|
// }
|
|
|
|
// // Check whether we should match on type or stop the matching process.
|
|
// // The latter is used to generate 406 (Not Acceptable) status codes.
|
|
// bool shouldMatchOnType = ShouldMatchOnType(sortedAcceptValues);
|
|
|
|
// // Match against the type of object we are writing out
|
|
// if (shouldMatchOnType && (match = MatchType(type, formatter)) != null)
|
|
// {
|
|
// matches.Add(match);
|
|
// continue;
|
|
// }
|
|
// }
|
|
|
|
// return matches;
|
|
// }
|
|
|
|
// /// <summary>
|
|
// /// Select the best match among the candidate matches found.
|
|
// /// </summary>
|
|
// /// <param name="matches">The collection of matches.</param>
|
|
// /// <returns>The <see cref="MediaTypeFormatterMatch"/> determined to be the best match.</returns>
|
|
// protected virtual MediaTypeFormatterMatch SelectResponseMediaTypeFormatter(ICollection<MediaTypeFormatterMatch> matches)
|
|
// {
|
|
// // Performance-sensitive
|
|
// if (matches == null)
|
|
// {
|
|
// throw new ArgumentNullException("matches");
|
|
// }
|
|
|
|
// List<MediaTypeFormatterMatch> matchList = matches.AsList();
|
|
|
|
// MediaTypeFormatterMatch bestMatchOnType = null;
|
|
// MediaTypeFormatterMatch bestMatchOnAcceptHeaderLiteral = null;
|
|
// MediaTypeFormatterMatch bestMatchOnAcceptHeaderSubtypeMediaRange = null;
|
|
// MediaTypeFormatterMatch bestMatchOnAcceptHeaderAllMediaRange = null;
|
|
// MediaTypeFormatterMatch bestMatchOnMediaTypeMapping = null;
|
|
// MediaTypeFormatterMatch bestMatchOnRequestMediaType = null;
|
|
|
|
// // Go through each formatter to find the best match in each category.
|
|
// for (int i = 0; i < matchList.Count; i++)
|
|
// {
|
|
// MediaTypeFormatterMatch match = matchList[i];
|
|
// switch (match.Ranking)
|
|
// {
|
|
// case MediaTypeFormatterMatchRanking.MatchOnCanWriteType:
|
|
// // First match by type trumps all other type matches
|
|
// if (bestMatchOnType == null)
|
|
// {
|
|
// bestMatchOnType = match;
|
|
// }
|
|
// break;
|
|
|
|
// case MediaTypeFormatterMatchRanking.MatchOnRequestWithMediaTypeMapping:
|
|
// // Matches on accept headers using mappings must choose the highest quality match
|
|
// bestMatchOnMediaTypeMapping = UpdateBestMatch(bestMatchOnMediaTypeMapping, match);
|
|
// break;
|
|
|
|
// case MediaTypeFormatterMatchRanking.MatchOnRequestAcceptHeaderLiteral:
|
|
// // Matches on accept headers must choose the highest quality match.
|
|
// // A match of 0.0 means we won't use it at all.
|
|
// bestMatchOnAcceptHeaderLiteral = UpdateBestMatch(bestMatchOnAcceptHeaderLiteral, match);
|
|
// break;
|
|
|
|
// case MediaTypeFormatterMatchRanking.MatchOnRequestAcceptHeaderSubtypeMediaRange:
|
|
// // Matches on accept headers must choose the highest quality match.
|
|
// // A match of 0.0 means we won't use it at all.
|
|
// bestMatchOnAcceptHeaderSubtypeMediaRange = UpdateBestMatch(bestMatchOnAcceptHeaderSubtypeMediaRange, match);
|
|
// break;
|
|
|
|
// case MediaTypeFormatterMatchRanking.MatchOnRequestAcceptHeaderAllMediaRange:
|
|
// // Matches on accept headers must choose the highest quality match.
|
|
// // A match of 0.0 means we won't use it at all.
|
|
// bestMatchOnAcceptHeaderAllMediaRange = UpdateBestMatch(bestMatchOnAcceptHeaderAllMediaRange, match);
|
|
// break;
|
|
|
|
// case MediaTypeFormatterMatchRanking.MatchOnRequestMediaType:
|
|
// // First match on request content type trumps other request content matches
|
|
// if (bestMatchOnRequestMediaType == null)
|
|
// {
|
|
// bestMatchOnRequestMediaType = match;
|
|
// }
|
|
// break;
|
|
// }
|
|
// }
|
|
|
|
// // If we received matches based on both supported media types and from media type mappings,
|
|
// // we want to give precedence to the media type mappings, but only if their quality is >= that of the supported media type.
|
|
// // We do this because media type mappings are the user's extensibility point and must take precedence over normal
|
|
// // supported media types in the case of a tie. The 99% case is where both have quality 1.0.
|
|
// if (bestMatchOnMediaTypeMapping != null)
|
|
// {
|
|
// MediaTypeFormatterMatch mappingOverride = bestMatchOnMediaTypeMapping;
|
|
// mappingOverride = UpdateBestMatch(mappingOverride, bestMatchOnAcceptHeaderLiteral);
|
|
// mappingOverride = UpdateBestMatch(mappingOverride, bestMatchOnAcceptHeaderSubtypeMediaRange);
|
|
// mappingOverride = UpdateBestMatch(mappingOverride, bestMatchOnAcceptHeaderAllMediaRange);
|
|
// if (mappingOverride != bestMatchOnMediaTypeMapping)
|
|
// {
|
|
// bestMatchOnMediaTypeMapping = null;
|
|
// }
|
|
// }
|
|
|
|
// // now select the formatter and media type
|
|
// // A MediaTypeMapping is highest precedence -- it is an extensibility point
|
|
// // allowing the user to override normal accept header matching
|
|
// MediaTypeFormatterMatch bestMatch = null;
|
|
// if (bestMatchOnMediaTypeMapping != null)
|
|
// {
|
|
// bestMatch = bestMatchOnMediaTypeMapping;
|
|
// }
|
|
// else if (bestMatchOnAcceptHeaderLiteral != null ||
|
|
// bestMatchOnAcceptHeaderSubtypeMediaRange != null ||
|
|
// bestMatchOnAcceptHeaderAllMediaRange != null)
|
|
// {
|
|
// bestMatch = UpdateBestMatch(bestMatch, bestMatchOnAcceptHeaderLiteral);
|
|
// bestMatch = UpdateBestMatch(bestMatch, bestMatchOnAcceptHeaderSubtypeMediaRange);
|
|
// bestMatch = UpdateBestMatch(bestMatch, bestMatchOnAcceptHeaderAllMediaRange);
|
|
// }
|
|
// else if (bestMatchOnRequestMediaType != null)
|
|
// {
|
|
// bestMatch = bestMatchOnRequestMediaType;
|
|
// }
|
|
// else if (bestMatchOnType != null)
|
|
// {
|
|
// bestMatch = bestMatchOnType;
|
|
// }
|
|
|
|
// return bestMatch;
|
|
// }
|
|
|
|
// /// <summary>
|
|
// /// Determine the best character encoding for writing the response. First we look
|
|
// /// for accept-charset headers and if not found then we try to match
|
|
// /// any charset encoding in the request (in case of PUT, POST, etc.)
|
|
// /// If no encoding is found then we use the default for the formatter.
|
|
// /// </summary>
|
|
// /// <returns>The <see cref="Encoding"/> determined to be the best match.</returns>
|
|
// protected virtual Encoding SelectResponseCharacterEncoding(IOwinRequest request, MediaTypeFormatter formatter)
|
|
// {
|
|
// if (request == null)
|
|
// {
|
|
// throw new ArgumentNullException("request");
|
|
// }
|
|
// if (formatter == null)
|
|
// {
|
|
// throw new ArgumentNullException("formatter");
|
|
// }
|
|
|
|
// // If there are any SupportedEncodings then we pick an encoding
|
|
// List<Encoding> supportedEncodings = formatter.SupportedEncodingsInternal;
|
|
// if (supportedEncodings.Count > 0)
|
|
// {
|
|
// // Sort Accept-Charset header values
|
|
// IEnumerable<StringWithQualityHeaderValue> sortedAcceptCharsetValues = SortStringWithQualityHeaderValuesByQFactor(request.Headers.AcceptCharset);
|
|
|
|
// // Check for match based on accept-charset headers
|
|
// foreach (StringWithQualityHeaderValue acceptCharset in sortedAcceptCharsetValues)
|
|
// {
|
|
// for (int i = 0; i < supportedEncodings.Count; i++)
|
|
// {
|
|
// Encoding encoding = supportedEncodings[i];
|
|
// if (encoding != null && acceptCharset.Quality != FormattingUtilities.NoMatch &&
|
|
// (acceptCharset.Value.Equals(encoding.WebName, StringComparison.OrdinalIgnoreCase) ||
|
|
// acceptCharset.Value.Equals("*", StringComparison.OrdinalIgnoreCase)))
|
|
// {
|
|
// return encoding;
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
// // Check for match based on any request entity body
|
|
|
|
// // TODO: Transform to use request content headers directly
|
|
// // was - request.Content != null ? request.Content.Headers : null
|
|
// return formatter.SelectCharacterEncoding(null);
|
|
// }
|
|
|
|
// return null;
|
|
// }
|
|
|
|
// /// <summary>
|
|
// /// Match a request against the <see cref="MediaTypeMapping"/>s registered with the formatter.
|
|
// /// </summary>
|
|
// /// <param name="request">The request to match.</param>
|
|
// /// <param name="formatter">The formatter to match against.</param>
|
|
// /// <returns>A <see cref="MediaTypeFormatterMatch"/> indicating the quality of the match or null is no match.</returns>
|
|
// protected virtual MediaTypeFormatterMatch MatchMediaTypeMapping(IOwinRequest request, MediaTypeFormatter formatter)
|
|
// {
|
|
// if (request == null)
|
|
// {
|
|
// throw new ArgumentNullException("request");
|
|
// }
|
|
// if (formatter == null)
|
|
// {
|
|
// throw new ArgumentNullException("formatter");
|
|
// }
|
|
|
|
// List<MediaTypeMapping> mediaTypeMappings = formatter.MediaTypeMappingsInternal;
|
|
// for (int i = 0; i < mediaTypeMappings.Count; i++)
|
|
// {
|
|
// MediaTypeMapping mapping = mediaTypeMappings[i];
|
|
// double quality;
|
|
// if (mapping != null && ((quality = mapping.TryMatchMediaType(request)) > FormattingUtilities.NoMatch))
|
|
// {
|
|
// return new MediaTypeFormatterMatch(formatter, mapping.MediaType, quality, MediaTypeFormatterMatchRanking.MatchOnRequestWithMediaTypeMapping);
|
|
// }
|
|
// }
|
|
|
|
// return null;
|
|
// }
|
|
|
|
// /// <summary>
|
|
// /// Match the request accept header field values against the formatter's registered supported media types.
|
|
// /// </summary>
|
|
// /// <param name="sortedAcceptValues">The sorted accept header values to match.</param>
|
|
// /// <param name="formatter">The formatter to match against.</param>
|
|
// /// <returns>A <see cref="MediaTypeFormatterMatch"/> indicating the quality of the match or null is no match.</returns>
|
|
// protected virtual MediaTypeFormatterMatch MatchAcceptHeader(IEnumerable<MediaTypeWithQualityHeaderValue> sortedAcceptValues, MediaTypeFormatter formatter)
|
|
// {
|
|
// if (sortedAcceptValues == null)
|
|
// {
|
|
// throw Error.ArgumentNull("sortedAcceptValues");
|
|
// }
|
|
// if (formatter == null)
|
|
// {
|
|
// throw Error.ArgumentNull("formatter");
|
|
// }
|
|
|
|
// foreach (MediaTypeWithQualityHeaderValue acceptMediaTypeValue in sortedAcceptValues)
|
|
// {
|
|
// List<MediaTypeHeaderValue> supportedMediaTypes = formatter.SupportedMediaTypesInternal;
|
|
// for (int i = 0; i < supportedMediaTypes.Count; i++)
|
|
// {
|
|
// MediaTypeHeaderValue supportedMediaType = supportedMediaTypes[i];
|
|
// MediaTypeHeaderValueRange range;
|
|
// if (supportedMediaType != null && acceptMediaTypeValue.Quality != FormattingUtilities.NoMatch &&
|
|
// supportedMediaType.IsSubsetOf(acceptMediaTypeValue, out range))
|
|
// {
|
|
// MediaTypeFormatterMatchRanking ranking;
|
|
// switch (range)
|
|
// {
|
|
// case MediaTypeHeaderValueRange.AllMediaRange:
|
|
// ranking = MediaTypeFormatterMatchRanking.MatchOnRequestAcceptHeaderAllMediaRange;
|
|
// break;
|
|
|
|
// case MediaTypeHeaderValueRange.SubtypeMediaRange:
|
|
// ranking = MediaTypeFormatterMatchRanking.MatchOnRequestAcceptHeaderSubtypeMediaRange;
|
|
// break;
|
|
|
|
// default:
|
|
// ranking = MediaTypeFormatterMatchRanking.MatchOnRequestAcceptHeaderLiteral;
|
|
// break;
|
|
// }
|
|
|
|
// return new MediaTypeFormatterMatch(formatter, supportedMediaType, acceptMediaTypeValue.Quality, ranking);
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
// return null;
|
|
// }
|
|
|
|
// /// <summary>
|
|
// /// Match any request media type (in case there is a request entity body) against the formatter's registered
|
|
// /// media types.
|
|
// /// </summary>
|
|
// /// <param name="request">The request to match.</param>
|
|
// /// <param name="formatter">The formatter to match against.</param>
|
|
// /// <returns>A <see cref="MediaTypeFormatterMatch"/> indicating the quality of the match or null is no match.</returns>
|
|
// protected virtual MediaTypeFormatterMatch MatchRequestMediaType(IOwinRequest request, MediaTypeFormatter formatter)
|
|
// {
|
|
// if (request == null)
|
|
// {
|
|
// throw new ArgumentNullException("request");
|
|
// }
|
|
// if (formatter == null)
|
|
// {
|
|
// throw new ArgumentNullException("formatter");
|
|
// }
|
|
|
|
// if (request.Content != null)
|
|
// {
|
|
// MediaTypeHeaderValue requestMediaType = request.Content.Headers.ContentType;
|
|
// if (requestMediaType != null)
|
|
// {
|
|
// List<MediaTypeHeaderValue> supportedMediaTypes = formatter.SupportedMediaTypesInternal;
|
|
// for (int i = 0; i < supportedMediaTypes.Count; i++)
|
|
// {
|
|
// MediaTypeHeaderValue supportedMediaType = supportedMediaTypes[i];
|
|
// if (supportedMediaType != null && supportedMediaType.IsSubsetOf(requestMediaType))
|
|
// {
|
|
// return new MediaTypeFormatterMatch(formatter, supportedMediaType, FormattingUtilities.Match, MediaTypeFormatterMatchRanking.MatchOnRequestMediaType);
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
// return null;
|
|
// }
|
|
|
|
// /// <summary>
|
|
// /// Determine whether to match on type or not. This is used to determine whether to
|
|
// /// generate a 406 response or use the default media type formatter in case there
|
|
// /// is no match against anything in the request. If ExcludeMatchOnTypeOnly is true
|
|
// /// then we don't match on type unless there are no accept headers.
|
|
// /// </summary>
|
|
// /// <param name="sortedAcceptValues">The sorted accept header values to match.</param>
|
|
// /// <returns>True if not ExcludeMatchOnTypeOnly and accept headers with a q-factor bigger than 0.0 are present.</returns>
|
|
// protected virtual bool ShouldMatchOnType(IEnumerable<MediaTypeWithQualityHeaderValue> sortedAcceptValues)
|
|
// {
|
|
// if (sortedAcceptValues == null)
|
|
// {
|
|
// throw new ArgumentNullException("sortedAcceptValues");
|
|
// }
|
|
|
|
// return !(ExcludeMatchOnTypeOnly && sortedAcceptValues.Any());
|
|
// }
|
|
|
|
// /// <summary>
|
|
// /// Pick the first supported media type and indicate we've matched only on type
|
|
// /// </summary>
|
|
// /// <param name="type">The type to be serialized.</param>
|
|
// /// <param name="formatter">The formatter we are matching against.</param>
|
|
// /// <returns>A <see cref="MediaTypeFormatterMatch"/> indicating the quality of the match or null is no match.</returns>
|
|
// protected virtual MediaTypeFormatterMatch MatchType(Type type, MediaTypeFormatter formatter)
|
|
// {
|
|
// // Performance-sensitive
|
|
// if (type == null)
|
|
// {
|
|
// throw new ArgumentNullException("type");
|
|
// }
|
|
// if (formatter == null)
|
|
// {
|
|
// throw new ArgumentNullException("formatter");
|
|
// }
|
|
|
|
// // We already know that we do match on type -- otherwise we wouldn't even be called --
|
|
// // so this is just a matter of determining how we match.
|
|
// MediaTypeHeaderValue mediaType = null;
|
|
// List<MediaTypeHeaderValue> supportedMediaTypes = formatter.SupportedMediaTypesInternal;
|
|
// if (supportedMediaTypes.Count > 0)
|
|
// {
|
|
// mediaType = supportedMediaTypes[0];
|
|
// }
|
|
// return new MediaTypeFormatterMatch(formatter, mediaType, FormattingUtilities.Match, MediaTypeFormatterMatchRanking.MatchOnCanWriteType);
|
|
// }
|
|
|
|
// /// <summary>
|
|
// /// Sort Accept header values and related header field values with similar syntax rules
|
|
// /// (if more than 1) in descending order based on q-factor.
|
|
// /// </summary>
|
|
// /// <param name="headerValues">The header values to sort.</param>
|
|
// /// <returns>The sorted header values.</returns>
|
|
// protected virtual IEnumerable<MediaTypeWithQualityHeaderValue> SortMediaTypeWithQualityHeaderValuesByQFactor(ICollection<MediaTypeWithQualityHeaderValue> headerValues)
|
|
// {
|
|
// if (headerValues == null)
|
|
// {
|
|
// throw new ArgumentNullException("headerValues");
|
|
// }
|
|
|
|
// if (headerValues.Count > 1)
|
|
// {
|
|
// // Use OrderBy() instead of Array.Sort() as it performs fewer comparisons. In this case the comparisons
|
|
// // are quite expensive so OrderBy() performs better.
|
|
// return headerValues.OrderByDescending(m => m, MediaTypeWithQualityHeaderValueComparer.QualityComparer).ToArray();
|
|
// }
|
|
// else
|
|
// {
|
|
// return headerValues;
|
|
// }
|
|
// }
|
|
|
|
// /// <summary>
|
|
// /// Sort Accept-Charset, Accept-Encoding, Accept-Language and related header field values with similar syntax rules
|
|
// /// (if more than 1) in descending order based on q-factor.
|
|
// /// </summary>
|
|
// /// <param name="headerValues">The header values to sort.</param>
|
|
// /// <returns>The sorted header values.</returns>
|
|
// protected virtual IEnumerable<StringWithQualityHeaderValue> SortStringWithQualityHeaderValuesByQFactor(ICollection<StringWithQualityHeaderValue> headerValues)
|
|
// {
|
|
// if (headerValues == null)
|
|
// {
|
|
// throw new ArgumentNullException("headerValues");
|
|
// }
|
|
|
|
// if (headerValues.Count > 1)
|
|
// {
|
|
// // Use OrderBy() instead of Array.Sort() as it performs fewer comparisons. In this case the comparisons
|
|
// // are quite expensive so OrderBy() performs better.
|
|
// return headerValues.OrderByDescending(m => m, StringWithQualityHeaderValueComparer.QualityComparer).ToArray();
|
|
// }
|
|
// else
|
|
// {
|
|
// return headerValues;
|
|
// }
|
|
// }
|
|
|
|
// /// <summary>
|
|
// /// Evaluates whether a match is better than the current match and if so returns the replacement; otherwise returns the
|
|
// /// current match.
|
|
// /// </summary>
|
|
// protected virtual MediaTypeFormatterMatch UpdateBestMatch(MediaTypeFormatterMatch current, MediaTypeFormatterMatch potentialReplacement)
|
|
// {
|
|
// if (potentialReplacement == null)
|
|
// {
|
|
// return current;
|
|
// }
|
|
|
|
// if (current != null)
|
|
// {
|
|
// return (potentialReplacement.Quality > current.Quality) ? potentialReplacement : current;
|
|
// }
|
|
|
|
// return potentialReplacement;
|
|
// }
|
|
|
|
// private static MediaTypeFormatter[] GetWritingFormatters(IEnumerable<MediaTypeFormatter> formatters)
|
|
// {
|
|
// Contract.Assert(formatters != null);
|
|
// MediaTypeFormatterCollection formatterCollection = formatters as MediaTypeFormatterCollection;
|
|
// if (formatterCollection != null)
|
|
// {
|
|
// return formatterCollection.WritingFormatters;
|
|
// }
|
|
// return formatters.AsArray();
|
|
// }
|
|
|
|
public ContentNegotiationResult Negotiate(Type type, IOwinContext context, IEnumerable<MediaTypeFormatter> formatters)
|
|
{
|
|
return new ContentNegotiationResult(formatters.First(), formatters.First().SupportedMediaTypes.First());
|
|
}
|
|
}
|
|
}
|