Imported Upstream version 3.6.0

Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
This commit is contained in:
Jo Shields
2014-08-13 10:39:27 +01:00
commit a575963da9
50588 changed files with 8155799 additions and 0 deletions

View File

@ -0,0 +1,46 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Web.Http.Dispatcher;
using System.Web.Http.WebHost;
using System.Web.Http.WebHost.Routing;
using System.Web.Routing;
namespace System.Web.Http
{
/// <summary>
/// Provides a global <see cref="T:System.Web.Http.HttpConfiguration"/> for ASP applications.
/// </summary>
public static class GlobalConfiguration
{
private static Lazy<HttpConfiguration> _configuration = new Lazy<HttpConfiguration>(
() =>
{
HttpConfiguration config = new HttpConfiguration(new HostedHttpRouteCollection(RouteTable.Routes));
config.Services.Replace(typeof(IAssembliesResolver), new WebHostAssembliesResolver());
config.Services.Replace(typeof(IHttpControllerTypeResolver), new WebHostHttpControllerTypeResolver());
return config;
});
private static Lazy<HttpControllerDispatcher> _dispatcher = new Lazy<HttpControllerDispatcher>(
() =>
{
return new HttpControllerDispatcher(_configuration.Value);
});
/// <summary>
/// Gets the global <see cref="T:System.Web.Http.HttpConfiguration"/>.
/// </summary>
public static HttpConfiguration Configuration
{
get { return _configuration.Value; }
}
/// <summary>
/// Gets the global <see cref="T:System.Web.Http.Dispatcher.HttpControllerDispatcher"/>.
/// </summary>
public static HttpControllerDispatcher Dispatcher
{
get { return _dispatcher.Value; }
}
}
}

View File

@ -0,0 +1,10 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Diagnostics.CodeAnalysis;
[assembly: SuppressMessage("Microsoft.Design", "CA2210:AssembliesShouldHaveValidStrongNames", Justification = "These assemblies are delay-signed.")]
[assembly: SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Justification = "Classes are grouped logically for user clarity.", Scope = "Namespace", Target = "System.Web.Http.WebHost")]
[assembly: SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Justification = "Classes are here so that they're shared with the main DLL's namespace", Scope = "Namespace", Target = "System.Web.Http")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Scope = "member", Target = "System.Web.Http.GlobalConfiguration.#.cctor()")]
[assembly: SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Scope = "namespace", Target = "System.Web.Http.WebHost.Routing", Justification = "This is the most logical namespace for this type.")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Scope = "member", Target = "System.Web.Http.WebHost.HttpControllerHandler.#.cctor()", Justification = "HttpServer is disposed by HttpMessageInvoker.")]

View File

