Пример #1
0
        public void Add_MediaTypeHeaderValue_AddsTheStringSegmentRepresentationOfTheMediaType()
        {
            // Arrange
            var mediaTypeHeaderValue = MediaTypeHeaderValue.Parse("application/json;charset=utf-16");
            var collection = new MediaTypeCollection();

            // Act
            collection.Add(mediaTypeHeaderValue);

            // Assert
            Assert.Contains("application/json; charset=utf-16", collection);
        }
Пример #2
0
        public void Remove_MediaTypeHeaderValue_RemovesTheStringSegmentRepresentationOfTheMediaType()
        {
            // Arrange
            var collection = new MediaTypeCollection
            {
                MediaTypeHeaderValue.Parse("text/plain"),
                MediaTypeHeaderValue.Parse("text/xml")
            };

            // Act
            collection.Remove(MediaTypeHeaderValue.Parse("text/xml"));

            // Assert
            Assert.DoesNotContain("text/xml", collection);
        }
Пример #3
0
        public void Insert_MediaTypeHeaderValue_AddsTheStringSegmentRepresentationOfTheMediaTypeOnTheGivenIndex()
        {
            // Arrange
            var mediaTypeHeaderValue = MediaTypeHeaderValue.Parse("application/json;charset=utf-16");
            var collection = new MediaTypeCollection
            {
                MediaTypeHeaderValue.Parse("text/plain"),
                MediaTypeHeaderValue.Parse("text/xml")
            };

            // Act
            collection.Insert(1, mediaTypeHeaderValue);

            // Assert
            Assert.Equal(1, collection.IndexOf("application/json; charset=utf-16"));
        }
Пример #4
0
        private string GetResponseContentType(string format)
        {
            var mediaTypes = new MediaTypeCollection();

            if (format != null)
            {
                mediaTypes.Add(
                    new MediaTypeHeaderValue(
                        this.options.FormatterMappings.GetMediaTypeMappingForFormat(
                            format)));
            }

            var formatter = this.selector.SelectFormatter(
                new OutputFormatterWriteContext(
                    this.HttpContext,
                    (s, e) => null,
                    typeof(IGraph),
                    null),
                this.options.OutputFormatters.OfType <GraphOutputFormatter>().Cast <IOutputFormatter>().ToList(),
                mediaTypes);

            return(((GraphOutputFormatter)formatter).SupportedMediaTypes.Single());
        }
        public ProblemDetailsOptions()
        {
            SourceCodeLineCount          = 6;
            Mappers                      = new List <ExceptionMapper>();
            RethrowPolicies              = new List <Func <HttpContext, Exception, bool> >();
            ContentTypes                 = new MediaTypeCollection();
            TraceIdPropertyName          = DefaultTraceIdPropertyName;
            ExceptionDetailsPropertyName = DefaultExceptionDetailsPropertyName;
            ValidationProblemStatusCode  = StatusCodes.Status422UnprocessableEntity;
            AllowedHeaderNames           = new HashSet <string>(StringComparer.OrdinalIgnoreCase)
            {
                HeaderNames.AccessControlAllowCredentials,
                HeaderNames.AccessControlAllowHeaders,
                HeaderNames.AccessControlAllowMethods,
                HeaderNames.AccessControlAllowOrigin,
                HeaderNames.AccessControlExposeHeaders,
                HeaderNames.AccessControlMaxAge,

                HeaderNames.StrictTransportSecurity,

                HeaderNames.WWWAuthenticate,
            };
        }
Пример #6
0
        private string GetResponseContentType(QueryParameters parameters)
        {
            var mediaTypes = new MediaTypeCollection();

            if (!(parameters.Format is null))
            {
                mediaTypes.Add(
                    new MediaTypeHeaderValue(
                        this.options.FormatterMappings.GetMediaTypeMappingForFormat(
                            parameters.Format)));
            }

            var formatter = this.selector.SelectFormatter(
                new OutputFormatterWriteContext(
                    this.HttpContext,
                    (s, e) => null,
                    typeof(Feed),
                    null),
                this.options.OutputFormatters.OfType <FeedFormatter>().Cast <IOutputFormatter>().ToList(),
                mediaTypes);

            return(((FeedFormatter)formatter).SupportedMediaTypes.Single());
        }
Пример #7
0
        private MediaTypeCollection GetContentTypes(string firstArg, string[] args)
        {
            var completeArgs = new List <string>();

            completeArgs.Add(firstArg);
            completeArgs.AddRange(args);
            var contentTypes = new MediaTypeCollection();

            foreach (var arg in completeArgs)
            {
                var mediaType = new MediaType(arg);
                if (mediaType.MatchesAllSubTypes ||
                    mediaType.MatchesAllTypes)
                {
                    throw new InvalidOperationException(
                              Resources.FormatMatchAllContentTypeIsNotAllowed(arg));
                }

                contentTypes.Add(arg);
            }

            return(contentTypes);
        }
Пример #8
0
        private IReadOnlyList <ApiRequestFormat> GetSupportedFormats(MediaTypeCollection contentTypes, Type type)
        {
            if (contentTypes.Count == 0)
            {
                contentTypes = new MediaTypeCollection
                {
                    (string)null,
                };
            }

            var results = new List <ApiRequestFormat>();

            foreach (var contentType in contentTypes)
            {
                foreach (var formatter in _inputFormatters)
                {
                    if (formatter is IApiRequestFormatMetadataProvider requestFormatMetadataProvider)
                    {
                        var supportedTypes = requestFormatMetadataProvider.GetSupportedContentTypes(contentType, type);

                        if (supportedTypes != null)
                        {
                            foreach (var supportedType in supportedTypes)
                            {
                                results.Add(new ApiRequestFormat()
                                {
                                    Formatter = formatter,
                                    MediaType = supportedType,
                                });
                            }
                        }
                    }
                }
            }

            return(results);
        }
Пример #9
0
        public override void OnException(ExceptionContext context)
        {
            var apiException = context.Exception as ApiException;

            if (apiException == null)
            {
                return;
            }


            int statusCode = apiException.StatusCode;

            if (string.IsNullOrEmpty(apiException.ResponseText))
            {
                context.Result = new StatusCodeResult(statusCode);
            }
            else
            {
                var contentTypes = new MediaTypeCollection();

                foreach (var type in apiException.Headers["Content-Type"])
                {
                    contentTypes.Add(type);
                }


                context.Result = new JsonResult(JObject.Parse(apiException.ResponseText))
                {
                    StatusCode = statusCode,
                };
            }

            context.ExceptionHandled = true;

            logger.Warning(apiException.Message);
        }
