public void Ctor_ClonesMediaType()
        {
            // Arrange
            MockMediaTypeFormatter formatter = new MockMediaTypeFormatter();
            MediaTypeHeaderValue mediaType = MediaTypeHeaderValue.Parse("text/test");

            // Act
            MediaTypeFormatterMatch match = new MediaTypeFormatterMatch(formatter, mediaType, null, MediaTypeFormatterMatchRanking.MatchOnCanWriteType);

            // Assert
            Assert.Equal(mediaType, match.MediaType);
            Assert.NotSame(mediaType, match.MediaType);
        }
        public void Ctor_InitializesDefaultValues()
        {
            // Arrange
            MockMediaTypeFormatter formatter = new MockMediaTypeFormatter();

            // Act
            MediaTypeFormatterMatch match = new MediaTypeFormatterMatch(formatter, null, null, MediaTypeFormatterMatchRanking.MatchOnCanWriteType);

            // Assert
            Assert.Same(formatter, match.Formatter);
            Assert.Equal(MediaTypeConstants.ApplicationOctetStreamMediaType, match.MediaType);
            Assert.Equal(FormattingUtilities.Match, match.Quality);
            Assert.Equal(MediaTypeFormatterMatchRanking.MatchOnCanWriteType, match.Ranking);
        }
        public void SelectResponseMediaTypeFormatter_SelectsMediaType(ICollection <MediaTypeFormatterMatch> matches, MediaTypeFormatterMatch expectedWinner)
        {
            // Arrange
            MockContentNegotiator negotiator = new MockContentNegotiator();

            // Act
            MediaTypeFormatterMatch actualWinner = negotiator.SelectResponseMediaTypeFormatter(matches);

            // Assert
            Assert.Same(expectedWinner, actualWinner);
        }
        /// <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;
        }
        /// <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)
        {
            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);
        }
Exemple #6
0
        public void UpdateBestMatch_SelectsCorrectly(MediaTypeFormatterMatch current, MediaTypeFormatterMatch replacement, bool currentWins)
        {
            // Arrange
            MockContentNegotiator negotiator = new MockContentNegotiator();

            // Act
            MediaTypeFormatterMatch actualResult = negotiator.UpdateBestMatch(current, replacement);

            // Assert
            if (currentWins)
            {
                Assert.Same(current, actualResult);
            }
            else
            {
                Assert.Same(replacement, actualResult);
            }
        }
        /// <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);
        }
        /// <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, HttpRequestMessage request, IEnumerable <MediaTypeFormatter> formatters)
        {
            // Performance-sensitive
            if (type == null)
            {
                throw Error.ArgumentNull("type");
            }
            if (request == null)
            {
                throw Error.ArgumentNull("request");
            }
            if (formatters == null)
            {
                throw Error.ArgumentNull("formatters");
            }

            IEnumerable <MediaTypeWithQualityHeaderValue> sortedAcceptValues = null;

            // Go through each formatter to find how well it matches.
            ListWrapperCollection <MediaTypeFormatterMatch> matches = new ListWrapperCollection <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);
        }
        public void UpdateBestMatch_SelectsCorrectly(MediaTypeFormatterMatch current, MediaTypeFormatterMatch replacement, bool currentWins)
        {
            // Arrange
            MockContentNegotiator negotiator = new MockContentNegotiator();

            // Act
            MediaTypeFormatterMatch actualResult = negotiator.UpdateBestMatch(current, replacement);

            // Assert
            if (currentWins)
            {
                Assert.Same(current, actualResult);
            }
            else
            {
                Assert.Same(replacement, actualResult);
            }
        }
        public void SelectResponseMediaTypeFormatter_SelectsMediaType(ICollection<MediaTypeFormatterMatch> matches, MediaTypeFormatterMatch expectedWinner)
        {
            // Arrange
            MockContentNegotiator negotiator = new MockContentNegotiator();

            // Act
            MediaTypeFormatterMatch actualWinner = negotiator.SelectResponseMediaTypeFormatter(matches);

            // Assert
            Assert.Same(expectedWinner, actualWinner);
        }
        /// <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, HttpRequestMessage request, IEnumerable <MediaTypeFormatter> formatters)
        {
            if (type == null)
            {
                throw Error.ArgumentNull("type");
            }
            if (request == null)
            {
                throw Error.ArgumentNull("request");
            }
            if (formatters == null)
            {
                throw Error.ArgumentNull("formatters");
            }

            IEnumerable <MediaTypeWithQualityHeaderValue> sortedAcceptValues = null;

            // Go through each formatter to find how well it matches.
            Collection <MediaTypeFormatterMatch> matches = new Collection <MediaTypeFormatterMatch>();

            foreach (MediaTypeFormatter formatter in formatters)
            {
                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;
                }

                // Match against the type of object we are writing out
                if ((match = MatchType(type, formatter)) != null)
                {
                    matches.Add(match);
                    continue;
                }
            }

            return(matches);
        }