@ -0,0 +1,400 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Configuration;
using System.Web.Http.Hosting;
using System.Web.Http.Routing;
using System.Web.Http.WebHost.Properties;
using System.Web.Http.WebHost.Routing;
using System.Web.Routing;
namespace System.Web.Http.WebHost
{
/// <summary>
/// A <see cref="IHttpAsyncHandler"/> that passes ASP.NET requests into the <see cref="HttpServer"/>
/// pipeline and write the result back.
/// </summary>
public class HttpControllerHandler : IHttpAsyncHandler
{
internal static readonly string HttpContextBaseKey = "MS_HttpContext";
private static readonly Lazy<Action<HttpContextBase>> _suppressRedirectAction =
new Lazy<Action<HttpContextBase>>(
() =>
{
// If the behavior is explicitly disabled, do nothing
if (!SuppressFormsAuthRedirectModule.GetEnabled(WebConfigurationManager.AppSettings))
{
return httpContext => { };
}
var srPropertyInfo = typeof(HttpResponseBase).GetProperty(SuppressFormsAuthRedirectModule.SuppressFormsAuthenticationRedirectPropertyName, BindingFlags.Instance | BindingFlags.Public);
// Use the property in .NET 4.5 if available
if (srPropertyInfo != null)
{
Action<HttpResponseBase, bool> setter = (Action<HttpResponseBase, bool>)Delegate.CreateDelegate(typeof(Action<HttpResponseBase, bool>), srPropertyInfo.GetSetMethod(), throwOnBindFailure: false);
return httpContext => setter(httpContext.Response, true);
}
// Use SuppressFormsAuthRedirectModule to revert the redirection on .NET 4.0
return httpContext => SuppressFormsAuthRedirectModule.DisableAuthenticationRedirect(httpContext);
});
private static readonly Lazy<HttpMessageInvoker> _server =
new Lazy<HttpMessageInvoker>(
() =>
{
HttpServer server = new HttpServer(GlobalConfiguration.Configuration, GlobalConfiguration.Dispatcher);
return new HttpMessageInvoker(server);
});
private IHttpRouteData _routeData;
/// <summary>
/// Initializes a new instance of the <see cref="HttpControllerHandler"/> class.
/// </summary>
/// <param name="routeData">The route data.</param>
public HttpControllerHandler(RouteData routeData)
{
if (routeData == null)
{
throw Error.ArgumentNull("routeData");
}
_routeData = new HostedHttpRouteData(routeData);
}
/// <summary>
/// Gets a value indicating whether another request can use the <see cref="T:System.Web.IHttpHandler"/> instance.
/// </summary>
/// <returns>true if the <see cref="T:System.Web.IHttpHandler"/> instance is reusable; otherwise, false.</returns>
bool IHttpHandler.IsReusable
{
get { return IsReusable; }
}
/// <summary>
/// Gets a value indicating whether another request can use the <see cref="T:System.Web.IHttpHandler"/> instance.
/// </summary>
/// <returns>true if the <see cref="T:System.Web.IHttpHandler"/> instance is reusable; otherwise, false.</returns>
protected virtual bool IsReusable
{
get { return false; }
}
/// <summary>
/// Processes the request.
/// </summary>
/// <param name="httpContext">The HTTP context base.</param>
void IHttpHandler.ProcessRequest(HttpContext httpContext)
{
ProcessRequest(new HttpContextWrapper(httpContext));
}
/// <summary>
/// Begins processing the request.
/// </summary>
/// <param name="httpContext">The HTTP context.</param>
/// <param name="callback">The callback.</param>
/// <param name="state">The state.</param>
/// <returns>An <see cref="IAsyncResult"/> that contains information about the status of the process. </returns>
IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, object state)
{
return BeginProcessRequest(new HttpContextWrapper(httpContext), callback, state);
}
/// <summary>
/// Provides an asynchronous process End method when the process ends.
/// </summary>
/// <param name="result">An <see cref="T:System.IAsyncResult"/> that contains information about the status of the process.</param>
void IHttpAsyncHandler.EndProcessRequest(IAsyncResult result)
{
EndProcessRequest(result);
}
/// <summary>
/// Processes the request.
/// </summary>
/// <param name="httpContextBase">The HTTP context base.</param>
protected virtual void ProcessRequest(HttpContextBase httpContextBase)
{
throw Error.NotSupported(SRResources.ProcessRequestNotSupported, typeof(HttpControllerHandler));
}
/// <summary>
/// Begins the process request.
/// </summary>
/// <param name="httpContextBase">The HTTP context base.</param>
/// <param name="callback">The callback.</param>
/// <param name="state">The state.</param>
/// <returns>An <see cref="IAsyncResult"/> that contains information about the status of the process. </returns>
[SuppressMessage("Microsoft.WebAPI", "CR4001:DoNotCallProblematicMethodsOnTask", Justification = "This is commented in great details.")]
[SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Object gets passed to a task")]
protected virtual IAsyncResult BeginProcessRequest(HttpContextBase httpContextBase, AsyncCallback callback, object state)
{
HttpRequestMessage request = httpContextBase.GetHttpRequestMessage() ?? ConvertRequest(httpContextBase);
// Add route data
request.Properties[HttpPropertyKeys.HttpRouteDataKey] = _routeData;
Task responseBodyTask = _server.Value.SendAsync(request, CancellationToken.None)
.Then(response => ConvertResponse(httpContextBase, response, request))
.FastUnwrap();
TaskWrapperAsyncResult result = new TaskWrapperAsyncResult(responseBodyTask, state);
if (callback != null)
{
if (result.IsCompleted)
{
// If the underlying task is already finished, from our caller's perspective this is just
// a synchronous completion. See also DevDiv #346170.
result.CompletedSynchronously = true;
callback(result);
}
else
{
// If the underlying task isn't yet finished, from our caller's perspective this will be
// an asynchronous completion. We'll use ContinueWith instead of Finally for two reasons:
//
// - Finally propagates the antecedent Task's exception, which we don't need to do here.
// Out caller will eventually call EndProcessRequest, which correctly observes the
// antecedent Task's exception anyway if it faulted.
//
// - Finally invokes the callback on the captured SynchronizationContext, which is
// unnecessary when using APM (Begin / End). APM assumes that the callback is invoked
// on an arbitrary ThreadPool thread with no SynchronizationContext set up, so
// ContinueWith gets us closer to the desired semantic.
//
// There is still a race here: the Task might complete after the IsCompleted check above,
// so the callback might be invoked on another thread concurrently with the original
// thread's call to BeginProcessRequest. But we shouldn't concern ourselves with that;
// the caller has to be prepared for that possibility and do the right thing. We also
// don't need to worry about the callback throwing since the caller should give us a
// callback which is well-behaved.
result.CompletedSynchronously = false;
responseBodyTask.ContinueWith(_ =>
{
callback(result);
});
}
}
return result;
}
/// <summary>
/// Provides an asynchronous process End method when the process ends.
/// </summary>
/// <param name="result">An <see cref="T:System.IAsyncResult"/> that contains information about the status of the process.</param>
protected virtual void EndProcessRequest(IAsyncResult result)
{
TaskWrapperAsyncResult asyncResult = (TaskWrapperAsyncResult)result;
Contract.Assert(asyncResult != null);
Task task = asyncResult.Task;
// Check task result and unwrap any exceptions
if (task.IsCanceled)
{
throw Error.OperationCanceled();
}
else if (task.IsFaulted)
{
throw task.Exception.GetBaseException();
}
}
private static void CopyHeaders(HttpHeaders from, HttpContextBase to)
{
Contract.Assert(from != null);
Contract.Assert(to != null);
foreach (var header in from)
{
string name = header.Key;
foreach (var value in header.Value)
{
to.Response.AppendHeader(name, value);
}
}
}
private static void AddHeaderToHttpRequestMessage(HttpRequestMessage httpRequestMessage, string headerName, string[] headerValues)
{
Contract.Assert(httpRequestMessage != null);
Contract.Assert(headerName != null);
Contract.Assert(headerValues != null);
if (!httpRequestMessage.Headers.TryAddWithoutValidation(headerName, headerValues))
{
httpRequestMessage.Content.Headers.TryAddWithoutValidation(headerName, headerValues);
}
}
/// <summary>
/// Converts a <see cref="HttpResponseMessage"/> to an <see cref="HttpResponseBase"/> and disposes the
/// <see cref="HttpResponseMessage"/> and <see cref="HttpRequestMessage"/> upon completion.
/// </summary>
/// <param name="httpContextBase">The HTTP context base.</param>
/// <param name="response">The response to convert.</param>
/// <param name="request">The request (which will be disposed).</param>
/// <returns>A <see cref="Task"/> representing the conversion of an <see cref="HttpResponseMessage"/> to an <see cref="HttpResponseBase"/>
/// including writing out any entity body.</returns>
internal static Task ConvertResponse(HttpContextBase httpContextBase, HttpResponseMessage response, HttpRequestMessage request)
{
Contract.Assert(httpContextBase != null);
Contract.Assert(response != null);
Contract.Assert(request != null);
HttpResponseBase httpResponseBase = httpContextBase.Response;
httpResponseBase.StatusCode = (int)response.StatusCode;
httpResponseBase.StatusDescription = response.ReasonPhrase;
httpResponseBase.TrySkipIisCustomErrors = true;
EnsureSuppressFormsAuthenticationRedirect(httpContextBase);
CopyHeaders(response.Headers, httpContextBase);
CacheControlHeaderValue cacheControl = response.Headers.CacheControl;
// TODO 335085: Consider this when coming up with our caching story
if (cacheControl == null)
{
// DevDiv2 #332323. ASP.NET by default always emits a cache-control: private header.
// However, we don't want requests to be cached by default.
// If nobody set an explicit CacheControl then explicitly set to no-cache to override the
// default behavior. This will cause the following response headers to be emitted:
// Cache-Control: no-cache
// Pragma: no-cache
// Expires: -1
httpContextBase.Response.Cache.SetCacheability(HttpCacheability.NoCache);
}
Task responseTask = null;
bool isBuffered = false;
if (response.Content != null)
{
// Select output buffering based on the kind of HttpContent.
// This is done before CopyHeaders because the ContentLength
// property getter will evaluate the content length and set
// the Content-Length header if it has not already been set.
// Doing this before CopyHeaders ensures the headers contain a
// valid Content-Length before they are copied to HttpContextBase.
// Unless HttpContextBase headers contain a positive Content-Length,
// the Transfer-Encoding for streamed output will be chunked.
isBuffered = IsOutputBufferingNecessary(response.Content);
httpResponseBase.BufferOutput = isBuffered;
CopyHeaders(response.Content.Headers, httpContextBase);
responseTask = response.Content.CopyToAsync(httpResponseBase.OutputStream);
}
else
{
responseTask = TaskHelpers.Completed();
}
return responseTask
.Catch((info) =>
{
if (isBuffered)
{
// Failure during the CopyToAsync needs to stop any partial content from
// reaching the client. If it was during a buffered write, we will give
// them InternalServerError with zero-length content.
httpResponseBase.SuppressContent = true;
httpResponseBase.Clear();
httpResponseBase.ClearContent();
httpResponseBase.ClearHeaders();
httpResponseBase.StatusCode = (int)Net.HttpStatusCode.InternalServerError;
}
else
{
// Any failure in non-buffered mode has already written out StatusCode and possibly content.
// This means the client will receive an OK but the content is incomplete.
// The proper action here is to abort the connection, but HttpResponse.Abort is a 4.5 feature.
// TODO: DevDiv bug #381233 -- call HttpResponse.Abort when it becomes available
httpResponseBase.Close();
}
// We do not propagate any errors up, or we will get the
// standard ASP.NET html page. We want empty content or
// a closed connection.
return info.Handled();
})
.Finally(
() =>
{
request.DisposeRequestResources();
request.Dispose();
response.Dispose();
});
}
/// <summary>
/// Determines whether the given <see cref="HttpContent"/> should use a buffered response.
/// </summary>
/// <param name="httpContent">The <see cref="HttpContent"/> of the response.</param>
/// <returns>A value of <c>true</c> indicates buffering should be used, otherwise a streamed response should be used.</returns>
internal static bool IsOutputBufferingNecessary(HttpContent httpContent)
{
Contract.Assert(httpContent != null);
// Any HttpContent that knows its length is presumably already buffered internally.
long? contentLength = httpContent.Headers.ContentLength;
if (contentLength.HasValue && contentLength.Value >= 0)
{
return false;
}
// Content length is null or -1 (meaning not known). Buffer any HttpContent except StreamContent.
return !(httpContent is StreamContent);
}
[SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Caller becomes owner")]
internal static HttpRequestMessage ConvertRequest(HttpContextBase httpContextBase)
{
Contract.Assert(httpContextBase != null);
HttpRequestBase requestBase = httpContextBase.Request;
HttpMethod method = HttpMethodHelper.GetHttpMethod(requestBase.HttpMethod);
Uri uri = requestBase.Url;
HttpRequestMessage request = new HttpRequestMessage(method, uri);
// TODO: Should we use GetBufferlessInputStream? Yes, as we don't need any of the parsing from ASP
request.Content = new StreamContent(requestBase.InputStream);
foreach (string headerName in requestBase.Headers)
{
string[] values = requestBase.Headers.GetValues(headerName);
AddHeaderToHttpRequestMessage(request, headerName, values);
}
// Add context to enable route lookup later on
request.Properties.Add(HttpContextBaseKey, httpContextBase);
return request;
}
/// <summary>
/// Prevents the <see cref="T:System.Web.Security.FormsAuthenticationModule"/> from altering a 401 response to 302 by
/// setting <see cref="P:System.Web.HttpResponseBase.SuppressFormsAuthenticationRedirect" /> to <c>true</c> if available.
/// </summary>
/// <param name="httpContextBase">The HTTP context base.</param>
internal static void EnsureSuppressFormsAuthenticationRedirect(HttpContextBase httpContextBase)
{
Contract.Assert(httpContextBase != null);
// Only if the response is status code is 401
if (httpContextBase.Response.StatusCode == (int)HttpStatusCode.Unauthorized)
{
_suppressRedirectAction.Value(httpContextBase);
}
}
}
}

View File

@ -0,0 +1,55 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Web.Routing;
namespace System.Web.Http.WebHost
{
/// <summary>
/// A <see cref="IRouteHandler"/> that returns instances of <see cref="HttpControllerHandler"/> that
/// can pass requests to a given <see cref="HttpServer"/> instance.
/// </summary>
public class HttpControllerRouteHandler : IRouteHandler
{
private static readonly Lazy<HttpControllerRouteHandler> _instance =
new Lazy<HttpControllerRouteHandler>(() => new HttpControllerRouteHandler(), isThreadSafe: true);
/// <summary>
/// Initializes a new instance of the <see cref="HttpControllerRouteHandler"/> class.
/// </summary>
protected HttpControllerRouteHandler()
{
}
/// <summary>
/// Gets the singleton <see cref="HttpControllerRouteHandler"/> instance.
/// </summary>
public static HttpControllerRouteHandler Instance
{
get { return _instance.Value; }
}
/// <summary>
/// Provides the object that processes the request.
/// </summary>
/// <param name="requestContext">An object that encapsulates information about the request.</param>
/// <returns>
/// An object that processes the request.
/// </returns>
IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext)
{
return GetHttpHandler(requestContext);
}
/// <summary>
/// Provides the object that processes the request.
/// </summary>
/// <param name="requestContext">An object that encapsulates information about the request.</param>
/// <returns>
/// An object that processes the request.
/// </returns>
protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext)
{
return new HttpControllerHandler(requestContext.RouteData);
}
}
}