Пример #10
0
        private IOutputFormatter SelectFormatterUsingAnyAcceptableContentType(
            OutputFormatterCanWriteContext formatterContext,
            IList <IOutputFormatter> formatters,
            MediaTypeCollection acceptableContentTypes)
        {
            if (formatterContext == null)
            {
                throw new ArgumentNullException(nameof(formatterContext));
            }

            if (formatters == null)
            {
                throw new ArgumentNullException(nameof(formatters));
            }

            if (acceptableContentTypes == null)
            {
                throw new ArgumentNullException(nameof(acceptableContentTypes));
            }

            foreach (var formatter in formatters)
            {
                foreach (var contentType in acceptableContentTypes)
                {
                    formatterContext.ContentType = new StringSegment(contentType);
                    formatterContext.ContentTypeIsServerDefined = true;

                    if (formatter.CanWriteResult(formatterContext))
                    {
                        return(formatter);
                    }
                }
            }

            return(null);
        }
        /// <summary>
        /// Selects the <see cref="IOutputFormatter"/> to write the response.
        /// </summary>
        /// <param name="formatterContext">The <see cref="OutputFormatterWriteContext"/>.</param>
        /// <param name="contentTypes">
        /// The list of content types provided by <see cref="ObjectResult.ContentTypes"/>.
        /// </param>
        /// <param name="formatters">
        /// The list of <see cref="IOutputFormatter"/> instances to consider.
        /// </param>
        /// <returns>
        /// The selected <see cref="IOutputFormatter"/> or <c>null</c> if no formatter can write the response.
        /// </returns>
        protected virtual IOutputFormatter SelectFormatter(
            OutputFormatterWriteContext formatterContext,
            MediaTypeCollection contentTypes,
            IList <IOutputFormatter> formatters)
        {
            if (formatterContext == null)
            {
                throw new ArgumentNullException(nameof(formatterContext));
            }

            if (contentTypes == null)
            {
                throw new ArgumentNullException(nameof(contentTypes));
            }

            if (formatters == null)
            {
                throw new ArgumentNullException(nameof(formatters));
            }

            var request = formatterContext.HttpContext.Request;
            var acceptableMediaTypes = GetAcceptableMediaTypes(contentTypes, request);
            var selectFormatterWithoutRegardingAcceptHeader = false;
            IOutputFormatter selectedFormatter = null;

            if (acceptableMediaTypes.Count == 0)
            {
                // There is either no Accept header value, or it contained */* and we
                // are not currently respecting the 'browser accept header'.
                Logger.NoAcceptForNegotiation();

                selectFormatterWithoutRegardingAcceptHeader = true;
            }
            else
            {
                if (contentTypes.Count == 0)
                {
                    // Use whatever formatter can meet the client's request
                    selectedFormatter = SelectFormatterUsingSortedAcceptHeaders(
                        formatterContext,
                        formatters,
                        acceptableMediaTypes);
                }
                else
                {
                    // Verify that a content type from the context is compatible with the client's request
                    selectedFormatter = SelectFormatterUsingSortedAcceptHeadersAndContentTypes(
                        formatterContext,
                        formatters,
                        acceptableMediaTypes,
                        contentTypes);
                }

                if (selectedFormatter == null && !ReturnHttpNotAcceptable)
                {
                    Logger.NoFormatterFromNegotiation(acceptableMediaTypes);

                    selectFormatterWithoutRegardingAcceptHeader = true;
                }
            }

            if (selectFormatterWithoutRegardingAcceptHeader)
            {
                if (contentTypes.Count == 0)
                {
                    selectedFormatter = SelectFormatterNotUsingContentType(
                        formatterContext,
                        formatters);
                }
                else
                {
                    selectedFormatter = SelectFormatterUsingAnyAcceptableContentType(
                        formatterContext,
                        formatters,
                        contentTypes);
                }
            }

            return(selectedFormatter);
        }
        private void CalculateResponseFormats(ICollection <ApiResponseType> responseTypes, MediaTypeCollection declaredContentTypes)
        {
            var responseTypeMetadataProviders = _mvcOptions.OutputFormatters.OfType <IApiResponseTypeMetadataProvider>();

            // Given the content-types that were declared for this action, determine the formatters that support the content-type for the given
            // response type.
            // 1. Responses that do not specify an type do not have any associated content-type. This usually is meant for status-code only responses such
            // as return NotFound();
            // 2. When a type is specified, use GetSupportedContentTypes to expand wildcards and get the range of content-types formatters support.
            // 3. When no formatter supports the specified content-type, use the user specified value as is. This is useful in actions where the user
            // dictates the content-type.
            // e.g. [Produces("application/pdf")] Action() => FileStream("somefile.pdf", "application/pdf");

            foreach (var apiResponse in responseTypes)
            {
                var responseType = apiResponse.Type;
                if (responseType == null || responseType == typeof(void))
                {
                    continue;
                }

                apiResponse.ModelMetadata = _modelMetadataProvider.GetMetadataForType(responseType);

                foreach (var contentType in declaredContentTypes)
                {
                    var isSupportedContentType = false;

                    foreach (var responseTypeMetadataProvider in responseTypeMetadataProviders)
                    {
                        var formatterSupportedContentTypes = responseTypeMetadataProvider.GetSupportedContentTypes(
                            contentType,
                            responseType);

                        if (formatterSupportedContentTypes == null)
                        {
                            continue;
                        }

                        isSupportedContentType = true;

                        foreach (var formatterSupportedContentType in formatterSupportedContentTypes)
                        {
                            apiResponse.ApiResponseFormats.Add(new ApiResponseFormat
                            {
                                Formatter = (IOutputFormatter)responseTypeMetadataProvider,
                                MediaType = formatterSupportedContentType,
                            });
                        }
                    }

                    if (!isSupportedContentType && contentType != null)
                    {
                        // No output formatter was found that supports this content type. Add the user specified content type as-is to the result.
                        apiResponse.ApiResponseFormats.Add(new ApiResponseFormat
                        {
                            MediaType = contentType,
                        });
                    }
                }
            }
        }
Пример #13
0
 /// <inheritdoc />
 void IApiResponseMetadataProvider.SetContentTypes(MediaTypeCollection contentTypes)
 => Produces.SetContentTypes(contentTypes);
Пример #14
0
        /// <summary>
        /// Selects the <see cref="IOutputFormatter"/> to write the response based on the content type values
        /// present in <paramref name="acceptableContentTypes"/>.
        /// </summary>
        /// <param name="formatterContext">The <see cref="OutputFormatterWriteContext"/>.</param>
        /// <param name="formatters">
        /// The list of <see cref="IOutputFormatter"/> instances to consider.
        /// </param>
        /// <param name="acceptableContentTypes">
        /// The ordered content types from <see cref="ObjectResult.ContentTypes"/> in descending priority order.
        /// </param>
        /// <returns>
        /// The selected <see cref="IOutputFormatter"/> or <c>null</c> if no formatter can write the response.
        /// </returns>
        protected virtual IOutputFormatter SelectFormatterUsingAnyAcceptableContentType(
            OutputFormatterWriteContext formatterContext,
            IList<IOutputFormatter> formatters,
            MediaTypeCollection acceptableContentTypes)
        {
            if (formatterContext == null)
            {
                throw new ArgumentNullException(nameof(formatterContext));
            }

            if (formatters == null)
            {
                throw new ArgumentNullException(nameof(formatters));
            }

            if (acceptableContentTypes == null)
            {
                throw new ArgumentNullException(nameof(acceptableContentTypes));
            }

            foreach (var formatter in formatters)
            {
                foreach (var contentType in acceptableContentTypes)
                {
                    formatterContext.ContentType = new StringSegment(contentType);
                    if (formatter.CanWriteResult(formatterContext))
                    {
                        return formatter;
                    }
                }
            }

            return null;
        }
