// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information. using System; using System.Collections.Generic; using System.Linq; using System.Reflection; namespace Microsoft.AspNet.SignalR.Hubs { public class ReflectedHubDescriptorProvider : IHubDescriptorProvider { private readonly Lazy> _hubs; private readonly Lazy _locator; public ReflectedHubDescriptorProvider(IDependencyResolver resolver) { _locator = new Lazy(resolver.Resolve); _hubs = new Lazy>(BuildHubsCache); } public IList GetHubs() { return _hubs.Value .Select(kv => kv.Value) .Distinct() .ToList(); } public bool TryGetHub(string hubName, out HubDescriptor descriptor) { return _hubs.Value.TryGetValue(hubName, out descriptor); } protected IDictionary BuildHubsCache() { // Getting all IHub-implementing types that apply var types = _locator.Value.GetAssemblies() .SelectMany(GetTypesSafe) .Where(IsHubType); // Building cache entries for each descriptor // Each descriptor is stored in dictionary under a key // that is it's name or the name provided by an attribute var cacheEntries = types .Select(type => new HubDescriptor { NameSpecified = (type.GetHubAttributeName() != null), Name = type.GetHubName(), HubType = type }) .ToDictionary(hub => hub.Name, hub => hub, StringComparer.OrdinalIgnoreCase); return cacheEntries; } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "If we throw then it's not a hub type")] private static bool IsHubType(Type type) { try { return typeof(IHub).IsAssignableFrom(type) && !type.IsAbstract && (type.Attributes.HasFlag(TypeAttributes.Public) || type.Attributes.HasFlag(TypeAttributes.NestedPublic)); } catch { return false; } } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "If we throw then we have an empty type")] private static IEnumerable GetTypesSafe(Assembly a) { try { return a.GetTypes(); } catch { return Enumerable.Empty(); } } } }