View File

@ -0,0 +1,129 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Web.Http.Dispatcher;
using System.Web.Http.WebHost.Properties;
using System.Xml;
namespace System.Web.Http.WebHost
{
// Processes files with this format:
//
// <typeCache lastModified=... mvcVersionId=...>
// <assembly name=...>
// <module versionId=...>
// <type>...</type>
// </module>
// </assembly>
// </typeCache>
//
// This is used to store caches of files between AppDomain resets, leading to improved cold boot time
// and more efficient use of memory.
/// <summary>
/// Manages serializing and deserializing the cache managed by <see cref="HttpControllerTypeCache"/>.
/// </summary>
internal sealed class HttpControllerTypeCacheSerializer
{
private static readonly Guid _mvcVersionId = typeof(HttpControllerTypeCacheSerializer).Module.ModuleVersionId;
// used for unit testing
private DateTime CurrentDate
{
get { return CurrentDateOverride ?? DateTime.Now; }
}
internal DateTime? CurrentDateOverride { get; set; }
[SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "This is an instance method for consistency with the SerializeTypes() method.")]
public ICollection<Type> DeserializeTypes(TextReader input)
{
// DevDiv: 314059: TypeCacheSerializer should use regular serialization instead of DOM
XmlDocument doc = new XmlDocument();
doc.Load(input);
XmlElement rootElement = doc.DocumentElement;
Guid readMvcVersionId = new Guid(rootElement.Attributes["mvcVersionId"].Value);
if (readMvcVersionId != _mvcVersionId)
{
// The cache is outdated because the cache file was produced by a different version
// of MVC.
return null;
}
List<Type> deserializedTypes = new List<Type>();
foreach (XmlNode assemblyNode in rootElement.ChildNodes)
{
string assemblyName = assemblyNode.Attributes["name"].Value;
Assembly assembly = Assembly.Load(assemblyName);
foreach (XmlNode moduleNode in assemblyNode.ChildNodes)
{
Guid moduleVersionId = new Guid(moduleNode.Attributes["versionId"].Value);
foreach (XmlNode typeNode in moduleNode.ChildNodes)
{
string typeName = typeNode.InnerText;
Type type = assembly.GetType(typeName);
if (type == null || type.Module.ModuleVersionId != moduleVersionId)
{
// The cache is outdated because we couldn't find a previously recorded
// type or the type's containing module was modified.
return null;
}
else
{
deserializedTypes.Add(type);
}
}
}
}
return deserializedTypes;
}
public void SerializeTypes(IEnumerable<Type> types, TextWriter output)
{
var groupedByAssembly = from type in types
group type by type.Module
into groupedByModule
group groupedByModule by groupedByModule.Key.Assembly;
XmlDocument doc = new XmlDocument();
doc.AppendChild(doc.CreateComment(SRResources.TypeCache_DoNotModify));
XmlElement typeCacheElement = doc.CreateElement("typeCache");
doc.AppendChild(typeCacheElement);
typeCacheElement.SetAttribute("lastModified", CurrentDate.ToString());
typeCacheElement.SetAttribute("mvcVersionId", _mvcVersionId.ToString());
foreach (var assemblyGroup in groupedByAssembly)
{
XmlElement assemblyElement = doc.CreateElement("assembly");
typeCacheElement.AppendChild(assemblyElement);
assemblyElement.SetAttribute("name", assemblyGroup.Key.FullName);
foreach (var moduleGroup in assemblyGroup)
{
XmlElement moduleElement = doc.CreateElement("module");
assemblyElement.AppendChild(moduleElement);
moduleElement.SetAttribute("versionId", moduleGroup.Key.ModuleVersionId.ToString());
foreach (Type type in moduleGroup)
{
XmlElement typeElement = doc.CreateElement("type");
moduleElement.AppendChild(typeElement);
typeElement.AppendChild(doc.CreateTextNode(type.FullName));
}
}
}
doc.Save(output);
}
}
}

