// 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.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq; using System.Threading; using Microsoft.AspNet.SignalR.Configuration; using Microsoft.AspNet.SignalR.Hubs; using Microsoft.AspNet.SignalR.Infrastructure; using Microsoft.AspNet.SignalR.Json; using Microsoft.AspNet.SignalR.Messaging; using Microsoft.AspNet.SignalR.Tracing; using Microsoft.AspNet.SignalR.Transports; namespace Microsoft.AspNet.SignalR { public class DefaultDependencyResolver : IDependencyResolver { private readonly Dictionary>> _resolvers = new Dictionary>>(); private readonly HashSet _trackedDisposables = new HashSet(); private int _disposed; [SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors", Justification = "It's easiest")] public DefaultDependencyResolver() { RegisterDefaultServices(); // Hubs RegisterHubExtensions(); } [SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Justification = "The resolver is the class that does the most coupling by design.")] [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "The resolver disposes dependencies on Dispose.")] private void RegisterDefaultServices() { var traceManager = new Lazy(() => new TraceManager()); Register(typeof(ITraceManager), () => traceManager.Value); var serverIdManager = new ServerIdManager(); Register(typeof(IServerIdManager), () => serverIdManager); var serverMessageHandler = new Lazy(() => new ServerCommandHandler(this)); Register(typeof(IServerCommandHandler), () => serverMessageHandler.Value); var newMessageBus = new Lazy(() => new MessageBus(this)); Register(typeof(IMessageBus), () => newMessageBus.Value); var stringMinifier = new Lazy(() => new StringMinifier()); Register(typeof(IStringMinifier), () => stringMinifier.Value); var serializer = new Lazy(); Register(typeof(IJsonSerializer), () => serializer.Value); var transportManager = new Lazy(() => new TransportManager(this)); Register(typeof(ITransportManager), () => transportManager.Value); var configurationManager = new DefaultConfigurationManager(); Register(typeof(IConfigurationManager), () => configurationManager); var transportHeartbeat = new Lazy(() => new TransportHeartbeat(this)); Register(typeof(ITransportHeartbeat), () => transportHeartbeat.Value); var connectionManager = new Lazy(() => new ConnectionManager(this)); Register(typeof(IConnectionManager), () => connectionManager.Value); var ackHandler = new Lazy(); Register(typeof(IAckHandler), () => ackHandler.Value); var perfCounterWriter = new Lazy(() => new PerformanceCounterManager(this)); Register(typeof(IPerformanceCounterManager), () => perfCounterWriter.Value); var protectedData = new DefaultProtectedData(); Register(typeof(IProtectedData), () => protectedData); } private void RegisterHubExtensions() { var methodDescriptorProvider = new Lazy(); Register(typeof(IMethodDescriptorProvider), () => methodDescriptorProvider.Value); var hubDescriptorProvider = new Lazy(() => new ReflectedHubDescriptorProvider(this)); Register(typeof(IHubDescriptorProvider), () => hubDescriptorProvider.Value); var parameterBinder = new Lazy(); Register(typeof(IParameterResolver), () => parameterBinder.Value); var activator = new Lazy(() => new DefaultHubActivator(this)); Register(typeof(IHubActivator), () => activator.Value); var hubManager = new Lazy(() => new DefaultHubManager(this)); Register(typeof(IHubManager), () => hubManager.Value); var proxyGenerator = new Lazy(() => new DefaultJavaScriptProxyGenerator(this)); Register(typeof(IJavaScriptProxyGenerator), () => proxyGenerator.Value); var requestParser = new Lazy(); Register(typeof(IHubRequestParser), () => requestParser.Value); var assemblyLocator = new Lazy(() => new DefaultAssemblyLocator()); Register(typeof(IAssemblyLocator), () => assemblyLocator.Value); // Setup the default hub pipeline var dispatcher = new Lazy(() => new HubPipeline().AddModule(new AuthorizeModule())); Register(typeof(IHubPipeline), () => dispatcher.Value); Register(typeof(IHubPipelineInvoker), () => dispatcher.Value); } public virtual object GetService(Type serviceType) { if (serviceType == null) { throw new ArgumentNullException("serviceType"); } IList> activators; if (_resolvers.TryGetValue(serviceType, out activators)) { if (activators.Count == 0) { return null; } if (activators.Count > 1) { throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, Resources.Error_MultipleActivatorsAreaRegisteredCallGetServices, serviceType.FullName)); } return Track(activators[0]); } return null; } public virtual IEnumerable GetServices(Type serviceType) { IList> activators; if (_resolvers.TryGetValue(serviceType, out activators)) { if (activators.Count == 0) { return null; } return activators.Select(Track).ToList(); } return null; } public virtual void Register(Type serviceType, Func activator) { IList> activators; if (!_resolvers.TryGetValue(serviceType, out activators)) { activators = new List>(); _resolvers.Add(serviceType, activators); } else { activators.Clear(); } activators.Add(activator); } public virtual void Register(Type serviceType, IEnumerable> activators) { if (activators == null) { throw new ArgumentNullException("activators"); } IList> list; if (!_resolvers.TryGetValue(serviceType, out list)) { list = new List>(); _resolvers.Add(serviceType, list); } else { list.Clear(); } foreach (var a in activators) { list.Add(a); } } private object Track(Func creator) { object obj = creator(); if (_disposed == 0) { var disposable = obj as IDisposable; if (disposable != null) { lock (_trackedDisposables) { if (_disposed == 0) { _trackedDisposables.Add(disposable); } } } } return obj; } protected virtual void Dispose(bool disposing) { if (disposing) { if (Interlocked.Exchange(ref _disposed, 1) == 0) { lock (_trackedDisposables) { foreach (var d in _trackedDisposables) { d.Dispose(); } _trackedDisposables.Clear(); } } } } public void Dispose() { Dispose(true); } } }