Пример #15
0
 public void SetContentTypes(MediaTypeCollection contentTypes)
 {
     throw new NotImplementedException();
 }
Пример #16
0
    public override IOutputFormatter?SelectFormatter(OutputFormatterCanWriteContext context, IList <IOutputFormatter> formatters, MediaTypeCollection contentTypes)
    {
        if (context == null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        if (formatters == null)
        {
            throw new ArgumentNullException(nameof(formatters));
        }

        if (contentTypes == null)
        {
            throw new ArgumentNullException(nameof(contentTypes));
        }

        ValidateContentTypes(contentTypes);

        if (formatters.Count == 0)
        {
            formatters = _formatters;
            if (formatters.Count == 0)
            {
                throw new InvalidOperationException(Resources.FormatOutputFormattersAreRequired(
                                                        typeof(MvcOptions).FullName,
                                                        nameof(MvcOptions.OutputFormatters),
                                                        typeof(IOutputFormatter).FullName));
            }
        }

        Log.RegisteredOutputFormatters(_logger, formatters);

        var request = context.HttpContext.Request;
        var acceptableMediaTypes = GetAcceptableMediaTypes(request);
        var selectFormatterWithoutRegardingAcceptHeader = false;

        IOutputFormatter?selectedFormatter = null;

        if (acceptableMediaTypes.Count == 0)
        {
            // There is either no Accept header value, or it contained */* and we
            // are not currently respecting the 'browser accept header'.
            Log.NoAcceptForNegotiation(_logger);

            selectFormatterWithoutRegardingAcceptHeader = true;
        }
        else
        {
            if (contentTypes.Count == 0)
            {
                Log.SelectingOutputFormatterUsingAcceptHeader(_logger, acceptableMediaTypes);

                // Use whatever formatter can meet the client's request
                selectedFormatter = SelectFormatterUsingSortedAcceptHeaders(
                    context,
                    formatters,
                    acceptableMediaTypes);
            }
            else
            {
                Log.SelectingOutputFormatterUsingAcceptHeaderAndExplicitContentTypes(_logger, acceptableMediaTypes, contentTypes);

                // Verify that a content type from the context is compatible with the client's request
                selectedFormatter = SelectFormatterUsingSortedAcceptHeadersAndContentTypes(
                    context,
                    formatters,
                    acceptableMediaTypes,
                    contentTypes);
            }

            if (selectedFormatter == null)
            {
                Log.NoFormatterFromNegotiation(_logger, acceptableMediaTypes);

                if (!_returnHttpNotAcceptable)
                {
                    selectFormatterWithoutRegardingAcceptHeader = true;
                }
            }
        }

        if (selectFormatterWithoutRegardingAcceptHeader)
        {
            if (contentTypes.Count == 0)
            {
                Log.SelectingOutputFormatterWithoutUsingContentTypes(_logger);

                selectedFormatter = SelectFormatterNotUsingContentType(
                    context,
                    formatters);
            }
            else
            {
                Log.SelectingOutputFormatterUsingContentTypes(_logger, contentTypes);

                selectedFormatter = SelectFormatterUsingAnyAcceptableContentType(
                    context,
                    formatters,
                    contentTypes);
            }
        }

        if (selectedFormatter != null)
        {
            Log.FormatterSelected(_logger, selectedFormatter, context);
        }

        return(selectedFormatter);
    }
Пример #17
0
        /// <summary>
        /// Selects the <see cref="IOutputFormatter"/> to write the response.
        /// </summary>
        /// <param name="formatterContext">The <see cref="OutputFormatterWriteContext"/>.</param>
        /// <param name="contentTypes">
        /// The list of content types provided by <see cref="ObjectResult.ContentTypes"/>.
        /// </param>
        /// <param name="formatters">
        /// The list of <see cref="IOutputFormatter"/> instances to consider.
        /// </param>
        /// <returns>
        /// The selected <see cref="IOutputFormatter"/> or <c>null</c> if no formatter can write the response.
        /// </returns>
        protected virtual IOutputFormatter SelectFormatter(
            OutputFormatterWriteContext formatterContext,
            MediaTypeCollection contentTypes,
            IList<IOutputFormatter> formatters)
        {
            if (formatterContext == null)
            {
                throw new ArgumentNullException(nameof(formatterContext));
            }

            if (contentTypes == null)
            {
                throw new ArgumentNullException(nameof(contentTypes));
            }

            if (formatters == null)
            {
                throw new ArgumentNullException(nameof(formatters));
            }

            // Check if any content-type was explicitly set (for example, via ProducesAttribute
            // or URL path extension mapping). If yes, then ignore content-negotiation and use this content-type.
            if (contentTypes.Count == 1)
            {
                Logger.SkippedContentNegotiation(contentTypes[0]);

                return SelectFormatterUsingAnyAcceptableContentType(formatterContext, formatters, contentTypes);
            }

            var request = formatterContext.HttpContext.Request;

            var mediaTypes = GetMediaTypes(contentTypes, request);
            IOutputFormatter selectedFormatter = null;
            if (contentTypes.Count == 0)
            {
                // Check if we have enough information to do content-negotiation, otherwise get the first formatter
                // which can write the type. Let the formatter choose the Content-Type.
                if (!(mediaTypes.Count > 0))
                {
                    Logger.NoAcceptForNegotiation();

                    return SelectFormatterNotUsingAcceptHeaders(formatterContext, formatters);
                }

                //
                // Content-Negotiation starts from this point on.
                //

                // 1. Select based on sorted accept headers.
                selectedFormatter = SelectFormatterUsingSortedAcceptHeaders(
                    formatterContext,
                    formatters,
                    mediaTypes);

                // 2. No formatter was found based on Accept header. Fallback to the first formatter which can write
                // the type. Let the formatter choose the Content-Type.
                if (selectedFormatter == null)
                {
                    Logger.NoFormatterFromNegotiation(mediaTypes);

                    // Set this flag to indicate that content-negotiation has failed to let formatters decide
                    // if they want to write the response or not.
                    formatterContext.FailedContentNegotiation = true;

                    return SelectFormatterNotUsingAcceptHeaders(formatterContext, formatters);
                }
            }
            else
            {
                if (mediaTypes.Count > 0)
                {
                    selectedFormatter = SelectFormatterUsingSortedAcceptHeaders(
                        formatterContext,
                        formatters,
                        mediaTypes);
                }

                if (selectedFormatter == null)
                {
                    // Either there were no acceptHeaders that were present OR
                    // There were no accept headers which matched OR
                    // There were acceptHeaders which matched but there was no formatter
                    // which supported any of them.
                    // In any of these cases, if the user has specified content types,
                    // do a last effort to find a formatter which can write any of the user specified content type.
                    selectedFormatter = SelectFormatterUsingAnyAcceptableContentType(
                        formatterContext,
                        formatters,
                        contentTypes);
                }
            }

            return selectedFormatter;
        }
Пример #18
0
        private MediaTypeCollection GetContentTypes(string firstArg, string[] args)
        {
            var completeArgs = new List<string>();
            completeArgs.Add(firstArg);
            completeArgs.AddRange(args);
            var contentTypes = new MediaTypeCollection();
            foreach (var arg in completeArgs)
            {
                var mediaType = new MediaType(arg);
                if (mediaType.MatchesAllSubTypes ||
                    mediaType.MatchesAllTypes)
                {
                    throw new InvalidOperationException(
                        Resources.FormatMatchAllContentTypeIsNotAllowed(arg));
                }

                contentTypes.Add(arg);
            }

            return contentTypes;
        }
Пример #19
0
 /// <inheritdoc />
 public void SetContentTypes(MediaTypeCollection contentTypes)
 {
     contentTypes.Clear();
     foreach (var contentType in ContentTypes)
     {
         contentTypes.Add(contentType);
     }
 }
Пример #20
0
 public ObjectResult(object value)
 {
     Value = value;
     Formatters = new FormatterCollection<IOutputFormatter>();
     ContentTypes = new MediaTypeCollection();
 }
Пример #21
0
        private void ValidateContentTypes(MediaTypeCollection contentTypes)
        {
            if (contentTypes == null)
            {
                return;
            }

            for (var i = 0; i < contentTypes.Count; i++)
            {
                var contentType = contentTypes[i];
                var parsedContentType = new MediaType(contentType);
                if (parsedContentType.MatchesAllTypes ||
                    parsedContentType.MatchesAllSubTypes)
                {
                    var message = Resources.FormatObjectResult_MatchAllContentType(
                        contentType,
                        nameof(ObjectResult.ContentTypes));
                    throw new InvalidOperationException(message);
                }
            }
        }
Пример #22
0
 /// <summary>
 /// Selects the <see cref="IOutputFormatter"/> to write the response based on the content type values
 /// present in <paramref name="sortedAcceptableContentTypes"/> and <paramref name="possibleOutputContentTypes"/>.
 /// </summary>
 /// <param name="formatterContext">The <see cref="OutputFormatterWriteContext"/>.</param>
 /// <param name="formatters">
 /// The list of <see cref="IOutputFormatter"/> instances to consider.
 /// </param>
 /// <param name="sortedAcceptableContentTypes">
 /// The ordered content types from the <c>Accept</c> header, sorted by descending q-value.
 /// </param>
 /// <param name="possibleOutputContentTypes">
 /// The ordered content types from <see cref="ObjectResult.ContentTypes"/> in descending priority order.
 /// </param>
 /// <returns>
 /// The selected <see cref="IOutputFormatter"/> or <c>null</c> if no formatter can write the response.
 /// </returns>
 protected virtual IOutputFormatter SelectFormatterUsingSortedAcceptHeadersAndContentTypes(
     OutputFormatterWriteContext formatterContext,
     IList<IOutputFormatter> formatters,
     IList<MediaTypeSegmentWithQuality> sortedAcceptableContentTypes,
     MediaTypeCollection possibleOutputContentTypes)
 {
     for (var i = 0; i < sortedAcceptableContentTypes.Count; i++) 
     {
         var acceptableContentType = new MediaType(sortedAcceptableContentTypes[i].MediaType);
         for (var j = 0; j < possibleOutputContentTypes.Count; j++) 
         {
             var candidateContentType = new MediaType(possibleOutputContentTypes[j]);
             if (candidateContentType.IsSubsetOf(acceptableContentType)) 
             {
                 for (var k = 0; k < formatters.Count; k++) 
                 {
                     var formatter = formatters[k];
                     formatterContext.ContentType = new StringSegment(possibleOutputContentTypes[j]);
                     if (formatter.CanWriteResult(formatterContext)) 
                     {
                         return formatter;
                     }
                 }
             }
         }
     }
     
     return null;
 }
Пример #23
0
 public static partial void ActionDoesNotSupportFormatFilterContentType(ILogger logger, string formatFilterContentType, MediaTypeCollection supportedMediaTypes);
Пример #24
0
 private static void SetAllowedMediaType(MediaTypeHeaderValue mediaType,
                                         MediaTypeCollection supportedMediaTypes)
 {
     supportedMediaTypes.Clear();
     supportedMediaTypes.Add(mediaType);
 }
Пример #25
0
        public void SetContentTypes_ClearsAndSetsContentTypes()
        {
            // Arrange
            var attribute = new ConsumesAttribute("application/json", "text/json");

            var contentTypes = new MediaTypeCollection()
            {
                MediaTypeHeaderValue.Parse("application/xml"),
                MediaTypeHeaderValue.Parse("text/xml"),
            };

            // Act
            attribute.SetContentTypes(contentTypes);

            // Assert
            Assert.Collection(
                contentTypes.OrderBy(t => t),
                t => Assert.Equal("application/json", t),
                t => Assert.Equal("text/json", t));
        }
        public override IOutputFormatter SelectFormatter(OutputFormatterCanWriteContext context, IList <IOutputFormatter> formatters, MediaTypeCollection mediaTypes)
        {
            if (!context.HttpContext.Request.Headers["Accept"].First().StartsWith("application/vnd."))
            {
                return(_fallbackSelector.SelectFormatter(context, formatters, mediaTypes));
            }

            if (formatters.Count == 0)
            {
                formatters = _formatters;
            }

            context.ContentType = GetContentTypeFromAcceptHeader(context.HttpContext.Request);

            var formatter = formatters.FirstOrDefault(x => x.CanWriteResult(context));

            context.ContentType = context.HttpContext.Request.Headers["Accept"].First();

            return(formatter);
        }
Пример #27
0
 public void SetContentTypes(MediaTypeCollection contentTypes)
 {
     contentTypes.Add(new MediaTypeHeaderValue("application/json"));
 }
Пример #28
0
        /// <summary>
        /// Selects the <see cref="IOutputFormatter"/> to write the response.
        /// </summary>
        /// <param name="formatterContext">The <see cref="OutputFormatterWriteContext"/>.</param>
        /// <param name="contentTypes">
        /// The list of content types provided by <see cref="ObjectResult.ContentTypes"/>.
        /// </param>
        /// <param name="formatters">
        /// The list of <see cref="IOutputFormatter"/> instances to consider.
        /// </param>
        /// <returns>
        /// The selected <see cref="IOutputFormatter"/> or <c>null</c> if no formatter can write the response.
        /// </returns>
        protected virtual IOutputFormatter SelectFormatter(
            OutputFormatterWriteContext formatterContext,
            MediaTypeCollection contentTypes,
            IList<IOutputFormatter> formatters)
        {
            if (formatterContext == null)
            {
                throw new ArgumentNullException(nameof(formatterContext));
            }

            if (contentTypes == null)
            {
                throw new ArgumentNullException(nameof(contentTypes));
            }

            if (formatters == null)
            {
                throw new ArgumentNullException(nameof(formatters));
            }

            var request = formatterContext.HttpContext.Request;
            var acceptableMediaTypes = GetAcceptableMediaTypes(contentTypes, request);
            var selectFormatterWithoutRegardingAcceptHeader = false;
            IOutputFormatter selectedFormatter = null;

            if (acceptableMediaTypes.Count == 0)
            {
                // There is either no Accept header value, or it contained */* and we
                // are not currently respecting the 'browser accept header'.            
                Logger.NoAcceptForNegotiation();

                selectFormatterWithoutRegardingAcceptHeader = true;
            }
            else
            {
                if (contentTypes.Count == 0)
                {
                    // Use whatever formatter can meet the client's request
                    selectedFormatter = SelectFormatterUsingSortedAcceptHeaders(
                        formatterContext,
                        formatters,
                        acceptableMediaTypes);
                }
                else
                {
                    // Verify that a content type from the context is compatible with the client's request
                    selectedFormatter = SelectFormatterUsingSortedAcceptHeadersAndContentTypes(
                        formatterContext,
                        formatters,
                        acceptableMediaTypes,
                        contentTypes);
                }

                if (selectedFormatter == null && !ReturnHttpNotAcceptable)
                {
                    Logger.NoFormatterFromNegotiation(acceptableMediaTypes);

                    selectFormatterWithoutRegardingAcceptHeader = true;
                }
            }

            if (selectFormatterWithoutRegardingAcceptHeader)
            {
                if (contentTypes.Count == 0)
                {
                    selectedFormatter = SelectFormatterNotUsingContentType(
                        formatterContext,
                        formatters);
                }
                else
                {
                    selectedFormatter = SelectFormatterUsingAnyAcceptableContentType(
                        formatterContext,
                        formatters,
                        contentTypes);
                }
            }

            return selectedFormatter;
        }
Пример #29
0
        private ICollection <ApiResponseType> GetApiResponseTypes(
            IReadOnlyList <IApiResponseMetadataProvider> responseMetadataAttributes,
            Type type,
            Type defaultErrorType)
        {
            var results = new Dictionary <int, ApiResponseType>();

            // Get the content type that the action explicitly set to support.
            // Walk through all 'filter' attributes in order, and allow each one to see or override
            // the results of the previous ones. This is similar to the execution path for content-negotiation.
            var contentTypes = new MediaTypeCollection();

            if (responseMetadataAttributes != null)
            {
                foreach (var metadataAttribute in responseMetadataAttributes)
                {
                    metadataAttribute.SetContentTypes(contentTypes);

                    var statusCode = metadataAttribute.StatusCode;

                    var apiResponseType = new ApiResponseType
                    {
                        Type              = metadataAttribute.Type,
                        StatusCode        = statusCode,
                        IsDefaultResponse = metadataAttribute is IApiDefaultResponseMetadataProvider,
                    };

                    if (apiResponseType.Type == typeof(void))
                    {
                        if (type != null && (statusCode == StatusCodes.Status200OK || statusCode == StatusCodes.Status201Created))
                        {
                            // ProducesResponseTypeAttribute's constructor defaults to setting "Type" to void when no value is specified.
                            // In this event, use the action's return type for 200 or 201 status codes. This lets you decorate an action with a
                            // [ProducesResponseType(201)] instead of [ProducesResponseType(201, typeof(Person)] when typeof(Person) can be inferred
                            // from the return type.
                            apiResponseType.Type = type;
                        }
                        else if (IsClientError(statusCode) || apiResponseType.IsDefaultResponse)
                        {
                            // Use the default error type for "default" responses or 4xx client errors if no response type is specified.
                            apiResponseType.Type = defaultErrorType;
                        }
                    }

                    if (apiResponseType.Type != null)
                    {
                        results[apiResponseType.StatusCode] = apiResponseType;
                    }
                }
            }

            // Set the default status only when no status has already been set explicitly
            if (results.Count == 0 && type != null)
            {
                results[StatusCodes.Status200OK] = new ApiResponseType
                {
                    StatusCode = StatusCodes.Status200OK,
                    Type       = type,
                };
            }

            if (contentTypes.Count == 0)
            {
                contentTypes.Add((string)null);
            }

            var responseTypeMetadataProviders = _mvcOptions.OutputFormatters.OfType <IApiResponseTypeMetadataProvider>();

            foreach (var apiResponse in results.Values)
            {
                var responseType = apiResponse.Type;
                if (responseType == null || responseType == typeof(void))
                {
                    continue;
                }

                apiResponse.ModelMetadata = _modelMetadataProvider.GetMetadataForType(responseType);

                foreach (var contentType in contentTypes)
                {
                    foreach (var responseTypeMetadataProvider in responseTypeMetadataProviders)
                    {
                        var formatterSupportedContentTypes = responseTypeMetadataProvider.GetSupportedContentTypes(
                            contentType,
                            responseType);

                        if (formatterSupportedContentTypes == null)
                        {
                            continue;
                        }

                        foreach (var formatterSupportedContentType in formatterSupportedContentTypes)
                        {
                            apiResponse.ApiResponseFormats.Add(new ApiResponseFormat
                            {
                                Formatter = (IOutputFormatter)responseTypeMetadataProvider,
                                MediaType = formatterSupportedContentType,
                            });
                        }
                    }
                }
            }

            return(results.Values);
        }
Пример #30
0
        private List<MediaTypeSegmentWithQuality> GetAcceptableMediaTypes(
            MediaTypeCollection contentTypes,
            HttpRequest request)
        {
            var result = new List<MediaTypeSegmentWithQuality>();
            AcceptHeaderParser.ParseAcceptHeader(request.Headers[HeaderNames.Accept], result);
            for (int i = 0; i < result.Count; i++)
            {
                var mediaType = new MediaType(result[i].MediaType);
                if (!RespectBrowserAcceptHeader && mediaType.MatchesAllSubTypes && mediaType.MatchesAllTypes)
                {
                    result.Clear();
                    return result;
                }
            }

            result.Sort((left, right) => left.Quality > right.Quality ? -1 : (left.Quality == right.Quality ? 0 : 1));

            return result;
        }
Пример #31
0
 /// <summary>
 /// Initializes an instance of <see cref="ProducesAttribute"/>.
 /// </summary>
 /// <param name="type">The <see cref="Type"/> of object that is going to be written in the response.</param>
 public ProducesAttribute(Type type)
 {
     Type         = type ?? throw new ArgumentNullException(nameof(type));
     ContentTypes = new MediaTypeCollection();
 }
Пример #32
0
        // Shared with EndpointMetadataApiDescriptionProvider
        internal static List <ApiResponseType> ReadResponseMetadata(
            IReadOnlyList <IApiResponseMetadataProvider> responseMetadataAttributes,
            Type?type,
            Type defaultErrorType,
            MediaTypeCollection contentTypes,
            IEnumerable <IApiResponseTypeMetadataProvider>?responseTypeMetadataProviders = null,
            IModelMetadataProvider?modelMetadataProvider = null)
        {
            var results = new Dictionary <int, ApiResponseType>();

            // Get the content type that the action explicitly set to support.
            // Walk through all 'filter' attributes in order, and allow each one to see or override
            // the results of the previous ones. This is similar to the execution path for content-negotiation.
            if (responseMetadataAttributes != null)
            {
                foreach (var metadataAttribute in responseMetadataAttributes)
                {
                    // All ProducesXAttributes, except for ProducesResponseTypeAttribute do
                    // not allow multiple instances on the same method/class/etc. For those
                    // scenarios, the `SetContentTypes` method on the attribute continuously
                    // clears out more general content types in favor of more specific ones
                    // since we iterate through the attributes in order. For example, if a
                    // Produces exists on both a controller and an action within the controller,
                    // we favor the definition in the action. This is a semantic that does not
                    // apply to ProducesResponseType, which allows multiple instances on an target.
                    if (metadataAttribute is not ProducesResponseTypeAttribute)
                    {
                        metadataAttribute.SetContentTypes(contentTypes);
                    }

                    var statusCode = metadataAttribute.StatusCode;

                    var apiResponseType = new ApiResponseType
                    {
                        Type              = metadataAttribute.Type,
                        StatusCode        = statusCode,
                        IsDefaultResponse = metadataAttribute is IApiDefaultResponseMetadataProvider,
                    };

                    if (apiResponseType.Type == typeof(void))
                    {
                        if (type != null && (statusCode == StatusCodes.Status200OK || statusCode == StatusCodes.Status201Created))
                        {
                            // ProducesResponseTypeAttribute's constructor defaults to setting "Type" to void when no value is specified.
                            // In this event, use the action's return type for 200 or 201 status codes. This lets you decorate an action with a
                            // [ProducesResponseType(201)] instead of [ProducesResponseType(typeof(Person), 201] when typeof(Person) can be inferred
                            // from the return type.
                            apiResponseType.Type = type;
                        }
                        else if (IsClientError(statusCode))
                        {
                            // Determine whether or not the type was provided by the user. If so, favor it over the default
                            // error type for 4xx client errors if no response type is specified..
                            var setByDefault = metadataAttribute is ProducesResponseTypeAttribute {
                                IsResponseTypeSetByDefault : true
                            };
                            apiResponseType.Type = setByDefault ? defaultErrorType : apiResponseType.Type;
                        }
                        else if (apiResponseType.IsDefaultResponse)
                        {
                            apiResponseType.Type = defaultErrorType;
                        }
                    }

                    // We special case the handling of ProcuesResponseTypeAttributes since
                    // multiple ProducesResponseTypeAttributes are permitted on a single
                    // action/controller/etc. In that scenario, instead of picking the most-specific
                    // set of content types (like we do with the Produces attribute above) we process
                    // the content types for each attribute independently.
                    if (metadataAttribute is ProducesResponseTypeAttribute)
                    {
                        var attributeContentTypes = new MediaTypeCollection();
                        metadataAttribute.SetContentTypes(attributeContentTypes);
                        CalculateResponseFormatForType(apiResponseType, attributeContentTypes, responseTypeMetadataProviders, modelMetadataProvider);
                    }

                    if (apiResponseType.Type != null)
                    {
                        results[apiResponseType.StatusCode] = apiResponseType;
                    }
                }
            }

            return(results.Values.ToList());
        }
        private IReadOnlyList <ApiResponseType> GetApiResponseTypes(
            IApiResponseMetadataProvider[] responseMetadataAttributes,
            Type type)
        {
            var results = new List <ApiResponseType>();

            // Build list of all possible return types (and status codes) for an action.
            var objectTypes = new Dictionary <int, Type>();

            // Get the content type that the action explicitly set to support.
            // Walk through all 'filter' attributes in order, and allow each one to see or override
            // the results of the previous ones. This is similar to the execution path for content-negotiation.
            var contentTypes = new MediaTypeCollection();

            if (responseMetadataAttributes != null)
            {
                foreach (var metadataAttribute in responseMetadataAttributes)
                {
                    metadataAttribute.SetContentTypes(contentTypes);

                    if (metadataAttribute.Type != null)
                    {
                        objectTypes[metadataAttribute.StatusCode] = metadataAttribute.Type;
                    }
                }
            }

            // Set the default status only when no status has already been set explicitly
            if (objectTypes.Count == 0 &&
                type != null)
            {
                objectTypes[StatusCodes.Status200OK] = type;
            }

            if (contentTypes.Count == 0)
            {
                contentTypes.Add((string)null);
            }

            var responseTypeMetadataProviders = _outputFormatters.OfType <IApiResponseTypeMetadataProvider>();

            foreach (var objectType in objectTypes)
            {
                if (objectType.Value == typeof(void))
                {
                    results.Add(new ApiResponseType()
                    {
                        StatusCode = objectType.Key,
                        Type       = objectType.Value
                    });

                    continue;
                }

                var apiResponseType = new ApiResponseType()
                {
                    Type          = objectType.Value,
                    StatusCode    = objectType.Key,
                    ModelMetadata = _modelMetadataProvider.GetMetadataForType(objectType.Value)
                };

                foreach (var contentType in contentTypes)
                {
                    foreach (var responseTypeMetadataProvider in responseTypeMetadataProviders)
                    {
                        var formatterSupportedContentTypes = responseTypeMetadataProvider.GetSupportedContentTypes(
                            contentType,
                            objectType.Value);

                        if (formatterSupportedContentTypes == null)
                        {
                            continue;
                        }

                        foreach (var formatterSupportedContentType in formatterSupportedContentTypes)
                        {
                            apiResponseType.ApiResponseFormats.Add(new ApiResponseFormat()
                            {
                                Formatter = (IOutputFormatter)responseTypeMetadataProvider,
                                MediaType = formatterSupportedContentType,
                            });
                        }
                    }
                }

                results.Add(apiResponseType);
            }

            return(results);
        }
Пример #34
0
        private static bool InAcceptableMediaTypes(StringSegment mediaType, MediaTypeCollection acceptableMediaTypes)
        {
            if (acceptableMediaTypes.Count == 0)
            {
                return true;
            }

            var parsedMediaType = new MediaType(mediaType);
            for (int i = 0; i < acceptableMediaTypes.Count; i++)
            {
                var acceptableMediaType = new MediaType(acceptableMediaTypes[i]);
                if (acceptableMediaType.IsSubsetOf(parsedMediaType))
                {
                    return true;
                }
            }

            return false;
        }
Пример #35
0
 /// <inheritdoc />
 void IApiResponseMetadataProvider.SetContentTypes(MediaTypeCollection contentTypes)
 {
     // Users are supposed to use the 'Produces' attribute to set the content types that an action can support.
 }
Пример #36
0
        public void SelectFormatter_WithMultipleProvidedContentTypes_DoesConneg(
            MediaTypeCollection contentTypes,
            string acceptHeader,
            string expectedContentType)
        {
            // Arrange
            var executor = CreateExecutor();

            var formatters = new List<IOutputFormatter>
            {
                new CannotWriteFormatter(),
                new TestJsonOutputFormatter(),
            };

            var context = new OutputFormatterWriteContext(
                new DefaultHttpContext(),
                new TestHttpResponseStreamWriterFactory().CreateWriter,
                objectType: null,
                @object: null);

            context.HttpContext.Request.Headers[HeaderNames.Accept] = acceptHeader;

            // Act
            var formatter = executor.SelectFormatter(
                context,
                contentTypes,
                formatters);

            // Assert
            Assert.Same(formatters[1], formatter);
            Assert.Equal(new StringSegment(expectedContentType), context.ContentType);
        }
Пример #37
0
        // Shared with EndpointMetadataApiDescriptionProvider
        internal static void CalculateResponseFormatForType(ApiResponseType apiResponse, MediaTypeCollection declaredContentTypes, IEnumerable <IApiResponseTypeMetadataProvider>?responseTypeMetadataProviders, IModelMetadataProvider?modelMetadataProvider)
        {
            // If response formats have already been calculate for this type,
            // then exit early. This avoids populating the ApiResponseFormat for
            // types that have already been handled, specifically ProducesResponseTypes.
            if (apiResponse.ApiResponseFormats.Count > 0)
            {
                return;
            }

            // Given the content-types that were declared for this action, determine the formatters that support the content-type for the given
            // response type.
            // 1. Responses that do not specify an type do not have any associated content-type. This usually is meant for status-code only responses such
            // as return NotFound();
            // 2. When a type is specified, use GetSupportedContentTypes to expand wildcards and get the range of content-types formatters support.
            // 3. When no formatter supports the specified content-type, use the user specified value as is. This is useful in actions where the user
            // dictates the content-type.
            // e.g. [Produces("application/pdf")] Action() => FileStream("somefile.pdf", "application/pdf");
            var responseType = apiResponse.Type;

            if (responseType == null || responseType == typeof(void))
            {
                return;
            }

            apiResponse.ModelMetadata = modelMetadataProvider?.GetMetadataForType(responseType);

            foreach (var contentType in declaredContentTypes)
            {
                var isSupportedContentType = false;

                if (responseTypeMetadataProviders != null)
                {
                    foreach (var responseTypeMetadataProvider in responseTypeMetadataProviders)
                    {
                        var formatterSupportedContentTypes = responseTypeMetadataProvider.GetSupportedContentTypes(
                            contentType,
                            responseType);

                        if (formatterSupportedContentTypes == null)
                        {
                            continue;
                        }

                        isSupportedContentType = true;

                        foreach (var formatterSupportedContentType in formatterSupportedContentTypes)
                        {
                            apiResponse.ApiResponseFormats.Add(new ApiResponseFormat
                            {
                                Formatter = (IOutputFormatter)responseTypeMetadataProvider,
                                MediaType = formatterSupportedContentType,
                            });
                        }
                    }
                }



                if (!isSupportedContentType && contentType != null)
                {
                    // No output formatter was found that supports this content type. Add the user specified content type as-is to the result.
                    apiResponse.ApiResponseFormats.Add(new ApiResponseFormat
                    {
                        MediaType = contentType,
                    });
                }
            }
        }
Пример #38
0
        public async Task ExecuteAsync_MatchAllContentType_Throws(string[] contentTypes, string invalidContentType)
        {
            // Arrange
            var result = new ObjectResult("input");

            var mediaTypes = new MediaTypeCollection();
            foreach (var contentType in contentTypes)
            {
                mediaTypes.Add(contentType);
            }

            result.ContentTypes = mediaTypes;

            var executor = CreateExecutor();

            var actionContext = new ActionContext() { HttpContext = new DefaultHttpContext() };

            // Act & Assert
            var exception = await Assert.ThrowsAsync<InvalidOperationException>(
                () => executor.ExecuteAsync(actionContext, result));

            var expectedMessage = string.Format("The content-type '{0}' added in the 'ContentTypes' property is " +
              "invalid. Media types which match all types or match all subtypes are not supported.",
              invalidContentType);
            Assert.Equal(expectedMessage, exception.Message);
        }
Пример #39
0
 public static void SelectingOutputFormatterUsingContentTypes(this ILogger logger,
                                                              MediaTypeCollection mediaTypeCollection)
 {
     _selectingOutputFormatterUsingContentTypes(logger, mediaTypeCollection, null);
 }
Пример #40
0
 new public IOutputFormatter SelectFormatter(
     OutputFormatterWriteContext formatterContext,
     MediaTypeCollection contentTypes,
     IList<IOutputFormatter> formatters)
 {
     return base.SelectFormatter(formatterContext, contentTypes, formatters);
 }
Пример #41
0
        public override IOutputFormatter SelectFormatter(OutputFormatterCanWriteContext context, IList <IOutputFormatter> formatters, MediaTypeCollection contentTypes)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (formatters == null)
            {
                throw new ArgumentNullException(nameof(formatters));
            }

            if (contentTypes == null)
            {
                throw new ArgumentNullException(nameof(contentTypes));
            }

            ValidateContentTypes(contentTypes);

            if (formatters.Count == 0)
            {
                formatters = _formatters;
                if (formatters.Count == 0)
                {
                    throw new InvalidOperationException($"At least one '{nameof(IOutputFormatter)}' is required to format a response.");
                }
            }

            _logger.RegisteredOutputFormatters(formatters);

            var request = context.MazeContext.Request;
            var acceptableMediaTypes = GetAcceptableMediaTypes(request);
            var selectFormatterWithoutRegardingAcceptHeader = false;

            IOutputFormatter selectedFormatter = null;

            if (acceptableMediaTypes.Count == 0)
            {
                // There is either no Accept header value, or it contained */* and we
                // are not currently respecting the 'browser accept header'.
                _logger.NoAcceptForNegotiation();

                selectFormatterWithoutRegardingAcceptHeader = true;
            }
            else
            {
                if (contentTypes.Count == 0)
                {
                    _logger.SelectingOutputFormatterUsingAcceptHeader(acceptableMediaTypes);

                    // Use whatever formatter can meet the client's request
                    selectedFormatter = SelectFormatterUsingSortedAcceptHeaders(
                        context,
                        formatters,
                        acceptableMediaTypes);
                }
                else
                {
                    _logger.SelectingOutputFormatterUsingAcceptHeaderAndExplicitContentTypes(acceptableMediaTypes, contentTypes);

                    // Verify that a content type from the context is compatible with the client's request
                    selectedFormatter = SelectFormatterUsingSortedAcceptHeadersAndContentTypes(
                        context,
                        formatters,
                        acceptableMediaTypes,
                        contentTypes);
                }

                if (selectedFormatter == null)
                {
                    _logger.NoFormatterFromNegotiation(acceptableMediaTypes);

                    if (!_returnHttpNotAcceptable)
                    {
                        selectFormatterWithoutRegardingAcceptHeader = true;
                    }
                }
            }

            if (selectFormatterWithoutRegardingAcceptHeader)
            {
                if (contentTypes.Count == 0)
                {
                    _logger.SelectingOutputFormatterWithoutUsingContentTypes();

                    selectedFormatter = SelectFormatterNotUsingContentType(
                        context,
                        formatters);
                }
                else
                {
                    _logger.SelectingOutputFormatterUsingContentTypes(contentTypes);

                    selectedFormatter = SelectFormatterUsingAnyAcceptableContentType(
                        context,
                        formatters,
                        contentTypes);
                }
            }

            if (selectedFormatter == null)
            {
                // No formatter supports this.
                _logger.NoFormatter(context);
                return(null);
            }

            _logger.FormatterSelected(selectedFormatter, context);
            return(selectedFormatter);
        }
