/// <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;
                }
            });
        }
Esempio n. 2
0
        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));
            }
        }
Esempio n. 3
0
        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);
        }
Esempio n. 4
0
        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();
        }
Esempio n. 5
0
        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);
        }