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,165 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Web.Http.Controllers;
using System.Web.Http.Properties;
using System.Web.Http.Routing;
namespace System.Web.Http.Dispatcher
{
/// <summary>
/// Default <see cref="IHttpControllerSelector"/> instance for choosing a <see cref="HttpControllerDescriptor"/> given a <see cref="HttpRequestMessage"/>
/// A different implementation can be registered via the <see cref="HttpConfiguration.Services"/>.
/// </summary>
public class DefaultHttpControllerSelector : IHttpControllerSelector
{
public static readonly string ControllerSuffix = "Controller";
private const string ControllerKey = "controller";
private readonly HttpConfiguration _configuration;
private readonly HttpControllerTypeCache _controllerTypeCache;
private readonly Lazy<ConcurrentDictionary<string, HttpControllerDescriptor>> _controllerInfoCache;
/// <summary>
/// Initializes a new instance of the <see cref="DefaultHttpControllerSelector"/> class.
/// </summary>
/// <param name="configuration">The configuration.</param>
public DefaultHttpControllerSelector(HttpConfiguration configuration)
{
if (configuration == null)
{
throw Error.ArgumentNull("configuration");
}
_controllerInfoCache = new Lazy<ConcurrentDictionary<string, HttpControllerDescriptor>>(InitializeControllerInfoCache);
_configuration = configuration;
_controllerTypeCache = new HttpControllerTypeCache(_configuration);
}
[SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Caller is responsible for disposing of response instance.")]
public virtual HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
if (request == null)
{
throw Error.ArgumentNull("request");
}
string controllerName = GetControllerName(request);
if (String.IsNullOrEmpty(controllerName))
{
throw new HttpResponseException(request.CreateResponse(HttpStatusCode.NotFound));
}
HttpControllerDescriptor controllerDescriptor;
if (_controllerInfoCache.Value.TryGetValue(controllerName, out controllerDescriptor))
{
return controllerDescriptor;
}
ICollection<Type> matchingTypes = _controllerTypeCache.GetControllerTypes(controllerName);
// ControllerInfoCache is already initialized.
Contract.Assert(matchingTypes.Count != 1);
if (matchingTypes.Count == 0)
{
// no matching types
throw new HttpResponseException(request.CreateResponse(
HttpStatusCode.NotFound,
Error.Format(SRResources.DefaultControllerFactory_ControllerNameNotFound, controllerName)));
}
else
{
// multiple matching types
throw new HttpResponseException(request.CreateResponse(
HttpStatusCode.InternalServerError,
CreateAmbiguousControllerExceptionMessage(request.GetRouteData().Route, controllerName, matchingTypes)));
}
}
public virtual IDictionary<string, HttpControllerDescriptor> GetControllerMapping()
{
return _controllerInfoCache.Value.ToDictionary(c => c.Key, c => c.Value, StringComparer.OrdinalIgnoreCase);
}
public virtual string GetControllerName(HttpRequestMessage request)
{
if (request == null)
{
throw Error.ArgumentNull("request");
}
IHttpRouteData routeData = request.GetRouteData();
if (routeData == null)
{
return null;
}
// Look up controller in route data
string controllerName = null;
routeData.Values.TryGetValue(ControllerKey, out controllerName);
return controllerName;
}
private static string CreateAmbiguousControllerExceptionMessage(IHttpRoute route, string controllerName, ICollection<Type> matchingTypes)
{
Contract.Assert(route != null);
Contract.Assert(controllerName != null);
Contract.Assert(matchingTypes != null);
// Generate an exception containing all the controller types
StringBuilder typeList = new StringBuilder();
foreach (Type matchedType in matchingTypes)
{
typeList.AppendLine();
typeList.Append(matchedType.FullName);
}
return Error.Format(SRResources.DefaultControllerFactory_ControllerNameAmbiguous_WithRouteTemplate, controllerName, route.RouteTemplate, typeList);
}
private ConcurrentDictionary<string, HttpControllerDescriptor> InitializeControllerInfoCache()
{
var result = new ConcurrentDictionary<string, HttpControllerDescriptor>(StringComparer.OrdinalIgnoreCase);
var duplicateControllers = new HashSet<string>();
Dictionary<string, ILookup<string, Type>> controllerTypeGroups = _controllerTypeCache.Cache;
foreach (KeyValuePair<string, ILookup<string, Type>> controllerTypeGroup in controllerTypeGroups)
{
string controllerName = controllerTypeGroup.Key;
foreach (IGrouping<string, Type> controllerTypesGroupedByNs in controllerTypeGroup.Value)
{
foreach (Type controllerType in controllerTypesGroupedByNs)
{
if (result.Keys.Contains(controllerName))
{
duplicateControllers.Add(controllerName);
break;
}
else
{
result.TryAdd(controllerName, new HttpControllerDescriptor(_configuration, controllerName, controllerType));
}
}
}
}
foreach (string duplicateController in duplicateControllers)
{
HttpControllerDescriptor descriptor;
result.TryRemove(duplicateController, out descriptor);
}
return result;
}
}
}