From bab520f4dd358dfd6fa22c727670a7a06a8b25f9 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Tue, 22 Nov 2016 14:29:56 -0800 Subject: [PATCH] Use latest `Microsoft.AspNet.WebApi.Client` package - #5822 - update `Microsoft.AspNet.WebApi.Client` package version - remove remaining few `$(PackageTargetFallback)` settings - remove .NET Standard-specific files - they duplicate what Microsoft.AspNet.WebApi.Client now provides - necessary only if cross-compiling a PCL version of the WebApiCompatShim - add type forwarding for the removed `public` types - reenable .NET Framework WebApiCompatShim tests - add breaking change record for `MediaTypeFormatterMatchRanking` value change - version of this type in the shim lacked the `MatchOnRequestWithMediaTypeMapping` value --- build/dependencies.props | 2 +- .../ContentNegotiator/CollectionExtensions.cs | 293 --------- .../ContentNegotiationResult.cs | 50 -- .../DefaultContentNegotiator.cs | 585 ------------------ .../ContentNegotiator/FormDataCollection.cs | 40 -- .../ContentNegotiator/FormattingUtilities.cs | 236 ------- .../ContentNegotiator/IContentNegotiator.cs | 37 -- .../ListWrapperCollection.cs | 31 - .../ContentNegotiator/MediaTypeConstants.cs | 109 ---- .../MediaTypeFormatterMatch.cs | 57 -- .../MediaTypeFormatterMatchRanking.cs | 45 -- .../MediaTypeHeaderValueExtensions.cs | 117 ---- .../MediaTypeWithQualityHeaderComparer.cs | 116 ---- .../ParsedMediaTypeHeaderValue.cs | 88 --- .../StringWithQualityHeaderValueComparer.cs | 75 --- ...oft.AspNetCore.Mvc.WebApiCompatShim.csproj | 3 - .../Properties/AssemblyInfo.cs | 11 + .../breakingchanges.netcore.json | 7 + ...soft.AspNetCore.Mvc.FunctionalTests.csproj | 3 - .../WebApiCompatShimBasicTest.cs | 4 - ...AspNetCore.Mvc.WebApiCompatShimTest.csproj | 9 +- .../WebApiCompatShimWebSite.csproj | 2 - 22 files changed, 21 insertions(+), 1899 deletions(-) delete mode 100644 src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/CollectionExtensions.cs delete mode 100644 src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/ContentNegotiationResult.cs delete mode 100644 src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/DefaultContentNegotiator.cs delete mode 100644 src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/FormDataCollection.cs delete mode 100644 src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/FormattingUtilities.cs delete mode 100644 src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/IContentNegotiator.cs delete mode 100644 src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/ListWrapperCollection.cs delete mode 100644 src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/MediaTypeConstants.cs delete mode 100644 src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/MediaTypeFormatterMatch.cs delete mode 100644 src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/MediaTypeFormatterMatchRanking.cs delete mode 100644 src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/MediaTypeHeaderValueExtensions.cs delete mode 100644 src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/MediaTypeWithQualityHeaderComparer.cs delete mode 100644 src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/ParsedMediaTypeHeaderValue.cs delete mode 100644 src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/StringWithQualityHeaderValueComparer.cs create mode 100644 src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/Properties/AssemblyInfo.cs create mode 100644 src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/breakingchanges.netcore.json diff --git a/build/dependencies.props b/build/dependencies.props index 06095e77c8..9d67ef017e 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -40,7 +40,7 @@ 2.1.0-preview1-27965 2.1.0-preview1-27965 2.1.0-preview1-27965 - 5.2.2 + 5.2.4-preview1 2.3.1 2.1.0-preview1-27965 2.1.0-preview1-27965 diff --git a/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/CollectionExtensions.cs b/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/CollectionExtensions.cs deleted file mode 100644 index 95cf8c22a1..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/CollectionExtensions.cs +++ /dev/null @@ -1,293 +0,0 @@ -// 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.Collections.ObjectModel; -using System.Diagnostics; -using System.Linq; - -namespace System.Collections.Generic -{ - /// - /// Helper extension methods for fast use of collections. - /// - internal static class CollectionExtensions - { - /// - /// Return a new array with the value added to the end. Slow and best suited to long lived arrays with few - /// writes relative to reads. - /// - public static T[] AppendAndReallocate(this T[] array, T value) - { - Debug.Assert(array != null); - - var originalLength = array.Length; - var newArray = new T[originalLength + 1]; - array.CopyTo(newArray, 0); - newArray[originalLength] = value; - return newArray; - } - - /// - /// Return the enumerable as an Array, copying if required. Optimized for common case where it is an Array. - /// Avoid mutating the return value. - /// - public static T[] AsArray(this IEnumerable values) - { - Debug.Assert(values != null); - - var array = values as T[]; - if (array == null) - { - array = values.ToArray(); - } - return array; - } - - /// - /// Return the enumerable as a Collection of T, copying if required. Optimized for the common case where it is - /// a Collection of T and avoiding a copy if it implements IList of T. Avoid mutating the return value. - /// - public static Collection AsCollection(this IEnumerable enumerable) - { - Debug.Assert(enumerable != null); - - var collection = enumerable as Collection; - if (collection != null) - { - return collection; - } - // Check for IList so that collection can wrap it instead of copying - var list = enumerable as IList; - if (list == null) - { - list = new List(enumerable); - } - return new Collection(list); - } - - /// - /// Return the enumerable as a IList of T, copying if required. Avoid mutating the return value. - /// - public static IList AsIList(this IEnumerable enumerable) - { - Debug.Assert(enumerable != null); - - var list = enumerable as IList; - if (list != null) - { - return list; - } - return new List(enumerable); - } - - /// - /// Return the enumerable as a List of T, copying if required. Optimized for common case where it is an List of - /// T or a ListWrapperCollection of T. Avoid mutating the return value. - /// - public static List AsList(this IEnumerable enumerable) - { - Debug.Assert(enumerable != null); - - List list = enumerable as List; - if (list != null) - { - return list; - } - ListWrapperCollection listWrapper = enumerable as ListWrapperCollection; - if (listWrapper != null) - { - return listWrapper.ItemsList; - } - return new List(enumerable); - } - - /// - /// Remove values from the list starting at the index start. - /// - public static void RemoveFrom(this List list, int start) - { - Debug.Assert(list != null); - Debug.Assert(start >= 0 && start <= list.Count); - - list.RemoveRange(start, list.Count - start); - } - - /// - /// Return the only value from list, the type's default value if empty, or call the errorAction for 2 or more. - /// - public static T SingleDefaultOrError(this IList list, Action errorAction, TArg1 errorArg1) - { - Debug.Assert(list != null); - Debug.Assert(errorAction != null); - - switch (list.Count) - { - case 0: - return default(T); - - case 1: - var value = list[0]; - return value; - - default: - errorAction(errorArg1); - return default(T); - } - } - - /// - /// Returns a single value in list matching type TMatch if there is only one, null if there are none of type - /// TMatch or calls the errorAction with errorArg1 if there is more than one. - /// - public static TMatch SingleOfTypeDefaultOrError( - this IList list, - Action errorAction, - TArg1 errorArg1) where TMatch : class - { - Debug.Assert(list != null); - Debug.Assert(errorAction != null); - - TMatch result = null; - for (var i = 0; i < list.Count; i++) - { - var typedValue = list[i] as TMatch; - if (typedValue != null) - { - if (result == null) - { - result = typedValue; - } - else - { - errorAction(errorArg1); - return null; - } - } - } - return result; - } - - /// - /// Convert an ICollection to an array, removing null values. Fast path for case where there are no null - /// values. - /// - public static T[] ToArrayWithoutNulls(this ICollection collection) where T : class - { - Debug.Assert(collection != null); - - var result = new T[collection.Count]; - var count = 0; - foreach (var value in collection) - { - if (value != null) - { - result[count] = value; - count++; - } - } - if (count == collection.Count) - { - return result; - } - else - { - var trimmedResult = new T[count]; - Array.Copy(result, trimmedResult, count); - return trimmedResult; - } - } - - /// - /// Convert the array to a Dictionary using the keySelector to extract keys from values and the specified - /// comparer. Optimized for array input. - /// - public static Dictionary ToDictionaryFast( - this TValue[] array, - Func keySelector, - IEqualityComparer comparer) - { - Debug.Assert(array != null); - Debug.Assert(keySelector != null); - - var dictionary = new Dictionary(array.Length, comparer); - for (var i = 0; i < array.Length; i++) - { - var value = array[i]; - dictionary.Add(keySelector(value), value); - } - return dictionary; - } - - /// - /// Convert the list to a Dictionary using the keySelector to extract keys from values and the specified - /// comparer. Optimized for IList of T input with fast path for array. - /// - public static Dictionary ToDictionaryFast( - this IList list, - Func keySelector, - IEqualityComparer comparer) - { - Debug.Assert(list != null); - Debug.Assert(keySelector != null); - - var array = list as TValue[]; - if (array != null) - { - return ToDictionaryFast(array, keySelector, comparer); - } - return ToDictionaryFastNoCheck(list, keySelector, comparer); - } - - /// - /// Convert the enumerable to a Dictionary using the keySelector to extract keys from values and the specified - /// comparer. Fast paths for array and IList of T. - /// - public static Dictionary ToDictionaryFast( - this IEnumerable enumerable, - Func keySelector, - IEqualityComparer comparer) - { - Debug.Assert(enumerable != null); - Debug.Assert(keySelector != null); - - var array = enumerable as TValue[]; - if (array != null) - { - return ToDictionaryFast(array, keySelector, comparer); - } - var list = enumerable as IList; - if (list != null) - { - return ToDictionaryFastNoCheck(list, keySelector, comparer); - } - var dictionary = new Dictionary(comparer); - foreach (var value in enumerable) - { - dictionary.Add(keySelector(value), value); - } - return dictionary; - } - - /// - /// Convert the list to a Dictionary using the keySelector to extract keys from values and the specified - /// comparer. Optimized for IList of T input. No checking for other types. - /// - private static Dictionary ToDictionaryFastNoCheck( - IList list, - Func keySelector, - IEqualityComparer comparer) - { - Debug.Assert(list != null); - Debug.Assert(keySelector != null); - - var listCount = list.Count; - var dictionary = new Dictionary(listCount, comparer); - for (var i = 0; i < listCount; i++) - { - var value = list[i]; - dictionary.Add(keySelector(value), value); - } - return dictionary; - } - } -} diff --git a/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/ContentNegotiationResult.cs b/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/ContentNegotiationResult.cs deleted file mode 100644 index 9ba9c47f07..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/ContentNegotiationResult.cs +++ /dev/null @@ -1,50 +0,0 @@ -// 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.Collections.Generic; -using System.Net.Http.Headers; - -namespace System.Net.Http.Formatting -{ - /// - /// Represents the result of content negotiation performed using - /// - /// - public class ContentNegotiationResult - { - private MediaTypeFormatter _formatter; - - /// - /// Create the content negotiation result object. - /// - /// The formatter. - /// The preferred media type. Can be null. - public ContentNegotiationResult(MediaTypeFormatter formatter, MediaTypeHeaderValue mediaType) - { - if (formatter == null) - { - throw new ArgumentNullException(nameof(formatter)); - } - - _formatter = formatter; - MediaType = mediaType; - } - - /// - /// The formatter chosen for serialization. - /// - public MediaTypeFormatter Formatter - { - get { return _formatter; } - set - { - _formatter = value; - } - } - - /// - /// The media type that is associated with the formatter chosen for serialization. Can be null. - /// - public MediaTypeHeaderValue MediaType { get; set; } - } -} diff --git a/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/DefaultContentNegotiator.cs b/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/DefaultContentNegotiator.cs deleted file mode 100644 index b046f2e989..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/DefaultContentNegotiator.cs +++ /dev/null @@ -1,585 +0,0 @@ -// 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.Collections.Generic; -using System.Collections.ObjectModel; -using System.Diagnostics; -using System.Linq; -using System.Net.Http.Headers; -using System.Text; - -namespace System.Net.Http.Formatting -{ - /// - /// Class that selects a for an - /// or . - /// - public class DefaultContentNegotiator : IContentNegotiator - { - public DefaultContentNegotiator() - : this(false) - { - } - - /// - /// Initializes a new instance of the with - /// the given setting for . - /// - /// - /// 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. - /// - public DefaultContentNegotiator(bool excludeMatchOnTypeOnly) - { - ExcludeMatchOnTypeOnly = 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. - /// - public bool ExcludeMatchOnTypeOnly { get; private set; } - - /// - /// Performs content negotiating by selecting the most appropriate out of the - /// passed in for the given that can serialize an - /// object of the given . - /// - /// The type to be serialized. - /// The request. - /// The set of objects from which to choose. - /// The result of the negotiation containing the most appropriate - /// instance, or null if there is no appropriate formatter. - public virtual ContentNegotiationResult Negotiate( - Type type, - HttpRequestMessage request, - IEnumerable formatters) - { - if (type == null) - { - throw new ArgumentNullException(nameof(type)); - } - - if (request == null) - { - throw new ArgumentNullException(nameof(request)); - } - - if (formatters == null) - { - throw new ArgumentNullException(nameof(formatters)); - } - - // Go through each formatter to compute how well it matches. - var matches = ComputeFormatterMatches(type, request, formatters); - - // Select best formatter match among the matches - var bestFormatterMatch = SelectResponseMediaTypeFormatter(matches); - - // We found a best formatter - if (bestFormatterMatch != null) - { - var bestMediaType = bestFormatterMatch.MediaType; - - // Find the best character encoding for the selected formatter. - var bestEncodingMatch = SelectResponseCharacterEncoding(request, bestFormatterMatch.Formatter); - if (bestEncodingMatch != null) - { - // Clone media type value since this is not done defensively in this implementation. - // `MediaTypeHeaderValue` lacks a Clone() method in this runtime. Fortunately, this is the only - // update to an existing instance we need. - var clonedMediaType = new MediaTypeHeaderValue(bestMediaType.MediaType); - foreach (var parameter in bestMediaType.Parameters) - { - clonedMediaType.Parameters.Add(new NameValueHeaderValue(parameter.Name, parameter.Value)); - } - - bestMediaType = clonedMediaType; - bestMediaType.CharSet = bestEncodingMatch.WebName; - } - - var bestFormatter = - bestFormatterMatch.Formatter.GetPerRequestFormatterInstance(type, request, bestMediaType); - return new ContentNegotiationResult(bestFormatter, bestMediaType); - } - - return null; - } - - /// - /// Determine how well each formatter matches by associating a - /// 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. - /// - /// The type to be serialized. - /// The request. - /// The set of objects from which to choose. - /// A collection containing all the matches. - protected virtual Collection ComputeFormatterMatches( - Type type, - HttpRequestMessage request, - IEnumerable formatters) - { - if (type == null) - { - throw new ArgumentNullException(nameof(type)); - } - - if (request == null) - { - throw new ArgumentNullException(nameof(request)); - } - - if (formatters == null) - { - throw new ArgumentNullException(nameof(formatters)); - } - - IEnumerable sortedAcceptValues = null; - - // Go through each formatter to find how well it matches. - var matches = - new ListWrapperCollection(); - var writingFormatters = GetWritingFormatters(formatters); - for (var i = 0; i < writingFormatters.Length; i++) - { - var formatter = writingFormatters[i]; - - // 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 the accept header values. - if (sortedAcceptValues == null) - { - // Sort the Accept header values in descending order based on q-factor - sortedAcceptValues = SortMediaTypeWithQualityHeaderValuesByQFactor(request.Headers.Accept); - } - - var match = MatchAcceptHeader(sortedAcceptValues, formatter); - if (match != 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. - var 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; - } - - /// - /// Select the best match among the candidate matches found. - /// - /// The collection of matches. - /// The determined to be the best match. - protected virtual MediaTypeFormatterMatch SelectResponseMediaTypeFormatter( - ICollection matches) - { - if (matches == null) - { - throw new ArgumentNullException(nameof(matches)); - } - - // Performance-sensitive - - var 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 (var i = 0; i < matchList.Count; i++) - { - var 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.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) - { - var 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; - } - - /// - /// 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. - /// - /// The determined to be the best match. - protected virtual Encoding SelectResponseCharacterEncoding( - HttpRequestMessage request, - MediaTypeFormatter formatter) - { - if (request == null) - { - throw new ArgumentNullException(nameof(request)); - } - - if (formatter == null) - { - throw new ArgumentNullException(nameof(formatter)); - } - - // If there are any SupportedEncodings then we pick an encoding - var supportedEncodings = formatter.SupportedEncodings.ToList(); - if (supportedEncodings.Count > 0) - { - // Sort Accept-Charset header values - var sortedAcceptCharsetValues = - SortStringWithQualityHeaderValuesByQFactor(request.Headers.AcceptCharset); - - // Check for match based on accept-charset headers - foreach (StringWithQualityHeaderValue acceptCharset in sortedAcceptCharsetValues) - { - for (var i = 0; i < supportedEncodings.Count; i++) - { - var encoding = supportedEncodings[i]; - if (encoding != null && acceptCharset.Quality != FormattingUtilities.NoMatch && - (acceptCharset.Value.Equals(encoding.WebName, StringComparison.OrdinalIgnoreCase) || - acceptCharset.Value.Equals("*", StringComparison.Ordinal))) - { - return encoding; - } - } - } - - // Check for match based on any request entity body - return formatter.SelectCharacterEncoding(request.Content != null ? request.Content.Headers : null); - } - - return null; - } - - /// - /// Match the request accept header field values against the formatter's registered supported media types. - /// - /// The sorted accept header values to match. - /// The formatter to match against. - /// - /// A indicating the quality of the match or null is no match. - /// - protected virtual MediaTypeFormatterMatch MatchAcceptHeader( - IEnumerable sortedAcceptValues, - MediaTypeFormatter formatter) - { - if (sortedAcceptValues == null) - { - throw new ArgumentNullException(nameof(sortedAcceptValues)); - } - - if (formatter == null) - { - throw new ArgumentNullException(nameof(formatter)); - } - - foreach (MediaTypeWithQualityHeaderValue acceptMediaTypeValue in sortedAcceptValues) - { - var supportedMediaTypes = formatter.SupportedMediaTypes.ToList(); - for (var i = 0; i < supportedMediaTypes.Count; i++) - { - var supportedMediaType = supportedMediaTypes[i]; - MediaTypeFormatterMatchRanking ranking; - if (supportedMediaType != null && - acceptMediaTypeValue.Quality != FormattingUtilities.NoMatch && - supportedMediaType.IsSubsetOf(acceptMediaTypeValue, out ranking)) - { - return new MediaTypeFormatterMatch( - formatter, - supportedMediaType, - acceptMediaTypeValue.Quality, - ranking); - } - } - } - - return null; - } - - /// - /// Match any request media type (in case there is a request entity body) against the formatter's registered - /// media types. - /// - /// The request to match. - /// The formatter to match against. - /// - /// A indicating the quality of the match or null is no match. - /// - protected virtual MediaTypeFormatterMatch MatchRequestMediaType( - HttpRequestMessage request, - MediaTypeFormatter formatter) - { - if (request == null) - { - throw new ArgumentNullException(nameof(request)); - } - - if (formatter == null) - { - throw new ArgumentNullException(nameof(formatter)); - } - - if (request.Content != null) - { - var requestMediaType = request.Content.Headers.ContentType; - if (requestMediaType != null) - { - var supportedMediaTypes = formatter.SupportedMediaTypes.ToList(); - for (var i = 0; i < supportedMediaTypes.Count; i++) - { - var supportedMediaType = supportedMediaTypes[i]; - if (supportedMediaType != null && supportedMediaType.IsSubsetOf(requestMediaType)) - { - return new MediaTypeFormatterMatch( - formatter, - supportedMediaType, - FormattingUtilities.Match, - MediaTypeFormatterMatchRanking.MatchOnRequestMediaType); - } - } - } - } - - return null; - } - - /// - /// 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. - /// - /// The sorted accept header values to match. - /// - /// True if not ExcludeMatchOnTypeOnly and accept headers with a q-factor bigger than 0.0 are present. - /// - protected virtual bool ShouldMatchOnType( - IEnumerable sortedAcceptValues) - { - if (sortedAcceptValues == null) - { - throw new ArgumentNullException(nameof(sortedAcceptValues)); - } - - return !(ExcludeMatchOnTypeOnly && sortedAcceptValues.Any()); - } - - /// - /// Pick the first supported media type and indicate we've matched only on type - /// - /// The type to be serialized. - /// The formatter we are matching against. - /// - /// A indicating the quality of the match or null is no match. - /// - protected virtual MediaTypeFormatterMatch MatchType( - Type type, - MediaTypeFormatter formatter) - { - if (type == null) - { - throw new ArgumentNullException(nameof(type)); - } - - if (formatter == null) - { - throw new ArgumentNullException(nameof(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; - var supportedMediaTypes = formatter.SupportedMediaTypes.ToList(); - if (supportedMediaTypes.Count > 0) - { - mediaType = supportedMediaTypes[0]; - } - return new MediaTypeFormatterMatch( - formatter, - mediaType, - FormattingUtilities.Match, - MediaTypeFormatterMatchRanking.MatchOnCanWriteType); - } - - /// - /// Sort Accept header values and related header field values with similar syntax rules - /// (if more than 1) in descending order based on q-factor. - /// - /// The header values to sort. - /// The sorted header values. - protected virtual IEnumerable SortMediaTypeWithQualityHeaderValuesByQFactor( - ICollection 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; - } - } - - /// - /// 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. - /// - /// The header values to sort. - /// The sorted header values. - protected virtual IEnumerable SortStringWithQualityHeaderValuesByQFactor( - ICollection headerValues) - { - if (headerValues == null) - { - throw new ArgumentNullException(nameof(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; - } - } - - /// - /// Evaluates whether a match is better than the current match and if so returns the replacement; otherwise - /// returns the current match. - /// - 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 formatters) - { - Debug.Assert(formatters != null); - return formatters.AsArray(); - } - } -} diff --git a/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/FormDataCollection.cs b/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/FormDataCollection.cs deleted file mode 100644 index 2c3ef9bb51..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/FormDataCollection.cs +++ /dev/null @@ -1,40 +0,0 @@ -// 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.AspNetCore.WebUtilities; -using System.Collections; -using System.Collections.Generic; - -namespace System.Net.Http.Formatting -{ - public class FormDataCollection : IEnumerable> - { - private readonly IList> _values; - - public FormDataCollection(string query) - { - var parsedQuery = QueryHelpers.ParseQuery(query); - - var values = new List>(); - foreach (var kvp in parsedQuery) - { - foreach (var value in kvp.Value) - { - values.Add(new KeyValuePair(kvp.Key, value)); - } - } - - _values = values; - } - - public IEnumerator> GetEnumerator() - { - return _values.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return _values.GetEnumerator(); - } - } -} diff --git a/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/FormattingUtilities.cs b/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/FormattingUtilities.cs deleted file mode 100644 index 0a405f8803..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/FormattingUtilities.cs +++ /dev/null @@ -1,236 +0,0 @@ -// 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.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Net.Http.Formatting; -using System.Net.Http.Headers; -using System.Xml; -using Newtonsoft.Json.Linq; - -namespace System.Net.Http -{ - /// - /// Provides various internal utility functions - /// - internal static class FormattingUtilities - { - // Supported date formats for input. - private static readonly string[] dateFormats = new string[] - { - // "r", // RFC 1123, required output format but too strict for input - "ddd, d MMM yyyy H:m:s 'GMT'", // RFC 1123 (r, except it allows both 1 and 01 for date and time) - "ddd, d MMM yyyy H:m:s", // RFC 1123, no zone - assume GMT - "d MMM yyyy H:m:s 'GMT'", // RFC 1123, no day-of-week - "d MMM yyyy H:m:s", // RFC 1123, no day-of-week, no zone - "ddd, d MMM yy H:m:s 'GMT'", // RFC 1123, short year - "ddd, d MMM yy H:m:s", // RFC 1123, short year, no zone - "d MMM yy H:m:s 'GMT'", // RFC 1123, no day-of-week, short year - "d MMM yy H:m:s", // RFC 1123, no day-of-week, short year, no zone - - "dddd, d'-'MMM'-'yy H:m:s 'GMT'", // RFC 850 - "dddd, d'-'MMM'-'yy H:m:s", // RFC 850 no zone - "ddd MMM d H:m:s yyyy", // ANSI C's asctime() format - - "ddd, d MMM yyyy H:m:s zzz", // RFC 5322 - "ddd, d MMM yyyy H:m:s", // RFC 5322 no zone - "d MMM yyyy H:m:s zzz", // RFC 5322 no day-of-week - "d MMM yyyy H:m:s", // RFC 5322 no day-of-week, no zone - }; - - // Valid header token characters are within the range 0x20 < c < 0x7F excluding the following characters - private const string NonTokenChars = "()<>@,;:\\\"/[]?={}"; - - /// - /// Quality factor to indicate a perfect match. - /// - public const double Match = 1.0; - - /// - /// Quality factor to indicate no match. - /// - public const double NoMatch = 0.0; - - /// - /// The default max depth for our formatter is 256 - /// - public const int DefaultMaxDepth = 256; - - /// - /// The default min depth for our formatter is 1 - /// - public const int DefaultMinDepth = 1; - - /// - /// HTTP X-Requested-With header field name - /// - public const string HttpRequestedWithHeader = "x-requested-with"; - - /// - /// HTTP X-Requested-With header field value - /// - public const string HttpRequestedWithHeaderValue = "XMLHttpRequest"; - - /// - /// HTTP Host header field name - /// - public const string HttpHostHeader = "Host"; - - /// - /// HTTP Version token - /// - public const string HttpVersionToken = "HTTP"; - - /// - /// A representing . - /// - public static readonly Type HttpRequestMessageType = typeof(HttpRequestMessage); - - /// - /// A representing . - /// - public static readonly Type HttpResponseMessageType = typeof(HttpResponseMessage); - - /// - /// A representing . - /// - public static readonly Type HttpContentType = typeof(HttpContent); - - /// - /// A representing . - /// - public static readonly Type DelegatingEnumerableGenericType = typeof(DelegatingEnumerable<>); - - /// - /// A representing . - /// - public static readonly Type EnumerableInterfaceGenericType = typeof(IEnumerable<>); - - /// - /// A representing . - /// - public static readonly Type QueryableInterfaceGenericType = typeof(IQueryable<>); - - /// - /// Determines whether is a type. - /// - /// The type to test. - /// - /// true if is a type; otherwise, false. - /// - public static bool IsJTokenType(Type type) - { - return typeof(JToken).IsAssignableFrom(type); - } - - /// - /// Creates an empty instance. The only way is to get it from a dummy - /// instance. - /// - /// The created instance. - public static HttpContentHeaders CreateEmptyContentHeaders() - { - HttpContent tempContent = null; - HttpContentHeaders contentHeaders; - try - { - tempContent = new StringContent(string.Empty); - contentHeaders = tempContent.Headers; - contentHeaders.Clear(); - } - finally - { - // We can dispose the content without touching the headers - if (tempContent != null) - { - tempContent.Dispose(); - } - } - - return contentHeaders; - } - - /// - /// Create a default reader quotas with a default depth quota of 1K. - /// - /// A default with a default depth quota of 1K. - public static XmlDictionaryReaderQuotas CreateDefaultReaderQuotas() - { - // MaxDepth is a DOS mitigation. We don't support MaxDepth in portable libraries because it is strictly - // client side. - return new XmlDictionaryReaderQuotas() - { - MaxArrayLength = int.MaxValue, - MaxBytesPerRead = int.MaxValue, - MaxDepth = DefaultMaxDepth, - MaxNameTableCharCount = int.MaxValue, - MaxStringContentLength = int.MaxValue - }; - } - - /// - /// Remove bounding quotes on a token if present - /// - /// Token to unquote. - /// Unquoted token. - public static string UnquoteToken(string token) - { - if (string.IsNullOrEmpty(token)) - { - return token; - } - - if (token.StartsWith("\"", StringComparison.Ordinal) && - token.EndsWith("\"", StringComparison.Ordinal) && - token.Length > 1) - { - return token.Substring(1, token.Length - 2); - } - - return token; - } - - public static bool ValidateHeaderToken(string token) - { - if (token == null) - { - return false; - } - - foreach (char c in token) - { - if (c < 0x21 || c > 0x7E || NonTokenChars.IndexOf(c) != -1) - { - return false; - } - } - - return true; - } - - public static string DateToString(DateTimeOffset dateTime) - { - // Format according to RFC1123; 'r' uses invariant info (DateTimeFormatInfo.InvariantInfo) - return dateTime.ToUniversalTime().ToString("r", CultureInfo.InvariantCulture); - } - - public static bool TryParseDate(string input, out DateTimeOffset result) - { - return DateTimeOffset.TryParseExact(input, dateFormats, DateTimeFormatInfo.InvariantInfo, - DateTimeStyles.AllowWhiteSpaces | DateTimeStyles.AssumeUniversal, - out result); - } - - /// - /// Parses valid integer strings with no leading signs, whitespace or other - /// - /// The value to parse - /// The result - /// True if value was valid; false otherwise. - public static bool TryParseInt32(string value, out int result) - { - return int.TryParse(value, NumberStyles.None, NumberFormatInfo.InvariantInfo, out result); - } - } -} diff --git a/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/IContentNegotiator.cs b/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/IContentNegotiator.cs deleted file mode 100644 index e3ec7d6321..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/IContentNegotiator.cs +++ /dev/null @@ -1,37 +0,0 @@ -// 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.Collections.Generic; - -namespace System.Net.Http.Formatting -{ - /// - /// Performs content negotiation. - /// This is the process of selecting a response writer (formatter) in compliance with header values in the request. - /// - public interface IContentNegotiator - { - /// - /// Performs content negotiating by selecting the most appropriate out of the - /// passed in for the given that can serialize an - /// object of the given . - /// - /// - /// Implementations of this method should call - /// on the selected formatter and return the result of that method. - /// - /// The type to be serialized. - /// - /// Request message, which contains the header values used to perform negotiation. - /// - /// The set of objects from which to choose. - /// - /// The result of the negotiation containing the most appropriate instance, - /// or null if there is no appropriate formatter. - /// - ContentNegotiationResult Negotiate( - Type type, - HttpRequestMessage request, - IEnumerable formatters); - } -} diff --git a/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/ListWrapperCollection.cs b/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/ListWrapperCollection.cs deleted file mode 100644 index 864f865a48..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/ListWrapperCollection.cs +++ /dev/null @@ -1,31 +0,0 @@ -// 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.Collections.Generic; - -namespace System.Collections.ObjectModel -{ - /// - /// A class that inherits from Collection of T but also exposes its underlying data as List of T for performance. - /// - internal sealed class ListWrapperCollection : Collection - { - private readonly List _items; - - internal ListWrapperCollection() - : this(new List()) - { - } - - internal ListWrapperCollection(List list) - : base(list) - { - _items = list; - } - - internal List ItemsList - { - get { return _items; } - } - } -} diff --git a/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/MediaTypeConstants.cs b/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/MediaTypeConstants.cs deleted file mode 100644 index bb796c8a07..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/MediaTypeConstants.cs +++ /dev/null @@ -1,109 +0,0 @@ -// 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.Net.Http.Headers; - -namespace System.Net.Http.Formatting -{ - /// - /// Constants related to media types. - /// - internal static class MediaTypeConstants - { - private static readonly MediaTypeHeaderValue _defaultApplicationXmlMediaType = - new MediaTypeHeaderValue("application/xml"); - private static readonly MediaTypeHeaderValue _defaultTextXmlMediaType = - new MediaTypeHeaderValue("text/xml"); - private static readonly MediaTypeHeaderValue _defaultApplicationJsonMediaType = - new MediaTypeHeaderValue("application/json"); - private static readonly MediaTypeHeaderValue _defaultTextJsonMediaType = - new MediaTypeHeaderValue("text/json"); - private static readonly MediaTypeHeaderValue _defaultApplicationOctetStreamMediaType = - new MediaTypeHeaderValue("application/octet-stream"); - private static readonly MediaTypeHeaderValue _defaultApplicationFormUrlEncodedMediaType = - new MediaTypeHeaderValue("application/x-www-form-urlencoded"); - private static readonly MediaTypeHeaderValue _defaultApplicationBsonMediaType = - new MediaTypeHeaderValue("application/bson"); - - /// - /// Gets a instance representing application/octet-stream. - /// - /// - /// A new instance representing application/octet-stream. - /// - public static MediaTypeHeaderValue ApplicationOctetStreamMediaType - { - get { return _defaultApplicationOctetStreamMediaType; } - } - - /// - /// Gets a instance representing application/xml. - /// - /// - /// A new instance representing application/xml. - /// - public static MediaTypeHeaderValue ApplicationXmlMediaType - { - get { return _defaultApplicationXmlMediaType; } - } - - /// - /// Gets a instance representing application/json. - /// - /// - /// A new instance representing application/json. - /// - public static MediaTypeHeaderValue ApplicationJsonMediaType - { - get { return _defaultApplicationJsonMediaType; } - } - - /// - /// Gets a instance representing text/xml. - /// - /// - /// A new instance representing text/xml. - /// - public static MediaTypeHeaderValue TextXmlMediaType - { - get { return _defaultTextXmlMediaType; } - } - - /// - /// Gets a instance representing text/json. - /// - /// - /// A new instance representing text/json. - /// - public static MediaTypeHeaderValue TextJsonMediaType - { - get { return _defaultTextJsonMediaType; } - } - - /// - /// Gets a instance representing application/x-www-form-urlencoded. - /// - /// - /// A new instance representing application/x-www-form-urlencoded. - /// - public static MediaTypeHeaderValue ApplicationFormUrlEncodedMediaType - { - get { return _defaultApplicationFormUrlEncodedMediaType; } - } - - /// - /// Gets a instance representing application/bson. - /// - /// - /// A new instance representing application/bson. - /// - /// - /// Not yet a standard. In particular this media type is not currently listed at - /// https://www.iana.org/assignments/media-types/application. - /// - public static MediaTypeHeaderValue ApplicationBsonMediaType - { - get { return _defaultApplicationBsonMediaType; } - } - } -} diff --git a/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/MediaTypeFormatterMatch.cs b/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/MediaTypeFormatterMatch.cs deleted file mode 100644 index a9a7aa0936..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/MediaTypeFormatterMatch.cs +++ /dev/null @@ -1,57 +0,0 @@ -// 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.Net.Http.Headers; - -namespace System.Net.Http.Formatting -{ - /// - /// This class describes how well a particular matches a request. - /// - public class MediaTypeFormatterMatch - { - /// - /// Initializes a new instance of the class. - /// - /// The matching formatter. - /// - /// The media type. Can be null in which case the media type application/octet-stream is used. - /// - /// - /// The quality of the match. Can be null in which case it is considered a full match with a value of - /// 1.0. - /// - /// The kind of match. - public MediaTypeFormatterMatch( - MediaTypeFormatter formatter, - MediaTypeHeaderValue mediaType, - double? quality, - MediaTypeFormatterMatchRanking ranking) - { - Formatter = formatter; - MediaType = mediaType != null ? mediaType : MediaTypeConstants.ApplicationOctetStreamMediaType; - Quality = quality ?? FormattingUtilities.Match; - Ranking = ranking; - } - - /// - /// Gets the media type formatter. - /// - public MediaTypeFormatter Formatter { get; private set; } - - /// - /// Gets the matched media type. - /// - public MediaTypeHeaderValue MediaType { get; private set; } - - /// - /// Gets the quality of the match - /// - public double Quality { get; private set; } - - /// - /// Gets the kind of match that occurred. - /// - public MediaTypeFormatterMatchRanking Ranking { get; private set; } - } -} diff --git a/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/MediaTypeFormatterMatchRanking.cs b/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/MediaTypeFormatterMatchRanking.cs deleted file mode 100644 index b79e7c80c8..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/MediaTypeFormatterMatchRanking.cs +++ /dev/null @@ -1,45 +0,0 @@ -// 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. - -namespace System.Net.Http.Formatting -{ - /// - /// Contains information about the degree to which a matches the - /// explicit or implicit preferences found in an incoming request. - /// - public enum MediaTypeFormatterMatchRanking - { - /// - /// No match was found - /// - None = 0, - - /// - /// Matched on type meaning that the formatter is able to serialize the type - /// - MatchOnCanWriteType, - - /// - /// Matched on explicit literal accept header in , - /// e.g. "application/json". - /// - MatchOnRequestAcceptHeaderLiteral, - - /// - /// Matched on explicit subtype range accept header in , - /// e.g. "application/*". - /// - MatchOnRequestAcceptHeaderSubtypeMediaRange, - - /// - /// Matched on explicit all media type range accept header in , - /// e.g. "*/*" - /// - MatchOnRequestAcceptHeaderAllMediaRange, - - /// - /// Matched on the media type of the of the . - /// - MatchOnRequestMediaType, - } -} diff --git a/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/MediaTypeHeaderValueExtensions.cs b/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/MediaTypeHeaderValueExtensions.cs deleted file mode 100644 index ebbec113c8..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/MediaTypeHeaderValueExtensions.cs +++ /dev/null @@ -1,117 +0,0 @@ -// 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.Collections.Generic; -using System.Diagnostics; -using System.Net.Http.Headers; - -namespace System.Net.Http.Formatting -{ - /// - /// Extension methods for . - /// - internal static class MediaTypeHeaderValueExtensions - { - /// - /// Determines whether two instances match. The instance - /// is said to match if and only if - /// is a strict subset of the values and parameters of - /// . - /// That is, if the media type and media type parameters of are all present - /// and match those of then it is a match even though - /// may have additional parameters. - /// - /// The first media type. - /// The second media type. - /// true if this is a subset of ; false otherwise. - public static bool IsSubsetOf(this MediaTypeHeaderValue mediaType1, MediaTypeHeaderValue mediaType2) - { - MediaTypeFormatterMatchRanking mediaType2Range; - return IsSubsetOf(mediaType1, mediaType2, out mediaType2Range); - } - - /// - /// Determines whether two instances match. The instance - /// is said to match if and only if - /// is a strict subset of the values and parameters of - /// . - /// That is, if the media type and media type parameters of are all present - /// and match those of then it is a match even though - /// may have additional parameters. - /// - /// The first media type. - /// The second media type. - /// - /// Indicates whether is a regular media type, a subtype media range, or a full - /// media range. - /// - /// true if this is a subset of ; false otherwise. - public static bool IsSubsetOf( - this MediaTypeHeaderValue mediaType1, - MediaTypeHeaderValue mediaType2, - out MediaTypeFormatterMatchRanking mediaType2Range) - { - // Performance-sensitive - Debug.Assert(mediaType1 != null); - - if (mediaType2 == null) - { - mediaType2Range = MediaTypeFormatterMatchRanking.None; - return false; - } - - var parsedMediaType1 = new ParsedMediaTypeHeaderValue(mediaType1); - var parsedMediaType2 = new ParsedMediaTypeHeaderValue(mediaType2); - mediaType2Range = parsedMediaType2.IsAllMediaRange ? MediaTypeFormatterMatchRanking.MatchOnRequestAcceptHeaderAllMediaRange : - parsedMediaType2.IsSubtypeMediaRange ? MediaTypeFormatterMatchRanking.MatchOnRequestAcceptHeaderSubtypeMediaRange : - MediaTypeFormatterMatchRanking.None; - - if (!parsedMediaType1.TypesEqual(ref parsedMediaType2)) - { - if (mediaType2Range != MediaTypeFormatterMatchRanking.MatchOnRequestAcceptHeaderAllMediaRange) - { - return false; - } - } - else if (!parsedMediaType1.SubTypesEqual(ref parsedMediaType2)) - { - if (mediaType2Range != MediaTypeFormatterMatchRanking.MatchOnRequestAcceptHeaderSubtypeMediaRange) - { - return false; - } - } - else - { - mediaType2Range = MediaTypeFormatterMatchRanking.MatchOnRequestAcceptHeaderLiteral; - } - - // So far we either have a full match or a subset match. Now check that all of - // mediaType1's parameters are present and equal in mediatype2 - // Optimize for the common case where the parameters inherit from Collection and cache the count which - // is faster for Collection. - var parameters1 = mediaType1.Parameters.AsCollection(); - var parameterCount1 = parameters1.Count; - var parameters2 = mediaType2.Parameters.AsCollection(); - var parameterCount2 = parameters2.Count; - for (var i = 0; i < parameterCount1; i++) - { - var parameter1 = parameters1[i]; - var found = false; - for (var j = 0; j < parameterCount2; j++) - { - var parameter2 = parameters2[j]; - if (parameter1.Equals(parameter2)) - { - found = true; - break; - } - } - if (!found) - { - return false; - } - } - return true; - } - } -} diff --git a/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/MediaTypeWithQualityHeaderComparer.cs b/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/MediaTypeWithQualityHeaderComparer.cs deleted file mode 100644 index 02c62a899c..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/MediaTypeWithQualityHeaderComparer.cs +++ /dev/null @@ -1,116 +0,0 @@ -// 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.Collections.Generic; -using System.Diagnostics; -using System.Net.Http.Headers; - -namespace System.Net.Http.Formatting -{ - /// Implementation of that can compare accept media type header fields - /// based on their quality values (a.k.a q-values). See - /// for a comparer for other content negotiation - /// header field q-values. - internal class MediaTypeWithQualityHeaderValueComparer : IComparer - { - private static readonly MediaTypeWithQualityHeaderValueComparer _mediaTypeComparer = - new MediaTypeWithQualityHeaderValueComparer(); - - private MediaTypeWithQualityHeaderValueComparer() - { - } - - public static MediaTypeWithQualityHeaderValueComparer QualityComparer - { - get { return _mediaTypeComparer; } - } - - /// - /// Compares two based on their quality value (a.k.a their - /// "q-value"). Values with identical q-values are considered equal (i.e the result is 0) with the exception - /// that sub-type wild-cards are considered less than specific media types and full wild-cards are considered - /// less than sub-type wild-cards. This allows to sort a sequence of - /// following their q-values in the order of specific media types, subtype wild-cards, and last any full - /// wild-cards. - /// - /// The first to compare. - /// The second to compare. - /// - /// 0 if and are considered equal. - /// 1 if is considered greater than . - /// -1 otherwise ( is considered less than ). - /// - public int Compare(MediaTypeWithQualityHeaderValue mediaType1, MediaTypeWithQualityHeaderValue mediaType2) - { - Debug.Assert(mediaType1 != null, "The 'mediaType1' parameter should not be null."); - Debug.Assert(mediaType2 != null, "The 'mediaType2' parameter should not be null."); - - if (ReferenceEquals(mediaType1, mediaType2)) - { - return 0; - } - - var returnValue = CompareBasedOnQualityFactor(mediaType1, mediaType2); - if (returnValue == 0) - { - var parsedMediaType1 = new ParsedMediaTypeHeaderValue(mediaType1); - var parsedMediaType2 = new ParsedMediaTypeHeaderValue(mediaType2); - - if (!parsedMediaType1.TypesEqual(ref parsedMediaType2)) - { - if (parsedMediaType1.IsAllMediaRange) - { - return -1; - } - else if (parsedMediaType2.IsAllMediaRange) - { - return 1; - } - else if (parsedMediaType1.IsSubtypeMediaRange && !parsedMediaType2.IsSubtypeMediaRange) - { - return -1; - } - else if (!parsedMediaType1.IsSubtypeMediaRange && parsedMediaType2.IsSubtypeMediaRange) - { - return 1; - } - } - else if (!parsedMediaType1.SubTypesEqual(ref parsedMediaType2)) - { - if (parsedMediaType1.IsSubtypeMediaRange) - { - return -1; - } - else if (parsedMediaType2.IsSubtypeMediaRange) - { - return 1; - } - } - } - - return returnValue; - } - - private static int CompareBasedOnQualityFactor( - MediaTypeWithQualityHeaderValue mediaType1, - MediaTypeWithQualityHeaderValue mediaType2) - { - Debug.Assert(mediaType1 != null); - Debug.Assert(mediaType2 != null); - - var mediaType1Quality = mediaType1.Quality ?? FormattingUtilities.Match; - var mediaType2Quality = mediaType2.Quality ?? FormattingUtilities.Match; - var qualityDifference = mediaType1Quality - mediaType2Quality; - if (qualityDifference < 0) - { - return -1; - } - else if (qualityDifference > 0) - { - return 1; - } - - return 0; - } - } -} diff --git a/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/ParsedMediaTypeHeaderValue.cs b/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/ParsedMediaTypeHeaderValue.cs deleted file mode 100644 index 8046dd94d7..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/ParsedMediaTypeHeaderValue.cs +++ /dev/null @@ -1,88 +0,0 @@ -// 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.Diagnostics; -using System.Net.Http.Headers; - -namespace System.Net.Http.Formatting -{ - // This type is instantiated by frequently called comparison methods so is very performance sensitive - internal struct ParsedMediaTypeHeaderValue - { - private const char MediaRangeAsterisk = '*'; - private const char MediaTypeSubtypeDelimiter = '/'; - - private readonly string _mediaType; - private readonly int _delimiterIndex; - private readonly bool _isAllMediaRange; - private readonly bool _isSubtypeMediaRange; - - public ParsedMediaTypeHeaderValue(MediaTypeHeaderValue mediaTypeHeaderValue) - { - Debug.Assert(mediaTypeHeaderValue != null); - var mediaType = _mediaType = mediaTypeHeaderValue.MediaType; - _delimiterIndex = mediaType.IndexOf(MediaTypeSubtypeDelimiter); - Debug.Assert( - _delimiterIndex > 0, - "The constructor of the MediaTypeHeaderValue would have failed if there wasn't a type and subtype."); - - _isAllMediaRange = false; - _isSubtypeMediaRange = false; - var mediaTypeLength = mediaType.Length; - if (_delimiterIndex == mediaTypeLength - 2) - { - if (mediaType[mediaTypeLength - 1] == MediaRangeAsterisk) - { - _isSubtypeMediaRange = true; - if (_delimiterIndex == 1 && mediaType[0] == MediaRangeAsterisk) - { - _isAllMediaRange = true; - } - } - } - } - - public bool IsAllMediaRange - { - get { return _isAllMediaRange; } - } - - public bool IsSubtypeMediaRange - { - get { return _isSubtypeMediaRange; } - } - - public bool TypesEqual(ref ParsedMediaTypeHeaderValue other) - { - if (_delimiterIndex != other._delimiterIndex) - { - return false; - } - - return string.Compare( - strA: _mediaType, - indexA: 0, - strB: other._mediaType, - indexB: 0, - length: _delimiterIndex, - comparisonType: StringComparison.OrdinalIgnoreCase) == 0; - } - - public bool SubTypesEqual(ref ParsedMediaTypeHeaderValue other) - { - var _subTypeLength = _mediaType.Length - _delimiterIndex - 1; - if (_subTypeLength != other._mediaType.Length - other._delimiterIndex - 1) - { - return false; - } - - return string.Compare( - strA: _mediaType, - indexA: _delimiterIndex + 1, - strB: other._mediaType, - indexB: other._delimiterIndex + 1, - length: _subTypeLength, - comparisonType: StringComparison.OrdinalIgnoreCase) == 0; - } - } -} diff --git a/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/StringWithQualityHeaderValueComparer.cs b/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/StringWithQualityHeaderValueComparer.cs deleted file mode 100644 index 3a2e8222bb..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/ContentNegotiator/StringWithQualityHeaderValueComparer.cs +++ /dev/null @@ -1,75 +0,0 @@ -// 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.Collections.Generic; -using System.Diagnostics; -using System.Net.Http.Headers; - -namespace System.Net.Http.Formatting -{ - /// - /// Implementation of that can compare content negotiation header fields - /// based on their quality values (a.k.a q-values). This applies to values used in accept-charset, - /// accept-encoding, accept-language and related header fields with similar syntax rules. See - /// for a comparer for media type - /// q-values. - /// - internal class StringWithQualityHeaderValueComparer : IComparer - { - private static readonly StringWithQualityHeaderValueComparer _qualityComparer = - new StringWithQualityHeaderValueComparer(); - - private StringWithQualityHeaderValueComparer() - { - } - - public static StringWithQualityHeaderValueComparer QualityComparer - { - get { return _qualityComparer; } - } - - /// - /// Compares two based on their quality value (a.k.a their - /// "q-value"). Values with identical q-values are considered equal (i.e the result is 0) with the exception of - /// wild-card values (i.e. a value of "*") which are considered less than non-wild-card values. This allows to - /// sort a sequence of following their q-values ending up with any - /// wild-cards at the end. - /// - /// The first value to compare. - /// The second value to compare - /// The result of the comparison. - public int Compare( - StringWithQualityHeaderValue stringWithQuality1, - StringWithQualityHeaderValue stringWithQuality2) - { - Debug.Assert(stringWithQuality1 != null); - Debug.Assert(stringWithQuality2 != null); - - var quality1 = stringWithQuality1.Quality ?? FormattingUtilities.Match; - var quality2 = stringWithQuality2.Quality ?? FormattingUtilities.Match; - var qualityDifference = quality1 - quality2; - if (qualityDifference < 0) - { - return -1; - } - else if (qualityDifference > 0) - { - return 1; - } - - if (!string.Equals(stringWithQuality1.Value, stringWithQuality2.Value, StringComparison.OrdinalIgnoreCase)) - { - if (string.Equals(stringWithQuality1.Value, "*", StringComparison.Ordinal)) - { - return -1; - } - else if (string.Equals(stringWithQuality2.Value, "*", StringComparison.Ordinal)) - { - return 1; - } - } - - return 0; - } - } -} diff --git a/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/Microsoft.AspNetCore.Mvc.WebApiCompatShim.csproj b/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/Microsoft.AspNetCore.Mvc.WebApiCompatShim.csproj index d0b81a0f91..ab1d11a599 100644 --- a/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/Microsoft.AspNetCore.Mvc.WebApiCompatShim.csproj +++ b/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/Microsoft.AspNetCore.Mvc.WebApiCompatShim.csproj @@ -8,9 +8,6 @@ System.Web.Http.ApiController $(NoWarn);CS1591 true aspnetcore;aspnetcoremvc;aspnetwebapi - - $(PackageTargetFallback);portable-net451+win8 - true diff --git a/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..a97fe6be81 --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/Properties/AssemblyInfo.cs @@ -0,0 +1,11 @@ +// 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.Runtime.CompilerServices; + +[assembly: TypeForwardedTo(typeof(System.Net.Http.Formatting.ContentNegotiationResult))] +[assembly: TypeForwardedTo(typeof(System.Net.Http.Formatting.DefaultContentNegotiator))] +[assembly: TypeForwardedTo(typeof(System.Net.Http.Formatting.FormDataCollection ))] +[assembly: TypeForwardedTo(typeof(System.Net.Http.Formatting.IContentNegotiator))] +[assembly: TypeForwardedTo(typeof(System.Net.Http.Formatting.MediaTypeFormatterMatch))] +[assembly: TypeForwardedTo(typeof(System.Net.Http.Formatting.MediaTypeFormatterMatchRanking))] diff --git a/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/breakingchanges.netcore.json b/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/breakingchanges.netcore.json new file mode 100644 index 0000000000..1ceaeb35b2 --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.WebApiCompatShim/breakingchanges.netcore.json @@ -0,0 +1,7 @@ +[ + { + "TypeId": "public enum System.Net.Http.Formatting.MediaTypeFormatterMatchRanking", + "MemberId": "MatchOnRequestMediaType = 5", + "Kind": "Removal" + } +] diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/Microsoft.AspNetCore.Mvc.FunctionalTests.csproj b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/Microsoft.AspNetCore.Mvc.FunctionalTests.csproj index 6130a01b12..b360623583 100644 --- a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/Microsoft.AspNetCore.Mvc.FunctionalTests.csproj +++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/Microsoft.AspNetCore.Mvc.FunctionalTests.csproj @@ -3,9 +3,6 @@ $(StandardTestTfms) - - $(PackageTargetFallback);portable-net451+win8 - true $(DefineConstants);GENERATE_BASELINES diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/WebApiCompatShimBasicTest.cs b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/WebApiCompatShimBasicTest.cs index 9834346b79..39c8d8baf8 100644 --- a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/WebApiCompatShimBasicTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/WebApiCompatShimBasicTest.cs @@ -62,11 +62,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests { typeof(JsonMediaTypeFormatter).FullName, typeof(XmlMediaTypeFormatter).FullName, - -#if NET461 - // We call into WebAPI and ask it to add all of its formatters. On net461 it adds this additional formatter. typeof(FormUrlEncodedMediaTypeFormatter).FullName -#endif }; // Act diff --git a/test/Microsoft.AspNetCore.Mvc.WebApiCompatShimTest/Microsoft.AspNetCore.Mvc.WebApiCompatShimTest.csproj b/test/Microsoft.AspNetCore.Mvc.WebApiCompatShimTest/Microsoft.AspNetCore.Mvc.WebApiCompatShimTest.csproj index 6987869a84..b10e11d8e7 100644 --- a/test/Microsoft.AspNetCore.Mvc.WebApiCompatShimTest/Microsoft.AspNetCore.Mvc.WebApiCompatShimTest.csproj +++ b/test/Microsoft.AspNetCore.Mvc.WebApiCompatShimTest/Microsoft.AspNetCore.Mvc.WebApiCompatShimTest.csproj @@ -1,12 +1,7 @@  - - netcoreapp2.1 - $(TargetFrameworks);netcoreapp2.0 - - - $(PackageTargetFallback);portable-net451+win8 - true + + $(StandardTestTfms) true true diff --git a/test/WebSites/WebApiCompatShimWebSite/WebApiCompatShimWebSite.csproj b/test/WebSites/WebApiCompatShimWebSite/WebApiCompatShimWebSite.csproj index 7bf6f180ef..fd4dd53d70 100644 --- a/test/WebSites/WebApiCompatShimWebSite/WebApiCompatShimWebSite.csproj +++ b/test/WebSites/WebApiCompatShimWebSite/WebApiCompatShimWebSite.csproj @@ -2,8 +2,6 @@ $(StandardTestWebsiteTfms) - $(PackageTargetFallback);portable-net451+win8 - true