// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Dependencies;
using System.Web.Http.Hosting;
using System.Web.Http.ModelBinding;
using System.Web.Http.Properties;
using System.Web.Http.Results;
using System.Web.Http.Routing;
namespace System.Net.Http
{
///
/// Provides extension methods for the class.
///
[EditorBrowsable(EditorBrowsableState.Never)]
public static class HttpRequestMessageExtensions
{
///
/// Gets the for the given request.
///
/// The HTTP request.
/// The .
public static HttpConfiguration GetConfiguration(this HttpRequestMessage request)
{
if (request == null)
{
throw Error.ArgumentNull("request");
}
HttpRequestContext requestContext = GetRequestContext(request);
if (requestContext != null)
{
return requestContext.Configuration;
}
return request.LegacyGetConfiguration();
}
internal static HttpConfiguration LegacyGetConfiguration(this HttpRequestMessage request)
{
return request.GetProperty(HttpPropertyKeys.HttpConfigurationKey);
}
///
/// Sets the for the given request.
///
/// The HTTP request.
/// The to set.
public static void SetConfiguration(this HttpRequestMessage request, HttpConfiguration configuration)
{
if (request == null)
{
throw Error.ArgumentNull("request");
}
if (configuration == null)
{
throw Error.ArgumentNull("configuration");
}
HttpRequestContext requestContext = GetRequestContext(request);
if (requestContext != null)
{
requestContext.Configuration = configuration;
}
request.Properties[HttpPropertyKeys.HttpConfigurationKey] = configuration;
}
///
/// Gets the dependency resolver scope associated with this .
/// Services which are retrieved from this scope will be released when the request is
/// cleaned up by the framework.
///
/// The HTTP request.
/// The for the given request.
public static IDependencyScope GetDependencyScope(this HttpRequestMessage request)
{
if (request == null)
{
throw Error.ArgumentNull("request");
}
IDependencyScope result;
if (!request.Properties.TryGetValue(HttpPropertyKeys.DependencyScope, out result))
{
IDependencyResolver dependencyResolver = request.GetConfiguration().DependencyResolver;
result = dependencyResolver.BeginScope();
if (result == null)
{
throw Error.InvalidOperation(SRResources.DependencyResolver_BeginScopeReturnsNull, dependencyResolver.GetType().Name);
}
request.Properties[HttpPropertyKeys.DependencyScope] = result;
request.RegisterForDispose(result);
}
return result;
}
/// Gets the associated with this request.
/// The HTTP request.
/// The associated with this request.
public static HttpRequestContext GetRequestContext(this HttpRequestMessage request)
{
if (request == null)
{
throw Error.ArgumentNull("request");
}
return request.GetProperty(HttpPropertyKeys.RequestContextKey);
}
/// Gets an associated with this request.
/// The HTTP request.
/// The to associate with this request.
public static void SetRequestContext(this HttpRequestMessage request, HttpRequestContext context)
{
if (request == null)
{
throw Error.ArgumentNull("request");
}
if (context == null)
{
throw Error.ArgumentNull("context");
}
request.Properties[HttpPropertyKeys.RequestContextKey] = context;
}
///
/// Gets the for the given request or null if not available.
///
/// The HTTP request.
/// The or null.
public static SynchronizationContext GetSynchronizationContext(this HttpRequestMessage request)
{
if (request == null)
{
throw Error.ArgumentNull("request");
}
return request.GetProperty(HttpPropertyKeys.SynchronizationContextKey);
}
internal static void SetSynchronizationContext(this HttpRequestMessage request, SynchronizationContext synchronizationContext)
{
if (request == null)
{
throw Error.ArgumentNull("request");
}
request.Properties[HttpPropertyKeys.SynchronizationContextKey] = synchronizationContext;
}
///
/// Gets the current or null if not available.
///
/// The HTTP request.
/// The or null.
public static X509Certificate2 GetClientCertificate(this HttpRequestMessage request)
{
if (request == null)
{
throw Error.ArgumentNull("request");
}
HttpRequestContext requestContext = GetRequestContext(request);
if (requestContext != null)
{
return requestContext.ClientCertificate;
}
return request.LegacyGetClientCertificate();
}
internal static X509Certificate2 LegacyGetClientCertificate(this HttpRequestMessage request)
{
X509Certificate2 result = null;
if (!request.Properties.TryGetValue(HttpPropertyKeys.ClientCertificateKey, out result))
{
// now let us get out the delegate and try to invoke it
Func retrieveCertificate;
if (request.Properties.TryGetValue(HttpPropertyKeys.RetrieveClientCertificateDelegateKey, out retrieveCertificate))
{
result = retrieveCertificate(request);
if (result != null)
{
request.Properties.Add(HttpPropertyKeys.ClientCertificateKey, result);
}
}
}
return result;
}
///
/// Gets the for the given request or null if not available.
///
/// The HTTP request.
/// The or null.
public static IHttpRouteData GetRouteData(this HttpRequestMessage request)
{
if (request == null)
{
throw Error.ArgumentNull("request");
}
HttpRequestContext requestContext = GetRequestContext(request);
if (requestContext != null)
{
return requestContext.RouteData;
}
return request.LegacyGetRouteData();
}
internal static IHttpRouteData LegacyGetRouteData(this HttpRequestMessage request)
{
return request.GetProperty(HttpPropertyKeys.HttpRouteDataKey);
}
///
/// Sets the for the given request.
///
/// The HTTP request.
/// The HTTP route data.
public static void SetRouteData(this HttpRequestMessage request, IHttpRouteData routeData)
{
if (request == null)
{
throw Error.ArgumentNull("request");
}
if (routeData == null)
{
throw Error.ArgumentNull("routeData");
}
HttpRequestContext requestContext = GetRequestContext(request);
if (requestContext != null)
{
requestContext.RouteData = routeData;
}
request.Properties[HttpPropertyKeys.HttpRouteDataKey] = routeData;
}
///
/// Gets the selected for the given request or null if not available.
///
/// The HTTP request.
/// The or null.
public static HttpActionDescriptor GetActionDescriptor(this HttpRequestMessage request)
{
if (request == null)
{
throw Error.ArgumentNull("request");
}
return request.GetProperty(HttpPropertyKeys.HttpActionDescriptorKey);
}
internal static void SetActionDescriptor(this HttpRequestMessage request, HttpActionDescriptor actionDescriptor)
{
if (request == null)
{
throw Error.ArgumentNull("request");
}
request.Properties[HttpPropertyKeys.HttpActionDescriptorKey] = actionDescriptor;
}
private static T GetProperty(this HttpRequestMessage request, string key)
{
T value;
request.Properties.TryGetValue(key, out value);
return value;
}
///
/// Helper method for creating an message with a "416 (Requested Range Not Satisfiable)" status code.
/// This response can be used in combination with the to indicate that the requested range or
/// ranges do not overlap with the current resource. The response contains a "Content-Range" header indicating the valid upper and lower
/// bounds for requested ranges.
///
/// The request.
/// An instance, typically thrown by a
/// instance.
/// An 416 (Requested Range Not Satisfiable) error response with a Content-Range header indicating the valid range.
[SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Caller will dispose")]
public static HttpResponseMessage CreateErrorResponse(this HttpRequestMessage request, InvalidByteRangeException invalidByteRangeException)
{
if (invalidByteRangeException == null)
{
throw Error.ArgumentNull("invalidByteRangeException");
}
HttpResponseMessage rangeNotSatisfiableResponse = request.CreateErrorResponse(HttpStatusCode.RequestedRangeNotSatisfiable, invalidByteRangeException);
rangeNotSatisfiableResponse.Content.Headers.ContentRange = invalidByteRangeException.ContentRange;
return rangeNotSatisfiableResponse;
}
///
/// Helper method that performs content negotiation and creates a representing an error
/// with an instance of wrapping an with message .
/// If no formatter is found, this method returns a response with status 406 NotAcceptable.
///
///
/// This method requires that has been associated with an instance of
/// .
///
/// The request.
/// The status code of the created response.
/// The error message.
/// An error response with error message and status code .
public static HttpResponseMessage CreateErrorResponse(this HttpRequestMessage request, HttpStatusCode statusCode, string message)
{
return request.CreateErrorResponse(statusCode, new HttpError(message));
}
///
/// Helper method that performs content negotiation and creates a representing an error
/// with an instance of wrapping an with message
/// and message detail .If no formatter is found, this method returns a response with
/// status 406 NotAcceptable.
///
///
/// This method requires that has been associated with an instance of
/// .
///
/// The request.
/// The status code of the created response.
/// The error message. This message will always be seen by clients.
/// The error message detail. This message will only be seen by clients if we should include error detail.
/// An error response with error message and message detail
/// and status code .
internal static HttpResponseMessage CreateErrorResponse(this HttpRequestMessage request, HttpStatusCode statusCode, string message, string messageDetail)
{
return request.CreateErrorResponse(statusCode, includeErrorDetail => includeErrorDetail ? new HttpError(message, messageDetail) : new HttpError(message));
}
///
/// Helper method that performs content negotiation and creates a representing an error
/// with an instance of wrapping an with error message
/// for exception . If no formatter is found, this method returns a response with status 406 NotAcceptable.
///
///
/// This method requires that has been associated with an instance of
/// .
///
/// The request.
/// The status code of the created response.
/// The error message.
/// The exception.
/// An error response for with error message
/// and status code .
public static HttpResponseMessage CreateErrorResponse(this HttpRequestMessage request, HttpStatusCode statusCode, string message, Exception exception)
{
if (request == null)
{
throw Error.ArgumentNull("request");
}
return request.CreateErrorResponse(statusCode, includeErrorDetail => new HttpError(exception, includeErrorDetail) { Message = message });
}
///
/// Helper method that performs content negotiation and creates a representing an error
/// with an instance of wrapping an for exception .
/// If no formatter is found, this method returns a response with status 406 NotAcceptable.
///
///
/// This method requires that has been associated with an instance of
/// .
///
/// The request.
/// The status code of the created response.
/// The exception.
/// An error response for with status code .
public static HttpResponseMessage CreateErrorResponse(this HttpRequestMessage request, HttpStatusCode statusCode, Exception exception)
{
if (request == null)
{
throw Error.ArgumentNull("request");
}
return request.CreateErrorResponse(statusCode, includeErrorDetail => new HttpError(exception, includeErrorDetail));
}
///
/// Helper method that performs content negotiation and creates a representing an error
/// with an instance of wrapping an for model state .
/// If no formatter is found, this method returns a response with status 406 NotAcceptable.
///
///
/// This method requires that has been associated with an instance of
/// .
///
/// The request.
/// The status code of the created response.
/// The model state.
/// An error response for with status code .
public static HttpResponseMessage CreateErrorResponse(this HttpRequestMessage request, HttpStatusCode statusCode, ModelStateDictionary modelState)
{
if (request == null)
{
throw Error.ArgumentNull("request");
}
return request.CreateErrorResponse(statusCode, includeErrorDetail => new HttpError(modelState, includeErrorDetail));
}
///
/// Helper method that performs content negotiation and creates a representing an error
/// with an instance of wrapping as the content. If no formatter
/// is found, this method returns a response with status 406 NotAcceptable.
///
///
/// This method requires that has been associated with an instance of
/// .
///
/// The request.
/// The status code of the created response.
/// The error to wrap.
/// An error response wrapping with status code .
public static HttpResponseMessage CreateErrorResponse(this HttpRequestMessage request, HttpStatusCode statusCode, HttpError error)
{
if (request == null)
{
throw Error.ArgumentNull("request");
}
return request.CreateErrorResponse(statusCode, includeErrorDetail => error);
}
private static HttpResponseMessage CreateErrorResponse(this HttpRequestMessage request, HttpStatusCode statusCode, Func errorCreator)
{
HttpConfiguration configuration = request.GetConfiguration();
HttpError error = errorCreator(request.ShouldIncludeErrorDetail());
// CreateErrorResponse should never fail, even if there is no configuration associated with the request
// In that case, use the default HttpConfiguration to con-neg the response media type
if (configuration == null)
{
using (HttpConfiguration defaultConfig = new HttpConfiguration())
{
return request.CreateResponse(statusCode, error, defaultConfig);
}
}
else
{
return request.CreateResponse(statusCode, error, configuration);
}
}
///
/// Helper method that performs content negotiation and creates a with an instance
/// of as the content and as the status code
/// if a formatter can be found. If no formatter is found, this method returns a response with status 406 NotAcceptable.
/// This forwards the call to with
/// status code and a null configuration.
///
///
/// This method requires that has been associated with an instance of
/// .
///
/// The type of the value.
/// The request.
/// The value to wrap. Can be null.
/// A response wrapping with status code.
public static HttpResponseMessage CreateResponse(this HttpRequestMessage request, T value)
{
return request.CreateResponse(HttpStatusCode.OK, value, configuration: null);
}
///
/// Helper method that performs content negotiation and creates a with an instance
/// of as the content if a formatter can be found. If no formatter is found, this
/// method returns a response with status 406 NotAcceptable. This forwards the call to
/// with a null
/// configuration.
///
///
/// This method requires that has been associated with an instance of
/// .
///
/// The type of the value.
/// The request.
/// The status code of the created response.
/// The value to wrap. Can be null.
/// A response wrapping with .
public static HttpResponseMessage CreateResponse(this HttpRequestMessage request, HttpStatusCode statusCode, T value)
{
return request.CreateResponse(statusCode, value, configuration: null);
}
///
/// Helper method that performs content negotiation and creates a with an instance
/// of as the content if a formatter can be found. If no formatter is found, this
/// method returns a response with status 406 NotAcceptable.
///
///
/// This method will use the provided or it will get the
/// instance associated with .
///
/// The type of the value.
/// The request.
/// The status code of the created response.
/// The value to wrap. Can be null.
/// The configuration to use. Can be null.
/// A response wrapping with .
public static HttpResponseMessage CreateResponse(this HttpRequestMessage request, HttpStatusCode statusCode, T value, HttpConfiguration configuration)
{
if (request == null)
{
throw Error.ArgumentNull("request");
}
configuration = configuration ?? request.GetConfiguration();
if (configuration == null)
{
throw Error.InvalidOperation(SRResources.HttpRequestMessageExtensions_NoConfiguration);
}
IContentNegotiator contentNegotiator = configuration.Services.GetContentNegotiator();
if (contentNegotiator == null)
{
throw Error.InvalidOperation(SRResources.HttpRequestMessageExtensions_NoContentNegotiator, typeof(IContentNegotiator).FullName);
}
IEnumerable formatters = configuration.Formatters;
return NegotiatedContentResult.Execute(statusCode, value, contentNegotiator, request, formatters);
}
///
/// Helper method that creates a with an instance containing the provided
/// . The given is used to find an instance of .
///
/// The type of the value.
/// The request.
/// The status code of the created response.
/// The value to wrap. Can be null.
/// The media type used to look up an instance of .
/// Thrown if the does not have an associated
/// instance or if the configuration does not have a formatter matching .
/// A response wrapping with .
public static HttpResponseMessage CreateResponse(this HttpRequestMessage request, HttpStatusCode statusCode, T value, string mediaType)
{
return request.CreateResponse(statusCode, value, new MediaTypeHeaderValue(mediaType));
}
///
/// Helper method that creates a with an instance containing the provided
/// . The given is used to find an instance of .
///
/// The type of the value.
/// The request.
/// The status code of the created response.
/// The value to wrap. Can be null.
/// The media type used to look up an instance of .
/// Thrown if the does not have an associated
/// instance or if the configuration does not have a formatter matching .
/// A response wrapping with .
public static HttpResponseMessage CreateResponse(this HttpRequestMessage request, HttpStatusCode statusCode, T value, MediaTypeHeaderValue mediaType)
{
if (request == null)
{
throw Error.ArgumentNull("request");
}
if (mediaType == null)
{
throw Error.ArgumentNull("mediaType");
}
HttpConfiguration configuration = request.GetConfiguration();
if (configuration == null)
{
throw Error.InvalidOperation(SRResources.HttpRequestMessageExtensions_NoConfiguration);
}
MediaTypeFormatter formatter = configuration.Formatters.FindWriter(typeof(T), mediaType);
if (formatter == null)
{
throw Error.InvalidOperation(SRResources.HttpRequestMessageExtensions_NoMatchingFormatter, mediaType, typeof(T).Name);
}
return request.CreateResponse(statusCode, value, formatter, mediaType);
}
///
/// Helper method that creates a with an instance containing the provided
/// and the given .
///
/// The type of the value.
/// The request.
/// The status code of the created response.
/// The value to wrap. Can be null.
/// The formatter to use.
/// A response wrapping with .
public static HttpResponseMessage CreateResponse(this HttpRequestMessage request, HttpStatusCode statusCode, T value, MediaTypeFormatter formatter)
{
return request.CreateResponse(statusCode, value, formatter, (MediaTypeHeaderValue)null);
}
///
/// Helper method that creates a with an instance containing the provided
/// and the given .
///
/// The type of the value.
/// The request.
/// The status code of the created response.
/// The value to wrap. Can be null.
/// The formatter to use.
/// The media type override to set on the response's content. Can be null.
/// A response wrapping with .
public static HttpResponseMessage CreateResponse(this HttpRequestMessage request, HttpStatusCode statusCode, T value, MediaTypeFormatter formatter, string mediaType)
{
MediaTypeHeaderValue mediaTypeHeader = mediaType != null ? new MediaTypeHeaderValue(mediaType) : null;
return request.CreateResponse(statusCode, value, formatter, mediaTypeHeader);
}
///
/// Helper method that creates a with an instance containing the provided
/// and the given .
///
/// The type of the value.
/// The request.
/// The status code of the created response.
/// The value to wrap. Can be null.
/// The formatter to use.
/// The media type override to set on the response's content. Can be null.
/// A response wrapping with .
public static HttpResponseMessage CreateResponse(this HttpRequestMessage request, HttpStatusCode statusCode, T value, MediaTypeFormatter formatter, MediaTypeHeaderValue mediaType)
{
if (request == null)
{
throw Error.ArgumentNull("request");
}
if (formatter == null)
{
throw Error.ArgumentNull("formatter");
}
return FormattedContentResult.Execute(statusCode, value, formatter, mediaType, request);
}
///
/// Adds the given to a list of resources that will be disposed by a host once
/// the is disposed.
///
/// The request controlling the lifecycle of .
/// The resource to dispose when is being disposed. Can be null.
public static void RegisterForDispose(this HttpRequestMessage request, IDisposable resource)
{
if (request == null)
{
throw Error.ArgumentNull("request");
}
if (resource == null)
{
return;
}
List trackedResources = GetRegisteredResourcesForDispose(request);
trackedResources.Add(resource);
}
///
/// Adds the given to a list of resources that will be disposed by a host once
/// the is disposed.
///
/// The request controlling the lifecycle of .
/// The resources to dispose when is being disposed. Can be null.
public static void RegisterForDispose(this HttpRequestMessage request, IEnumerable resources)
{
if (request == null)
{
throw Error.ArgumentNull("request");
}
if (resources == null)
{
throw Error.ArgumentNull("resources");
}
List trackedResources = GetRegisteredResourcesForDispose(request);
foreach (IDisposable resource in resources)
{
if (resource != null)
{
trackedResources.Add(resource);
}
}
}
///
/// Disposes of all tracked resources associated with the which were added via the
/// method.
///
/// The request.
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "We want to ignore all exceptions.")]
public static void DisposeRequestResources(this HttpRequestMessage request)
{
if (request == null)
{
throw Error.ArgumentNull("request");
}
List resourcesToDispose;
if (request.Properties.TryGetValue(HttpPropertyKeys.DisposableRequestResourcesKey, out resourcesToDispose))
{
foreach (IDisposable resource in resourcesToDispose)
{
try
{
resource.Dispose();
}
catch
{
// ignore exceptions
}
}
resourcesToDispose.Clear();
}
}
///
/// Retrieves the which has been assigned as the
/// correlation id associated with the given .
/// The value will be created and set the first time this method is called.
///
/// The
/// The associated with that request.
public static Guid GetCorrelationId(this HttpRequestMessage request)
{
if (request == null)
{
throw Error.ArgumentNull("request");
}
Guid correlationId;
if (!request.Properties.TryGetValue(HttpPropertyKeys.RequestCorrelationKey, out correlationId))
{
// Check if the Correlation Manager ID is set; otherwise fallback to creating a new GUID
correlationId = Trace.CorrelationManager.ActivityId;
if (correlationId == Guid.Empty)
{
correlationId = Guid.NewGuid();
}
request.Properties.Add(HttpPropertyKeys.RequestCorrelationKey, correlationId);
}
return correlationId;
}
///
/// Retrieves the parsed query string as a collection of key-value pairs.
///
/// The
/// The query string as a collection of key-value pairs.
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "NameValuePairsValueProvider takes an IEnumerable>")]
public static IEnumerable> GetQueryNameValuePairs(this HttpRequestMessage request)
{
if (request == null)
{
throw Error.ArgumentNull("request");
}
Uri uri = request.RequestUri;
// Unit tests may not always provide a Uri in the request
if (uri == null || String.IsNullOrEmpty(uri.Query))
{
return Enumerable.Empty>();
}
IEnumerable> queryStringData;
string cachedQueryString;
request.Properties.TryGetValue>>(HttpPropertyKeys.RequestQueryNameValuePairsKey, out queryStringData);
request.Properties.TryGetValue(HttpPropertyKeys.CachedRequestQueryKey, out cachedQueryString);
if (queryStringData == null ||
(cachedQueryString != null && !Object.ReferenceEquals(cachedQueryString, uri.Query ?? String.Empty)))
{
FormDataCollection formData = new FormDataCollection(uri);
// The ToArray call here avoids reparsing the query string, and avoids storing an Enumerator state
// machine in the request state.
queryStringData = formData.GetJQueryNameValuePairs().ToArray();
request.Properties[HttpPropertyKeys.RequestQueryNameValuePairsKey] = queryStringData;
request.Properties[HttpPropertyKeys.CachedRequestQueryKey] = uri.Query ?? String.Empty;
}
return queryStringData;
}
///
/// Retrieves the instance associated with this request.
///
/// The .
/// The instance associated with this request.
public static UrlHelper GetUrlHelper(this HttpRequestMessage request)
{
if (request == null)
{
throw Error.ArgumentNull("request");
}
HttpRequestContext requestContext = GetRequestContext(request);
if (requestContext != null)
{
return requestContext.Url;
}
return new UrlHelper(request);
}
///
/// Gets a value indicating whether the request originates from a local address or not.
///
/// The HTTP request.
/// if the request originates from a local address; otherwise, .
public static bool IsLocal(this HttpRequestMessage request)
{
if (request == null)
{
throw Error.ArgumentNull("request");
}
HttpRequestContext requestContext = GetRequestContext(request);
if (requestContext != null)
{
return requestContext.IsLocal;
}
return request.LegacyIsLocal();
}
internal static bool LegacyIsLocal(this HttpRequestMessage request)
{
Lazy isLocal = request.GetProperty>(HttpPropertyKeys.IsLocalKey);
return isLocal == null ? false : isLocal.Value;
}
///
/// Gets a value indicating whether the request originates from a batch.
///
/// The HTTP request.
/// if the request originates from a batch; otherwise, .
public static bool IsBatchRequest(this HttpRequestMessage request)
{
if (request == null)
{
throw Error.ArgumentNull("request");
}
return request.GetProperty(HttpPropertyKeys.IsBatchRequest);
}
///
/// Gets a value indicating whether error details, such as exception messages and stack traces, should be included for this HTTP request.
///
/// The HTTP request.
/// if the error details are to be included; otherwise, .
public static bool ShouldIncludeErrorDetail(this HttpRequestMessage request)
{
if (request == null)
{
throw Error.ArgumentNull("request");
}
HttpRequestContext requestContext = GetRequestContext(request);
if (requestContext != null)
{
return requestContext.IncludeErrorDetail;
}
return request.LegacyShouldIncludeErrorDetail();
}
internal static bool LegacyShouldIncludeErrorDetail(this HttpRequestMessage request)
{
HttpConfiguration configuration = request.GetConfiguration();
IncludeErrorDetailPolicy includeErrorDetailPolicy = IncludeErrorDetailPolicy.Default;
if (configuration != null)
{
includeErrorDetailPolicy = configuration.IncludeErrorDetailPolicy;
}
switch (includeErrorDetailPolicy)
{
case IncludeErrorDetailPolicy.Default:
Lazy includeErrorDetail = request.GetProperty>(HttpPropertyKeys.IncludeErrorDetailKey);
if (includeErrorDetail != null)
{
// If we are on webhost and the user hasn't changed the IncludeErrorDetailPolicy
// look up into the Request's property bag else default to LocalOnly.
return includeErrorDetail.Value;
}
goto case IncludeErrorDetailPolicy.LocalOnly;
case IncludeErrorDetailPolicy.LocalOnly:
return request.IsLocal();
case IncludeErrorDetailPolicy.Always:
return true;
case IncludeErrorDetailPolicy.Never:
default:
return false;
}
}
///
/// Gets the collection of resources registered for dispose once the is disposed.
///
/// The request.
/// A collection of resources registered for dispose.
public static IEnumerable GetResourcesForDisposal(this HttpRequestMessage request)
{
if (request == null)
{
throw Error.ArgumentNull("request");
}
return GetRegisteredResourcesForDispose(request);
}
private static List GetRegisteredResourcesForDispose(HttpRequestMessage request)
{
List registeredResourcesForDispose;
if (!request.Properties.TryGetValue(HttpPropertyKeys.DisposableRequestResourcesKey, out registeredResourcesForDispose))
{
registeredResourcesForDispose = new List();
request.Properties[HttpPropertyKeys.DisposableRequestResourcesKey] = registeredResourcesForDispose;
}
return registeredResourcesForDispose;
}
}
}