Merge pull request #513 from filipw/feature/cache-httpcontrollerdescriptor

Cache HttpControllerDescriptor in NamespaceHttpControllerSelector
This commit is contained in:
Shannon Deminick
2014-10-22 12:13:06 +10:00

View File

@@ -14,12 +14,12 @@ namespace Umbraco.Web.WebApi
{
private const string ControllerKey = "controller";
private readonly HttpConfiguration _configuration;
private readonly Lazy<IEnumerable<Type>> _duplicateControllerTypes;
private readonly Lazy<ConcurrentStack<NamespaceHttpControllerMetadata>> _duplicateControllerTypes;
public NamespaceHttpControllerSelector(HttpConfiguration configuration) : base(configuration)
{
_configuration = configuration;
_duplicateControllerTypes = new Lazy<IEnumerable<Type>>(GetDuplicateControllerTypes);
_duplicateControllerTypes = new Lazy<ConcurrentStack<NamespaceHttpControllerMetadata>>(GetDuplicateControllerTypes);
}
public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
@@ -52,32 +52,69 @@ namespace Umbraco.Web.WebApi
return base.SelectController(request);
//see if this is in our cache
var found = _duplicateControllerTypes.Value
.Where(x => string.Equals(x.Name, controllerNameAsString + ControllerSuffix, StringComparison.OrdinalIgnoreCase))
.FirstOrDefault(x => namespaces.Contains(x.Namespace));
var found = _duplicateControllerTypes.Value.FirstOrDefault(x => string.Equals(x.ControllerName, controllerNameAsString, StringComparison.OrdinalIgnoreCase) && namespaces.Contains(x.ControllerNamespace));
if (found == null)
return base.SelectController(request);
return new HttpControllerDescriptor(_configuration, controllerNameAsString, found);
return found.Descriptor;
}
private IEnumerable<Type> GetDuplicateControllerTypes()
private ConcurrentStack<NamespaceHttpControllerMetadata> GetDuplicateControllerTypes()
{
var assembliesResolver = _configuration.Services.GetAssembliesResolver();
var controllersResolver = _configuration.Services.GetHttpControllerTypeResolver();
var controllerTypes = controllersResolver.GetControllerTypes(assembliesResolver);
//we have all controller types, so just store the ones with duplicate class names - we don't
// want to cache too much and the underlying selector caches everything else
var groupedByName = controllerTypes.GroupBy(
t => t.Name.Substring(0, t.Name.Length - ControllerSuffix.Length),
StringComparer.OrdinalIgnoreCase).Where(x => x.Count() > 1);
var duplicates = controllerTypes.GroupBy(x => x.Name)
.Where(x => x.Count() > 1)
.SelectMany(x => x)
.ToArray();
var duplicateControllers = groupedByName.ToDictionary(
g => g.Key,
g => g.ToLookup(t => t.Namespace ?? String.Empty, StringComparer.OrdinalIgnoreCase),
StringComparer.OrdinalIgnoreCase);
return duplicates;
var result = new ConcurrentStack<NamespaceHttpControllerMetadata>();
foreach (var controllerTypeGroup in duplicateControllers)
{
foreach (var controllerType in controllerTypeGroup.Value.SelectMany(controllerTypesGrouping => controllerTypesGrouping))
{
result.Push(new NamespaceHttpControllerMetadata(controllerTypeGroup.Key, controllerType.Namespace,
new HttpControllerDescriptor(_configuration, controllerTypeGroup.Key, controllerType)));
}
}
return result;
}
private class NamespaceHttpControllerMetadata
{
private readonly string _controllerName;
private readonly string _controllerNamespace;
private readonly HttpControllerDescriptor _descriptor;
public NamespaceHttpControllerMetadata(string controllerName, string controllerNamespace, HttpControllerDescriptor descriptor)
{
_controllerName = controllerName;
_controllerNamespace = controllerNamespace;
_descriptor = descriptor;
}
public string ControllerName
{
get { return _controllerName; }
}
public string ControllerNamespace
{
get { return _controllerNamespace; }
}
public HttpControllerDescriptor Descriptor
{
get { return _descriptor; }
}
}
}
}