View File

@ -0,0 +1,24 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.ComponentModel;
namespace System.Web.Http.WebHost
{
[EditorBrowsable(EditorBrowsableState.Never)]
public static class PreApplicationStartCode
{
private static bool _startWasCalled;
public static void Start()
{
// Guard against multiple calls. All Start calls are made on same thread, so no lock needed here
if (_startWasCalled)
{
return;
}
_startWasCalled = true;
SuppressFormsAuthRedirectModule.Register();
}
}
}

View File

@ -0,0 +1,12 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Web;
using System.Web.Http.WebHost;
[assembly: AssemblyTitle("System.Web.Http.WebHost")]
[assembly: AssemblyDescription("")]
[assembly: InternalsVisibleTo("System.Web.Http.WebHost.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")]
[assembly: PreApplicationStartMethod(typeof(PreApplicationStartCode), "Start")]

View File

@ -0,0 +1,108 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.239
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace System.Web.Http.WebHost.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class SRResources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal SRResources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("System.Web.Http.WebHost.Properties.SRResources", typeof(SRResources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to The &apos;{0}&apos; class only supports asynchronous processing of HTTP requests..
/// </summary>
internal static string ProcessRequestNotSupported {
get {
return ResourceManager.GetString("ProcessRequestNotSupported", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to This operation is not supported by &apos;{0}&apos;..
/// </summary>
internal static string RouteCollectionNotSupported {
get {
return ResourceManager.GetString("RouteCollectionNotSupported", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The index cannot be less than 0 or equal to or larger than the number of items in the collection..
/// </summary>
internal static string RouteCollectionOutOfRange {
get {
return ResourceManager.GetString("RouteCollectionOutOfRange", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to This operation is only supported by directly calling it on &apos;{0}&apos;..
/// </summary>
internal static string RouteCollectionUseDirectly {
get {
return ResourceManager.GetString("RouteCollectionUseDirectly", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to This file is automatically generated. Please do not modify the contents of this file..
/// </summary>
internal static string TypeCache_DoNotModify {
get {
return ResourceManager.GetString("TypeCache_DoNotModify", resourceCulture);
}
}
}
}

View File

@ -0,0 +1,135 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="ProcessRequestNotSupported" xml:space="preserve">
<value>The '{0}' class only supports asynchronous processing of HTTP requests.</value>
</data>
<data name="RouteCollectionNotSupported" xml:space="preserve">
<value>This operation is not supported by '{0}'.</value>
</data>
<data name="RouteCollectionOutOfRange" xml:space="preserve">
<value>The index cannot be less than 0 or equal to or larger than the number of items in the collection.</value>
</data>
<data name="RouteCollectionUseDirectly" xml:space="preserve">
<value>This operation is only supported by directly calling it on '{0}'.</value>
</data>
<data name="TypeCache_DoNotModify" xml:space="preserve">
<value>This file is automatically generated. Please do not modify the contents of this file.</value>
</data>
</root>

View File

@ -0,0 +1,68 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.ComponentModel;
using System.Web.Http.WebHost;
using System.Web.Http.WebHost.Routing;
using System.Web.Routing;
namespace System.Web.Http
{
/// <summary>
/// Extension methods for <see cref="RouteCollection"/>
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public static class RouteCollectionExtensions
{
/// <summary>
/// Maps the specified route template.
/// </summary>
/// <param name="routes">A collection of routes for the application.</param>
/// <param name="name">The name of the route to map.</param>
/// <param name="routeTemplate">The route template for the route.</param>
/// <returns>A reference to the mapped route.</returns>
public static Route MapHttpRoute(this RouteCollection routes, string name, string routeTemplate)
{
return MapHttpRoute(routes, name, routeTemplate, defaults: null, constraints: null);
}
/// <summary>
/// Maps the specified route template and sets default constraints, and namespaces.
/// </summary>
/// <param name="routes">A collection of routes for the application.</param>
/// <param name="name">The name of the route to map.</param>
/// <param name="routeTemplate">The route template for the route.</param>
/// <param name="defaults">An object that contains default route values.</param>
/// <returns>A reference to the mapped route.</returns>
public static Route MapHttpRoute(this RouteCollection routes, string name, string routeTemplate, object defaults)
{
return MapHttpRoute(routes, name, routeTemplate, defaults, constraints: null);
}
/// <summary>
/// Maps the specified route template and sets default route values, constraints, and namespaces.
/// </summary>
/// <param name="routes">A collection of routes for the application.</param>
/// <param name="name">The name of the route to map.</param>
/// <param name="routeTemplate">The route template for the route.</param>
/// <param name="defaults">An object that contains default route values.</param>
/// <param name="constraints">A set of expressions that specify values for <paramref name="routeTemplate"/>.</param>
/// <returns>A reference to the mapped route.</returns>
public static Route MapHttpRoute(this RouteCollection routes, string name, string routeTemplate, object defaults, object constraints)
{
if (routes == null)
{
throw Error.ArgumentNull("routes");
}
HttpWebRoute route = new HttpWebRoute(routeTemplate, HttpControllerRouteHandler.Instance)
{
Defaults = new RouteValueDictionary(defaults),
Constraints = new RouteValueDictionary(constraints),
DataTokens = new RouteValueDictionary()
};
routes.Add(name, route);
return route;
}
}
}

View File

@ -0,0 +1,100 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Net.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Routing;
using System.Web.Routing;
namespace System.Web.Http.WebHost.Routing
{
internal class HostedHttpRoute : IHttpRoute
{
private readonly Route _route;
public HostedHttpRoute(Route route)
{
if (route == null)
{
throw Error.ArgumentNull("route");
}
_route = route;
}
public string RouteTemplate
{
get { return _route.Url; }
}
public IDictionary<string, object> Defaults
{
get { return _route.Defaults; }
}
public IDictionary<string, object> Constraints
{
get { return _route.Constraints; }
}
public IDictionary<string, object> DataTokens
{
get { return _route.DataTokens; }
}
internal Route OriginalRoute
{
get { return _route; }
}
public IHttpRouteData GetRouteData(string rootVirtualPath, HttpRequestMessage request)
{
if (rootVirtualPath == null)
{
throw Error.ArgumentNull("rootVirtualPath");
}
if (request == null)
{
throw Error.ArgumentNull("request");
}
HttpContextBase httpContextBase;
if (request.Properties.TryGetValue(HttpControllerHandler.HttpContextBaseKey, out httpContextBase))
{
RouteData routeData = _route.GetRouteData(httpContextBase);
if (routeData != null)
{
return new HostedHttpRouteData(routeData);
}
}
return null;
}
public IHttpVirtualPathData GetVirtualPath(HttpControllerContext controllerContext, IDictionary<string, object> values)
{
if (controllerContext == null)
{
throw Error.ArgumentNull("controllerContext");
}
HttpContextBase httpContextBase;
if (controllerContext.Request.Properties.TryGetValue(HttpControllerHandler.HttpContextBaseKey, out httpContextBase))
{
HostedHttpRouteData routeData = controllerContext.RouteData as HostedHttpRouteData;
if (routeData != null)
{
RequestContext requestContext = new RequestContext(httpContextBase, routeData.OriginalRouteData);
VirtualPathData virtualPathData = _route.GetVirtualPath(requestContext, new RouteValueDictionary(values));
if (virtualPathData != null)
{
return new HostedHttpVirtualPathData(virtualPathData);
}
}
}
return null;
}
}
}

View File

@ -0,0 +1,196 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Web.Hosting;
using System.Web.Http.Controllers;
using System.Web.Http.Routing;
using System.Web.Http.WebHost.Properties;
using System.Web.Routing;
namespace System.Web.Http.WebHost.Routing
{
internal class HostedHttpRouteCollection : HttpRouteCollection
{
private readonly RouteCollection _routeCollection;
public HostedHttpRouteCollection(RouteCollection routeCollection)
{
if (routeCollection == null)
{
throw Error.ArgumentNull("routeCollection");
}
_routeCollection = routeCollection;
}
public override string VirtualPathRoot
{
get { return HostingEnvironment.ApplicationVirtualPath; }
}
public override int Count
{
get { return _routeCollection.Count; }
}
public override IHttpRoute this[string name]
{
get
{
Route route = _routeCollection[name] as Route;
if (route != null)
{
return new HostedHttpRoute(route);
}
throw Error.KeyNotFound();
}
}
public override IHttpRoute this[int index]
{
get
{
Route route = _routeCollection[index] as Route;
if (route != null)
{
return new HostedHttpRoute(route);
}
throw Error.ArgumentOutOfRange("index", index, SRResources.RouteCollectionOutOfRange);
}
}
public override IHttpRouteData GetRouteData(HttpRequestMessage request)
{
if (request == null)
{
throw Error.ArgumentNull("request");
}
HttpContextBase httpContextBase;
if (request.Properties.TryGetValue(HttpControllerHandler.HttpContextBaseKey, out httpContextBase))
{
RouteData routeData = _routeCollection.GetRouteData(httpContextBase);
if (routeData != null)
{
return new HostedHttpRouteData(routeData);
}
}
return null;
}
public override IHttpVirtualPathData GetVirtualPath(HttpControllerContext controllerContext, string name, IDictionary<string, object> values)
{
if (controllerContext == null)
{
throw Error.ArgumentNull("controllerContext");
}
HttpRequestMessage request = controllerContext.Request;
HttpContextBase httpContextBase;
if (request.Properties.TryGetValue(HttpControllerHandler.HttpContextBaseKey, out httpContextBase))
{
RequestContext requestContext = new RequestContext(httpContextBase, controllerContext.RouteData.ToRouteData());
RouteValueDictionary routeValues = values != null ? new RouteValueDictionary(values) : new RouteValueDictionary();
VirtualPathData virtualPathData = _routeCollection.GetVirtualPath(requestContext, name, routeValues);
if (virtualPathData != null)
{
return new HostedHttpVirtualPathData(virtualPathData);
}
}
return null;
}
public override IHttpRoute CreateRoute(string uriTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> dataTokens, IDictionary<string, object> parameters)
{
RouteValueDictionary routeDefaults = defaults != null ? new RouteValueDictionary(defaults) : null;
RouteValueDictionary routeConstraints = constraints != null ? new RouteValueDictionary(constraints) : null;
RouteValueDictionary routeDataTokens = dataTokens != null ? new RouteValueDictionary(dataTokens) : null;
HttpWebRoute route = new HttpWebRoute(uriTemplate, routeDefaults, routeConstraints, routeDataTokens, HttpControllerRouteHandler.Instance);
return new HostedHttpRoute(route);
}
public override void Add(string name, IHttpRoute route)
{
_routeCollection.Add(name, route.ToRoute());
}
public override void Clear()
{
_routeCollection.Clear();
}
public override bool Contains(IHttpRoute item)
{
HostedHttpRoute hostedHttpRoute = item as HostedHttpRoute;
if (hostedHttpRoute != null)
{
return _routeCollection.Contains(hostedHttpRoute.OriginalRoute);
}
return false;
}
public override bool ContainsKey(string name)
{
return _routeCollection[name] != null;
}
public override void CopyTo(IHttpRoute[] array, int arrayIndex)
{
throw NotSupportedByHostedRouteCollection();
}
public override void CopyTo(KeyValuePair<string, IHttpRoute>[] array, int arrayIndex)
{
throw NotSupportedByRouteCollection();
}
public override void Insert(int index, string name, IHttpRoute value)
{
throw NotSupportedByRouteCollection();
}
public override bool Remove(string name)
{
throw NotSupportedByRouteCollection();
}
public override IEnumerator<IHttpRoute> GetEnumerator()
{
// Here we only care about Web API routes.
return _routeCollection
.OfType<HttpWebRoute>()
.Select(httpWebRoute => new HostedHttpRoute(httpWebRoute))
.GetEnumerator();
}
public override bool TryGetValue(string name, out IHttpRoute route)
{
Route rt = _routeCollection[name] as Route;
if (rt != null)
{
route = new HostedHttpRoute(rt);
return true;
}
route = null;
return false;
}
private static NotSupportedException NotSupportedByRouteCollection()
{
return Error.NotSupported(SRResources.RouteCollectionNotSupported, typeof(RouteCollection).Name);
}
private static NotSupportedException NotSupportedByHostedRouteCollection()
{
return Error.NotSupported(SRResources.RouteCollectionUseDirectly, typeof(RouteCollection).Name);
}
}
}

View File

@ -0,0 +1,40 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Web.Http.Routing;
using System.Web.Routing;
namespace System.Web.Http.WebHost.Routing
{
internal class HostedHttpRouteData : IHttpRouteData
{
private readonly RouteData _routeData;
private readonly HostedHttpRoute _hostedHttpRoute;
public HostedHttpRouteData(RouteData routeData)
{
if (routeData == null)
{
throw Error.ArgumentNull("routeData");
}
_routeData = routeData;
_hostedHttpRoute = new HostedHttpRoute(_routeData.Route as Route);
}
public IHttpRoute Route
{
get { return _hostedHttpRoute; }
}
public IDictionary<string, object> Values
{
get { return _routeData.Values; }
}
internal RouteData OriginalRouteData
{
get { return _routeData; }
}
}
}

View File

@ -0,0 +1,34 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Web.Http.Routing;
using System.Web.Routing;
namespace System.Web.Http.WebHost.Routing
{
internal class HostedHttpVirtualPathData : IHttpVirtualPathData
{
private readonly VirtualPathData _virtualPath;
private readonly HostedHttpRoute _hostedHttpRoute;
public HostedHttpVirtualPathData(VirtualPathData virtualPath)
{
if (virtualPath == null)
{
throw Error.ArgumentNull("route");
}
_virtualPath = virtualPath;
_hostedHttpRoute = new HostedHttpRoute(_virtualPath.Route as Route);
}
public IHttpRoute Route
{
get { return _hostedHttpRoute; }
}
public string VirtualPath
{
get { return _virtualPath.VirtualPath; }
}
}
}

View File

@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Net.Http;
namespace System.Web.Http.WebHost.Routing
{
internal static class HttpContextBaseExtensions
{
internal static readonly string HttpRequestMessageKey = "MS_HttpRequestMessage";
public static HttpRequestMessage GetHttpRequestMessage(this HttpContextBase context)
{
if (context == null)
{
throw Error.ArgumentNull("context");
}
if (!context.Items.Contains(HttpRequestMessageKey))
{
return null;
}
return context.Items[HttpRequestMessageKey] as HttpRequestMessage;
}
public static void SetHttpRequestMessage(this HttpContextBase context, HttpRequestMessage request)
{
context.Items.Add(HttpRequestMessageKey, request);
}
}
}

View File

@ -0,0 +1,27 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Web.Http.Routing;
using System.Web.Routing;
namespace System.Web.Http.WebHost.Routing
{
internal static class HttpRouteDataExtensions
{
public static RouteData ToRouteData(this IHttpRouteData httpRouteData)
{
if (httpRouteData == null)
{
throw Error.ArgumentNull("httpRouteData");
}
HostedHttpRouteData hostedHttpRouteData = httpRouteData as HostedHttpRouteData;
if (hostedHttpRouteData != null)
{
return hostedHttpRouteData.OriginalRouteData;
}
Route route = httpRouteData.Route.ToRoute();
return new RouteData(route, HttpControllerRouteHandler.Instance);
}
}
}

View File

@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Web.Http.Routing;
using System.Web.Routing;
namespace System.Web.Http.WebHost.Routing
{
internal static class HttpRouteExtensions
{
public static Route ToRoute(this IHttpRoute httpRoute)
{
if (httpRoute == null)
{
throw Error.ArgumentNull("httpRoute");
}
HostedHttpRoute hostedHttpRoute = httpRoute as HostedHttpRoute;
if (hostedHttpRoute != null)
{
return hostedHttpRoute.OriginalRoute;
}
return new HttpWebRoute(httpRoute.RouteTemplate, HttpControllerRouteHandler.Instance)
{
Defaults = new RouteValueDictionary(httpRoute.Defaults),
Constraints = new RouteValueDictionary(httpRoute.Constraints),
DataTokens = new RouteValueDictionary(httpRoute.DataTokens),
};
}
}
}

View File

@ -0,0 +1,111 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Net.Http;
using System.Web.Http.Routing;
using System.Web.Routing;
namespace System.Web.Http.WebHost.Routing
{
/// <summary>
/// Mimics the System.Web.Routing.Route class to work better for Web API scenarios. The only
/// difference between the base class and this class is that this one will match only when
/// a special "httproute" key is specified when generating URLs. There is no special behavior
/// for incoming URLs.
/// </summary>
public class HttpWebRoute : Route
{
/// <summary>
/// Key used to signify that a route URL generation request should include HTTP routes (e.g. Web API).
/// If this key is not specified then no HTTP routes will match.
/// </summary>
private const string HttpRouteKey = "httproute";
[SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "0#", Justification = "Matches the base class's parameter names.")]
public HttpWebRoute(string url, IRouteHandler routeHandler)
: base(url, routeHandler)
{
}
[SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "0#", Justification = "Matches the base class's parameter names.")]
public HttpWebRoute(string url, RouteValueDictionary defaults, IRouteHandler routeHandler)
: base(url, defaults, routeHandler)
{
}
[SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "0#", Justification = "Matches the base class's parameter names.")]
public HttpWebRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, IRouteHandler routeHandler)
: base(url, defaults, constraints, routeHandler)
{
}
[SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "0#", Justification = "Matches the base class's parameter names.")]
public HttpWebRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens, IRouteHandler routeHandler)
: base(url, defaults, constraints, dataTokens, routeHandler)
{
}
protected override bool ProcessConstraint(HttpContextBase httpContext, object constraint, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
IHttpRouteConstraint httpRouteConstraint = constraint as IHttpRouteConstraint;
if (httpRouteConstraint != null)
{
HttpRequestMessage request = httpContext.GetHttpRequestMessage();
if (request == null)
{
request = HttpControllerHandler.ConvertRequest(httpContext);
httpContext.SetHttpRequestMessage(request);
}
return httpRouteConstraint.Match(request, new HostedHttpRoute(this), parameterName, values, ConvertRouteDirection(routeDirection));
}
return base.ProcessConstraint(httpContext, constraint, parameterName, values, routeDirection);
}
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
// Only perform URL generation if the "httproute" key was specified. This allows these
// routes to be ignored when a regular MVC app tries to generate URLs. Without this special
// key an HTTP route used for Web API would normally take over almost all the routes in a
// typical app.
if (!values.ContainsKey(HttpRouteKey))
{
return null;
}
// Remove the value from the collection so that it doesn't affect the generated URL
RouteValueDictionary newValues = GetRouteDictionaryWithoutHttpRouteKey(values);
return base.GetVirtualPath(requestContext, newValues);
}
private static RouteValueDictionary GetRouteDictionaryWithoutHttpRouteKey(IDictionary<string, object> routeValues)
{
var newRouteValues = new RouteValueDictionary();
foreach (var routeValue in routeValues)
{
if (!String.Equals(routeValue.Key, HttpRouteKey, StringComparison.OrdinalIgnoreCase))
{
newRouteValues.Add(routeValue.Key, routeValue.Value);
}
}
return newRouteValues;
}
private static HttpRouteDirection ConvertRouteDirection(RouteDirection routeDirection)
{
if (routeDirection == RouteDirection.IncomingRequest)
{
return HttpRouteDirection.UriResolution;
}
if (routeDirection == RouteDirection.UrlGeneration)
{
return HttpRouteDirection.UriGeneration;
}
throw Error.InvalidEnumArgument("routeDirection", (int)routeDirection, typeof(RouteDirection));
}
}
}

View File

@ -0,0 +1,186 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Collections;
using System.Collections.Specialized;
using System.Diagnostics.Contracts;
using System.Globalization;
using System.Net;
using System.Reflection;
using System.Web.Configuration;
using System.Web.Security;
namespace System.Web.Http.WebHost
{
/// <summary>
/// Recovers the response status code to 401 if it was altered by <see cref="T:System.Web.Security.FormsAuthenticationModule"/>.
/// This module autoregisters on .NET 4.0, which ensures it runs after <see cref="T:System.Web.Security.FormsAuthenticationModule"/>.
/// </summary>
internal class SuppressFormsAuthRedirectModule : IHttpModule
{
internal static readonly string SuppressFormsAuthenticationRedirectPropertyName = "SuppressFormsAuthenticationRedirect";
internal static readonly string AppSettingsSuppressFormsAuthenticationRedirectKey = "webapi:EnableSuppressRedirect";
internal static readonly object DisableAuthenticationRedirectKey = new Object();
/// <summary>
/// Abstract the properties needed by <see cref="T:System.Web.Http.WebHost.SuppressFormsAuthRedirectModule"/> for unit testing purposes.
/// </summary>
internal interface IDisableRedirect
{
IDictionary ContextItems { get; }
HttpResponse Response { get; }
}
/// <summary>
/// Enables authentication redirects.
/// </summary>
/// <param name="httpContextBase">The HTTP context.</param>
internal static void AllowAuthenticationRedirect(HttpContextBase httpContextBase)
{
SetDisableAuthenticationRedirectState(httpContextBase.Items, value: false);
}
/// <summary>
/// Disables authentication redirects.
/// </summary>
/// <param name="httpContextBase">The HTTP context.</param>
internal static void DisableAuthenticationRedirect(HttpContextBase httpContextBase)
{
SetDisableAuthenticationRedirectState(httpContextBase.Items, value: true);
}
public void Init(HttpApplication context)
{
context.EndRequest += OnEndRequest;
}
private void OnEndRequest(object source, EventArgs args)
{
HttpApplication httpApplication = source as HttpApplication;
if (httpApplication == null)
{
return;
}
EnsureRestoreUnauthorized(new HttpApplicationDisableRedirect(httpApplication));
}
internal static void EnsureRestoreUnauthorized(IDisableRedirect disableRedirect)
{
Contract.Assert(disableRedirect != null);
HttpResponse response = disableRedirect.Response;
// If there was no redirection, do nothing
if (response.StatusCode != (int)HttpStatusCode.Redirect)
{
return;
}
// If the flag is set and is true, revert the redirection
if (disableRedirect.ContextItems.Contains(DisableAuthenticationRedirectKey)
&& Convert.ToBoolean(disableRedirect.ContextItems[DisableAuthenticationRedirectKey], CultureInfo.InvariantCulture))
{
response.TrySkipIisCustomErrors = true;
response.ClearContent();
response.StatusCode = (int)HttpStatusCode.Unauthorized;
response.RedirectLocation = null;
}
}
public void Dispose()
{
}
/// <summary>
/// Registers the module if necessary.
/// </summary>
/// <remarks>
/// We do not want the module to be registered if:
/// - Running on .NET 4.5 because there is a standard way to prevent the redirection
/// - The behavior is explicitly disabled using the appSettings flag
/// - The module <see cref="T:System.Web.Security.FormsAuthenticationModule"/> is not enabled
/// </remarks>
public static void Register()
{
// If FormsAuthentication is not enabled, this module is not needed
if (!FormsAuthentication.IsEnabled)
{
return;
}
// If explicitly requested, don't enable the module
if (!GetEnabled(WebConfigurationManager.AppSettings))
{
return;
}
PropertyInfo suppressRedirect = typeof(HttpResponseBase).GetProperty(SuppressFormsAuthenticationRedirectPropertyName, BindingFlags.Instance | BindingFlags.Public);
// Don't enable the module if hosted on .NET 4.5 or later. In this case the automatic
// redirection will be disabled using the specific API call
if (suppressRedirect != null)
{
return;
}
Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(SuppressFormsAuthRedirectModule));
}
/// <summary>
/// Returns whether the module is explicitly enabled or not
/// </summary>
internal static bool GetEnabled(NameValueCollection appSettings)
{
string disableSuppressRedirect = appSettings.Get(AppSettingsSuppressFormsAuthenticationRedirectKey);
if (!String.IsNullOrEmpty(disableSuppressRedirect))
{
bool enabled;
// anything but "false" will return true, which is the default behavior
if (Boolean.TryParse(disableSuppressRedirect, out enabled))
{
if (!enabled)
{
return false;
}
}
}
return true;
}
private static void SetDisableAuthenticationRedirectState(IDictionary items, bool value)
{
items[DisableAuthenticationRedirectKey] = value;
}
/// <summary>
/// Wrapper implementation of <see cref="T:System.Web.Http.WebHost.SuppressFormsAuthRedirectModule.IDisableRedirect"/> for <see cref="T:System.Web.HttpApplication"/>.
/// </summary>
internal class HttpApplicationDisableRedirect : IDisableRedirect
{
private HttpApplication _httpApplication;
public HttpApplicationDisableRedirect(HttpApplication httpApplication)
{
Contract.Assert(httpApplication != null);
_httpApplication = httpApplication;
}
public IDictionary ContextItems
{
get { return _httpApplication.Context.Items; }
}
public HttpResponse Response
{
get { return _httpApplication.Response; }
}
}
}
}

View File

@ -0,0 +1,157 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory),Runtime.sln))\tools\WebStack.settings.targets" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<CodeAnalysis Condition=" '$(CodeAnalysis)' == '' ">false</CodeAnalysis>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{A0187BC2-8325-4BB2-8697-7F955CF4173E}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>System.Web.Http.WebHost</RootNamespace>
<AssemblyName>System.Web.Http.WebHost</AssemblyName>
<FileAlignment>512</FileAlignment>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\..\bin\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG;ASPNETMVC</DefineConstants>
<CodeAnalysisRuleSet>..\Strict.ruleset</CodeAnalysisRuleSet>
<DocumentationFile>$(OutputPath)\$(AssemblyName).xml</DocumentationFile>
<NoWarn>1591</NoWarn>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\..\bin\Release\</OutputPath>
<DefineConstants>TRACE;ASPNETMVC</DefineConstants>
<CodeAnalysisRuleSet>..\Strict.ruleset</CodeAnalysisRuleSet>
<RunCodeAnalysis>$(CodeAnalysis)</RunCodeAnalysis>
<DocumentationFile>$(OutputPath)\$(AssemblyName).xml</DocumentationFile>
<NoWarn>1591</NoWarn>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'CodeCoverage|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>..\..\bin\CodeCoverage\</OutputPath>
<DefineConstants>TRACE;DEBUG;CODE_COVERAGE;ASPNETMVC</DefineConstants>
<DebugType>full</DebugType>
<CodeAnalysisRuleSet>..\Strict.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Net.Http, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Net.Http.2.0.20326.1\lib\net40\System.Net.Http.dll</HintPath>
</Reference>
<Reference Include="System.Net.Http.WebRequest, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Net.Http.2.0.20326.1\lib\net40\System.Net.Http.WebRequest.dll</HintPath>
</Reference>
<Reference Include="System.Web" />
<Reference Include="System.XML" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\CommonAssemblyInfo.cs">
<Link>Properties\CommonAssemblyInfo.cs</Link>
</Compile>
<Compile Include="..\Common\DictionaryExtensions.cs">
<Link>Common\DictionaryExtensions.cs</Link>
</Compile>
<Compile Include="..\Common\Error.cs">
<Link>Common\Error.cs</Link>
</Compile>
<Compile Include="..\Common\HttpMethodHelper.cs">
<Link>Common\HttpMethodHelper.cs</Link>
</Compile>
<Compile Include="..\Common\TaskHelpers.cs">
<Link>Common\TaskHelpers.cs</Link>
</Compile>
<Compile Include="..\Common\TaskHelpersExtensions.cs">
<Link>Common\TaskHelpersExtensions.cs</Link>
</Compile>
<Compile Include="PreApplicationStartCode.cs" />
<Compile Include="HttpControllerTypeCacheSerializer.cs" />
<Compile Include="Routing\HttpContextBaseExtensions.cs" />
<Compile Include="WebHostHttpControllerTypeResolver.cs" />
<Compile Include="Routing\HostedHttpRouteCollection.cs" />
<Compile Include="Routing\HostedHttpRoute.cs" />
<Compile Include="Routing\HostedHttpRouteData.cs" />
<Compile Include="Routing\HostedHttpVirtualPathData.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="..\TransparentCommonAssemblyInfo.cs">
<Link>Properties\TransparentCommonAssemblyInfo.cs</Link>
</Compile>
<Compile Include="GlobalConfiguration.cs" />
<Compile Include="Routing\HttpRouteDataExtensions.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Routing\HttpRouteExtensions.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Routing\HttpWebRoute.cs" />
<Compile Include="SuppressFormsAuthRedirectModule.cs" />
<Compile Include="WebHostAssembliesResolver.cs" />
<Compile Include="Properties\SRResources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>SRResources.resx</DependentUpon>
</Compile>
<Compile Include="GlobalSuppressions.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="HttpControllerHandler.cs" />
<Compile Include="HttpControllerRouteHandler.cs" />
<Compile Include="RouteCollectionExtensions.cs" />
<Compile Include="TaskWrapperAsyncResult.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Common\CommonWebApiResources.Designer.cs">
<Link>Properties\CommonWebApiResources.Designer.cs</Link>
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>CommonWebApiResources.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="..\Common\CommonWebApiResources.resx">
<Link>Properties\CommonWebApiResources.resx</Link>
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>CommonWebApiResources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Properties\SRResources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>SRResources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\System.Web.Http\System.Web.Http.csproj">
<Project>{DDC1CE0C-486E-4E35-BB3B-EAB61F8F9440}</Project>
<Name>System.Web.Http</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<CodeAnalysisDictionary Include="..\CodeAnalysisDictionary.xml">
<Link>CodeAnalysisDictionary.xml</Link>
</CodeAnalysisDictionary>
</ItemGroup>
<ItemGroup>
<None Include="packages.config">
<SubType>Designer</SubType>
</None>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

Some files were not shown because too many files have changed in this diff Show More