/// <summary> /// Method mostly copied from Microsoft.AspNet.SignalR OwinExtensions class, but without external dependency on Katana. /// </summary> /// <param name="configuration">The <see cref="HubConfiguration"/> to use.</param> /// <param name="startupEnv">Startup parameters.</param> /// <param name="next">Next <see cref="AppFunc"/> in pipeline.</param> /// <returns><see cref="AppFunc"/> ready for use.</returns> public static Func <IDictionary <string, object>, Task> BuildHubFunc(HubConfiguration configuration, IDictionary <string, object> startupEnv, AppFunc next) { if (configuration == null) { throw new ArgumentException("No configuration provided"); } var resolver = configuration.Resolver; if (resolver == null) { throw new ArgumentException("No dependency resolver provider"); } var token = startupEnv.GetValueOrDefault("owin.CallCancelled", CancellationToken.None); string instanceName = startupEnv.GetValueOrDefault("host.AppName", Guid.NewGuid().ToString()); var protectedData = new DefaultProtectedData(); resolver.Register(typeof(IProtectedData), () => protectedData); // If the host provides trace output then add a default trace listener var traceOutput = startupEnv.GetValueOrDefault("host.TraceOutput", (TextWriter)null); if (traceOutput != null) { var hostTraceListener = new TextWriterTraceListener(traceOutput); var traceManager = new TraceManager(hostTraceListener); resolver.Register(typeof(ITraceManager), () => traceManager); } // Try to get the list of reference assemblies from the host IEnumerable <Assembly> referenceAssemblies = startupEnv.GetValueOrDefault("host.ReferencedAssemblies", (IEnumerable <Assembly>)null); if (referenceAssemblies != null) { // Use this list as the assembly locator var assemblyLocator = new EnumerableOfAssemblyLocator(referenceAssemblies); resolver.Register(typeof(IAssemblyLocator), () => assemblyLocator); } resolver.InitializeHost(instanceName, token); var hub = new HubDispatcherMiddleware(new KatanaShim(next), configuration); return(async env => { await hub.Invoke(new OwinContext(env)); if (!env.ContainsKey("owin.ResponseStatusCode")) { env["owin.ResponseStatusCode"] = 200; } }); }
public void FarmDisconnectOnlyRaisesEventOnce() { EnableTracing(); // Each node shares the same bus but are indepenent servers var counters = new SignalR.Infrastructure.PerformanceCounterManager(); var configurationManager = new DefaultConfigurationManager(); var protectedData = new DefaultProtectedData(); using (var bus = new MessageBus(new StringMinifier(), new TraceManager(), counters, configurationManager, 5000)) { var nodeCount = 3; var nodes = new List <ServerNode>(); for (int i = 0; i < nodeCount; i++) { nodes.Add(new ServerNode(bus)); } var timeout = TimeSpan.FromSeconds(5); foreach (var node in nodes) { var config = node.Resolver.Resolve <IConfigurationManager>(); config.DisconnectTimeout = TimeSpan.FromSeconds(6); IDependencyResolver resolver = node.Resolver; node.Server.Configure(app => { app.MapSignalR <FarmConnection>("/echo", new ConnectionConfiguration { Resolver = resolver }); resolver.Register(typeof(IProtectedData), () => protectedData); }); } var loadBalancer = new LoadBalancer(nodes.Select(f => f.Server).ToArray()); var transport = new Client.Transports.LongPollingTransport(loadBalancer); var connection = new Client.Connection("http://goo/echo"); connection.Start(transport).Wait(); for (int i = 0; i < nodes.Count; i++) { nodes[i].Broadcast(String.Format("From Node {0}: {1}", i, i + 1)); Thread.Sleep(TimeSpan.FromSeconds(1)); } ((Client.IConnection)connection).Disconnect(); Thread.Sleep(TimeSpan.FromTicks(timeout.Ticks * nodes.Count)); Assert.Equal(1, nodes.Sum(n => n.Connection.DisconnectCount)); } }
private void RegisterDefaultServices() { var traceManager = new Lazy <TraceManager>(() => new TraceManager()); Register(typeof(ITraceManager), () => traceManager.Value); var serverIdManager = new ServerIdManager(); Register(typeof(IServerIdManager), () => serverIdManager); var serverMessageHandler = new Lazy <IServerCommandHandler>(() => new ServerCommandHandler(this)); Register(typeof(IServerCommandHandler), () => serverMessageHandler.Value); var newMessageBus = new Lazy <IMessageBus>(() => new MessageBus(this)); Register(typeof(IMessageBus), () => newMessageBus.Value); var stringMinifier = new Lazy <IStringMinifier>(() => new StringMinifier()); Register(typeof(IStringMinifier), () => stringMinifier.Value); var serializer = new Lazy <JsonNetSerializer>(); Register(typeof(IJsonSerializer), () => serializer.Value); var transportManager = new Lazy <TransportManager>(() => new TransportManager(this)); Register(typeof(ITransportManager), () => transportManager.Value); var configurationManager = new DefaultConfigurationManager(); Register(typeof(IConfigurationManager), () => configurationManager); var transportHeartbeat = new Lazy <TransportHeartbeat>(() => new TransportHeartbeat(this)); Register(typeof(ITransportHeartbeat), () => transportHeartbeat.Value); var connectionManager = new Lazy <ConnectionManager>(() => new ConnectionManager(this)); Register(typeof(IConnectionManager), () => connectionManager.Value); var ackHandler = new Lazy <AckHandler>(); Register(typeof(IAckHandler), () => ackHandler.Value); var perfCounterWriter = new Lazy <PerformanceCounterManager>(() => new PerformanceCounterManager(this)); Register(typeof(IPerformanceCounterManager), () => perfCounterWriter.Value); var protectedData = new DefaultProtectedData(); Register(typeof(IProtectedData), () => protectedData); }
public static void Scaleout(int nodes, int clients) { var hosts = new MemoryHost[nodes]; var random = new Random(); var eventBus = new EventBus(); var protectedData = new DefaultProtectedData(); for (var i = 0; i < nodes; ++i) { var host = new MemoryHost(); host.Configure(app => { var config = new HubConfiguration() { Resolver = new DefaultDependencyResolver() }; var delay = i % 2 == 0 ? TimeSpan.Zero : TimeSpan.FromSeconds(1); var bus = new DelayedMessageBus(host.InstanceName, eventBus, config.Resolver, delay); config.Resolver.Register(typeof(IMessageBus), () => bus); app.MapSignalR(config); config.Resolver.Register(typeof(IProtectedData), () => protectedData); }); hosts[i] = host; } var client = new LoadBalancer(hosts); var wh = new ManualResetEventSlim(); for (int i = 0; i < clients; i++) { Task.Run(() => RunLoop(client, wh)); } wh.Wait(); }
private static IAppBuilder UseSignalRMiddleware <T>(this IAppBuilder builder, params object[] args) { ConnectionConfiguration configuration = null; // Ensure we have the conversions for MS.Owin so that // the app builder respects the OwinMiddleware base class SignatureConversions.AddConversions(builder); if (args.Length > 0) { configuration = args[args.Length - 1] as ConnectionConfiguration; if (configuration == null) { throw new ArgumentException(Resources.Error_NoConfiguration); } var resolver = configuration.Resolver; if (resolver == null) { throw new ArgumentException(Resources.Error_NoDependencyResolver); } var env = builder.Properties; CancellationToken token = env.GetShutdownToken(); // If we don't get a valid instance name then generate a random one string instanceName = env.GetAppInstanceName() ?? Guid.NewGuid().ToString(); // Use the data protection provider from app builder and fallback to the // Dpapi provider IDataProtectionProvider provider = builder.GetDataProtectionProvider(); IProtectedData protectedData; // If we're using DPAPI then fallback to the default protected data if running // on mono since it doesn't support any of this if (provider == null && MonoUtility.IsRunningMono) { protectedData = new DefaultProtectedData(); } else { if (provider == null) { provider = new DpapiDataProtectionProvider(instanceName); } protectedData = new DataProtectionProviderProtectedData(provider); } resolver.Register(typeof(IProtectedData), () => protectedData); // If the host provides trace output then add a default trace listener TextWriter traceOutput = env.GetTraceOutput(); if (traceOutput != null) { var hostTraceListener = new TextWriterTraceListener(traceOutput); var traceManager = new TraceManager(hostTraceListener); resolver.Register(typeof(ITraceManager), () => traceManager); } // Try to get the list of reference assemblies from the host IEnumerable <Assembly> referenceAssemblies = env.GetReferenceAssemblies(); if (referenceAssemblies != null) { // Use this list as the assembly locator var assemblyLocator = new EnumerableOfAssemblyLocator(referenceAssemblies); resolver.Register(typeof(IAssemblyLocator), () => assemblyLocator); } resolver.InitializeHost(instanceName, token); } builder.Use(typeof(T), args); // BUG 2306: We need to make that SignalR runs before any handlers are // mapped in the IIS pipeline so that we avoid side effects like // session being enabled. The session behavior can be // manually overridden if user calls SetSessionStateBehavior but that shouldn't // be a problem most of the time. builder.UseStageMarker(PipelineStage.PostAuthorize); return(builder); }