private Encoding MatchAcceptCharacterEncoding(string acceptCharsetHeader) { var acceptCharsetHeaders = HeaderParsingHelpers .GetAcceptCharsetHeaders(acceptCharsetHeader); if (acceptCharsetHeaders != null && acceptCharsetHeaders.Count > 0) { var sortedAcceptCharsetHeaders = acceptCharsetHeaders .Where(acceptCharset => acceptCharset.Quality != HttpHeaderUtilitites.NoMatch) .OrderByDescending( m => m, StringWithQualityHeaderValueComparer.QualityComparer); foreach (var acceptCharset in sortedAcceptCharsetHeaders) { var charset = acceptCharset.Value; if (!string.IsNullOrWhiteSpace(charset)) { var encoding = SupportedEncodings.FirstOrDefault( supportedEncoding => charset.Equals(supportedEncoding.WebName, StringComparison.OrdinalIgnoreCase) || charset.Equals("*", StringComparison.OrdinalIgnoreCase)); if (encoding != null) { return(encoding); } } } } return(null); }
public virtual IOutputFormatter SelectFormatter(OutputFormatterContext formatterContext, IEnumerable <IOutputFormatter> formatters) { var incomingAcceptHeader = HeaderParsingHelpers.GetAcceptHeaders( formatterContext.ActionContext.HttpContext.Request.Accept); var sortedAcceptHeaders = SortMediaTypeWithQualityHeaderValues(incomingAcceptHeader) .Where(header => header.Quality != HttpHeaderUtilitites.NoMatch) .ToArray(); IOutputFormatter selectedFormatter = null; if (ContentTypes == null || ContentTypes.Count == 0) { // Select based on sorted accept headers. selectedFormatter = SelectFormatterUsingSortedAcceptHeaders( formatterContext, formatters, sortedAcceptHeaders); if (selectedFormatter == null) { var requestContentType = formatterContext.ActionContext.HttpContext.Request.ContentType; // No formatter found based on accept headers, fall back on request contentType. MediaTypeHeaderValue incomingContentType = null; MediaTypeHeaderValue.TryParse(requestContentType, out incomingContentType); // In case the incomingContentType is null (as can be the case with get requests), // we need to pick the first formatter which // can support writing this type. var contentTypes = new[] { incomingContentType }; selectedFormatter = SelectFormatterUsingAnyAcceptableContentType( formatterContext, formatters, contentTypes); // This would be the case when no formatter could write the type base on the // accept headers and the request content type. Fallback on type based match. if (selectedFormatter == null) { foreach (var formatter in formatters) { var supportedContentTypes = formatter.GetSupportedContentTypes( formatterContext.DeclaredType, formatterContext.Object?.GetType(), contentType: null); if (formatter.CanWriteResult(formatterContext, supportedContentTypes?.FirstOrDefault())) { return(formatter); } } } } } else if (ContentTypes.Count == 1) { // There is only one value that can be supported. selectedFormatter = SelectFormatterUsingAnyAcceptableContentType( formatterContext, formatters, ContentTypes); } else { // Filter and remove accept headers which cannot support any of the user specified content types. var filteredAndSortedAcceptHeaders = sortedAcceptHeaders .Where(acceptHeader => ContentTypes .Any(contentType => contentType.IsSubsetOf(acceptHeader))) .ToArray(); if (filteredAndSortedAcceptHeaders.Length > 0) { selectedFormatter = SelectFormatterUsingSortedAcceptHeaders( formatterContext, formatters, filteredAndSortedAcceptHeaders); } 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); }