Пример #42
0
 protected override IOutputFormatter SelectFormatter(
     OutputFormatterWriteContext formatterContext,
     MediaTypeCollection contentTypes,
     IList<IOutputFormatter> formatters)
 {
     SelectedOutputFormatter = base.SelectFormatter(formatterContext, contentTypes, formatters);
     return SelectedOutputFormatter;
 }
Пример #43
0
 /// <summary>
 /// Selects an <see cref="IOutputFormatter"/> to write the response based on the provided values and the current request.
 /// </summary>
 /// <param name="context">The <see cref="OutputFormatterCanWriteContext"/> associated with the current request.</param>
 /// <param name="formatters">A list of formatters to use; this acts as an override to <see cref="MvcOptions.OutputFormatters"/>.</param>
 /// <param name="mediaTypes">A list of media types to use; this acts as an override to the <c>Accept</c> header. </param>
 /// <returns>The selected <see cref="IOutputFormatter"/>, or <c>null</c> if one could not be selected.</returns>
 public abstract IOutputFormatter?SelectFormatter(OutputFormatterCanWriteContext context, IList <IOutputFormatter> formatters, MediaTypeCollection mediaTypes);
Пример #44
0
        private bool IsSuperSetOfAnySupportedMediaType(string contentType, MediaTypeCollection supportedMediaTypes)
        {
            var parsedContentType = new MediaType(contentType);
            for (var i = 0; i < supportedMediaTypes.Count; i++)
            {
                var supportedMediaType = new MediaType(supportedMediaTypes[i]);
                if (supportedMediaType.IsSubsetOf(parsedContentType))
                {
                    return true;
                }
            }

            return false;
        }
        private ICollection <ApiResponseType> GetApiResponseTypes(
            IReadOnlyList <IApiResponseMetadataProvider> responseMetadataAttributes,
            Type type,
            Type defaultErrorType)
        {
            var results = new Dictionary <int, ApiResponseType>();

            // Get the content type that the action explicitly set to support.
            // Walk through all 'filter' attributes in order, and allow each one to see or override
            // the results of the previous ones. This is similar to the execution path for content-negotiation.
            var contentTypes = new MediaTypeCollection();

            if (responseMetadataAttributes != null)
            {
                foreach (var metadataAttribute in responseMetadataAttributes)
                {
                    metadataAttribute.SetContentTypes(contentTypes);

                    var statusCode = metadataAttribute.StatusCode;

                    var apiResponseType = new ApiResponseType
                    {
                        Type              = metadataAttribute.Type,
                        StatusCode        = statusCode,
                        IsDefaultResponse = metadataAttribute is IApiDefaultResponseMetadataProvider,
                    };

                    if (apiResponseType.Type == typeof(void))
                    {
                        if (type != null && (statusCode == StatusCodes.Status200OK || statusCode == StatusCodes.Status201Created))
                        {
                            // ProducesResponseTypeAttribute's constructor defaults to setting "Type" to void when no value is specified.
                            // In this event, use the action's return type for 200 or 201 status codes. This lets you decorate an action with a
                            // [ProducesResponseType(201)] instead of [ProducesResponseType(201, typeof(Person)] when typeof(Person) can be inferred
                            // from the return type.
                            apiResponseType.Type = type;
                        }
                        else if (IsClientError(statusCode) || apiResponseType.IsDefaultResponse)
                        {
                            // Use the default error type for "default" responses or 4xx client errors if no response type is specified.
                            apiResponseType.Type = defaultErrorType;
                        }
                    }

                    if (apiResponseType.Type != null)
                    {
                        results[apiResponseType.StatusCode] = apiResponseType;
                    }
                }
            }

            // Set the default status only when no status has already been set explicitly
            if (results.Count == 0 && type != null)
            {
                results[StatusCodes.Status200OK] = new ApiResponseType
                {
                    StatusCode = StatusCodes.Status200OK,
                    Type       = type,
                };
            }

            if (contentTypes.Count == 0)
            {
                // None of the IApiResponseMetadataProvider specified a content type. This is common for actions that
                // specify one or more ProducesResponseType but no ProducesAttribute. In this case, formatters will participate in conneg
                // and respond to the incoming request.
                // Querying IApiResponseTypeMetadataProvider.GetSupportedContentTypes with "null" should retrieve all supported
                // content types that each formatter may respond in.
                contentTypes.Add((string)null);
            }

            var responseTypes = results.Values;

            CalculateResponseFormats(responseTypes, contentTypes);
            return(responseTypes);
        }
