// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.Threading;
using System.Web.Http;
using System.Web.Http.Dependencies;
using System.Web.Http.Hosting;
using System.Web.Http.Properties;
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");
}
return request.GetProperty(HttpPropertyKeys.HttpConfigurationKey);
}
///
/// 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))
{
result = request.GetConfiguration().DependencyResolver.BeginScope();
request.Properties[HttpPropertyKeys.DependencyScope] = result;
request.RegisterForDispose(result);
}
return result;
}
///
/// 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);
}
///
/// 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");
}
return request.GetProperty(HttpPropertyKeys.HttpRouteDataKey);
}
private static T GetProperty(this HttpRequestMessage request, string key)
{
T value;
request.Properties.TryGetValue(key, out value);
return value;
}
///
/// 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 that 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 that 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 .
[SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Caller will dispose")]
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;
// Run content negotiation
ContentNegotiationResult result = contentNegotiator.Negotiate(typeof(T), request, formatters);
if (result == null)
{
// no result from content negotiation indicates that 406 should be sent.
return new HttpResponseMessage
{
StatusCode = HttpStatusCode.NotAcceptable,
RequestMessage = request,
};
}
else
{
MediaTypeHeaderValue mediaType = result.MediaType;
return new HttpResponseMessage
{
Content = new ObjectContent(value, result.Formatter, mediaType != null ? mediaType.ToString() : null),
StatusCode = statusCode,
RequestMessage = request
};
}
}
///
/// 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 .
[SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Caller will dispose")]
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");
}
HttpResponseMessage response = request.CreateResponse(statusCode);
// TODO pass in full mediaType when OC gets the right ctor overload.
string mediaTypeValue = mediaType != null ? mediaType.MediaType : null;
response.Content = new ObjectContent(value, formatter, mediaTypeValue);
return response;
}
///
/// 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;
if (!request.Properties.TryGetValue(HttpPropertyKeys.DisposableRequestResourcesKey, out trackedResources))
{
trackedResources = new List();
request.Properties[HttpPropertyKeys.DisposableRequestResourcesKey] = trackedResources;
}
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))
{
correlationId = Guid.NewGuid();
request.Properties.Add(HttpPropertyKeys.RequestCorrelationKey, correlationId);
}
return correlationId;
}
}
}