Пример #46
0
        /// <summary>
        /// As a <see cref="IResourceFilter"/>, this filter looks at the request and rejects it before going ahead if
        /// 1. The format in the request does not match any format in the map.
        /// 2. If there is a conflicting producesFilter.
        /// </summary>
        /// <param name="context">The <see cref="ResourceExecutingContext"/>.</param>
        public void OnResourceExecuting(ResourceExecutingContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            var format = GetFormat(context);
            if (format == null)
            {
                // no format specified by user, so the filter is muted
                return;
            }

            var contentType = _options.FormatterMappings.GetMediaTypeMappingForFormat(format);
            if (contentType == null)
            {
                // no contentType exists for the format, return 404
                context.Result = new NotFoundResult();
                return;
            }

            // Determine media types this action supports.
            var responseTypeFilters = context.Filters.OfType<IApiResponseMetadataProvider>();
            var supportedMediaTypes = new MediaTypeCollection();
            foreach (var filter in responseTypeFilters)
            {
                filter.SetContentTypes(supportedMediaTypes);
            }

            // Check if support is adequate for requested media type.
            if (supportedMediaTypes.Count != 0)
            {
                // We need to check if the action can generate the content type the user asked for. That is, treat the
                // request's format and IApiResponseMetadataProvider-provided content types similarly to an Accept
                // header and an output formatter's SupportedMediaTypes: Confirm action supports a more specific media
                // type than requested e.g. OK if "text/*" requested and action supports "text/plain".
                if (!IsSuperSetOfAnySupportedMediaType(contentType, supportedMediaTypes))
                {
                    context.Result = new NotFoundResult();
                }
            }
        }
Пример #47
0
 public void SetContentTypes(MediaTypeCollection contentTypes)
 {
 }
Пример #48
0
 public static partial void SelectingOutputFormatterUsingAcceptHeaderAndExplicitContentTypes(ILogger logger, IEnumerable <MediaTypeSegmentWithQuality> acceptHeader, MediaTypeCollection explicitContentTypes);
Пример #49
0
 /// <summary>
 /// Creates a new <see cref="ObjectResult"/> instance with the provided <paramref name="value"/>.
 /// </summary>
 /// <param name="value"></param>
 public ObjectResult(object?value)
 {
     Value         = value;
     Formatters    = new FormatterCollection <IOutputFormatter>();
     _contentTypes = new MediaTypeCollection();
 }
Пример #50
0
 public static partial void SelectingOutputFormatterUsingContentTypes(ILogger logger, MediaTypeCollection explicitContentTypes);