public async Task SendToGroupFromOutsideOfHub() { using (var host = new MemoryHost()) { IHubContext<IBasicClient> hubContext = null; host.Configure(app => { var configuration = new HubConfiguration { Resolver = new DefaultDependencyResolver() }; app.MapSignalR(configuration); hubContext = configuration.Resolver.Resolve<IConnectionManager>().GetHubContext<SendToSome, IBasicClient>(); }); var connection1 = new HubConnection("http://foo/"); using (connection1) { var wh1 = new AsyncManualResetEvent(initialState: false); var hub1 = connection1.CreateHubProxy("SendToSome"); await connection1.Start(host); hub1.On("send", wh1.Set); hubContext.Groups.Add(connection1.ConnectionId, "Foo").Wait(); hubContext.Clients.Group("Foo").send(); Assert.True(await wh1.WaitAsync(TimeSpan.FromSeconds(10))); } } }
public void AuthenticatedAndAuthorizedUserCanInvokeMethodsInHubsAuthorizedSpecifyingUserAndRole() { using (var host = new MemoryHost()) { host.Configure(app => { var configuration = new HubConfiguration { Resolver = new DefaultDependencyResolver() }; WithUser(app, new GenericPrincipal(new GenericIdentity("User"), new string[] { "Admin" })); app.MapHubs("/signalr", configuration); }); var connection = CreateHubConnection("http://foo/"); var hub = connection.CreateHubProxy("UserAndRoleAuthHub"); var wh = new ManualResetEvent(false); hub.On<string, string>("invoked", (id, time) => { Assert.NotNull(id); wh.Set(); }); connection.Start(host).Wait(); hub.InvokeWithTimeout("InvokedFromClient"); Assert.True(wh.WaitOne(TimeSpan.FromSeconds(3))); connection.Stop(); } }
public async Task AuthenticatedUserCanReceiveHubMessagesByDefault() { using (var host = new MemoryHost()) { host.Configure(app => { var configuration = new HubConfiguration { Resolver = new DefaultDependencyResolver() }; WithUser(app, new GenericPrincipal(new GenericIdentity("test"), new string[] { })); app.MapSignalR("/signalr", configuration); }); var connection = CreateHubConnection("http://foo/"); using (connection) { var hub = connection.CreateHubProxy("NoAuthHub"); var wh = new ManualResetEvent(false); hub.On<string, string, object>("joined", (id, time, authInfo) => { Assert.NotNull(id); wh.Set(); }); await connection.Start(host); Assert.True(wh.WaitOne(TimeSpan.FromSeconds(3))); } } }
public static IDisposable StressGroups(int max = 100) { var host = new MemoryHost(); host.Configure(app => { var config = new HubConfiguration() { Resolver = new DefaultDependencyResolver() }; app.MapSignalR(config); var configuration = config.Resolver.Resolve<IConfigurationManager>(); // The below effectively sets the heartbeat interval to five seconds. configuration.KeepAlive = TimeSpan.FromSeconds(10); }); var countDown = new CountDownRange<int>(Enumerable.Range(0, max)); var connection = new HubConnection("http://foo"); var proxy = connection.CreateHubProxy("HubWithGroups"); proxy.On<int>("Do", i => { if (!countDown.Mark(i)) { Debugger.Break(); } }); try { connection.Start(new Client.Transports.LongPollingTransport(host)).Wait(); proxy.Invoke("Join", "foo").Wait(); for (int i = 0; i < max; i++) { proxy.Invoke("Send", "foo", i).Wait(); } proxy.Invoke("Leave", "foo").Wait(); for (int i = max + 1; i < max + 50; i++) { proxy.Invoke("Send", "foo", i).Wait(); } if (!countDown.Wait(TimeSpan.FromSeconds(10))) { Console.WriteLine("Didn't receive " + max + " messages. Got " + (max - countDown.Count) + " missed " + String.Join(",", countDown.Left.Select(i => i.ToString()))); Debugger.Break(); } } finally { connection.Stop(); } return host; }
public void Configuration(IAppBuilder app) { app.MapSignalR<SendingConnection>("/sending-connection"); app.MapSignalR<TestConnection>("/test-connection"); app.MapSignalR<RawConnection>("/raw-connection"); app.MapSignalR<StreamingConnection>("/streaming-connection"); app.Use(typeof(ClaimsMiddleware)); ConfigureSignalR(GlobalHost.DependencyResolver, GlobalHost.HubPipeline); var config = new HubConfiguration() { EnableDetailedErrors = true }; app.MapSignalR(config); app.Map("/cors", map => { map.UseCors(CorsOptions.AllowAll); map.MapSignalR<RawConnection>("/raw-connection"); map.MapSignalR(); }); app.Map("/basicauth", map => { map.UseBasicAuthentication(new BasicAuthenticationProvider()); map.MapSignalR<AuthenticatedEchoConnection>("/echo"); map.MapSignalR(); }); BackgroundThread.Start(); }
public static IDisposable BrodcastFromServer() { var host = new MemoryHost(); IHubContext context = null; host.Configure(app => { var config = new HubConfiguration() { Resolver = new DefaultDependencyResolver() }; app.MapHubs(config); var configuration = config.Resolver.Resolve<IConfigurationManager>(); // The below effectively sets the heartbeat interval to five seconds. configuration.KeepAlive = TimeSpan.FromSeconds(10); var connectionManager = config.Resolver.Resolve<IConnectionManager>(); context = connectionManager.GetHubContext("EchoHub"); }); var cancellationTokenSource = new CancellationTokenSource(); var thread = new Thread(() => { while (!cancellationTokenSource.IsCancellationRequested) { context.Clients.All.echo(); } }); thread.Start(); var connection = new Client.Hubs.HubConnection("http://foo"); var proxy = connection.CreateHubProxy("EchoHub"); try { connection.Start(host).Wait(); Thread.Sleep(1000); } finally { connection.Stop(); } return new DisposableAction(() => { cancellationTokenSource.Cancel(); thread.Join(); host.Dispose(); }); }
protected override void ConfigureApp(IAppBuilder app) { var config = new HubConfiguration { Resolver = Resolver }; app.MapHubs(config); config.Resolver.Register(typeof(IProtectedData), () => new EmptyProtectedData()); }
public async Task GroupsWorkAfterServerRestart() { var host = new ServerRestarter(app => { var config = new HubConfiguration { Resolver = new DefaultDependencyResolver() }; app.MapSignalR(config); }); using (host) { using (var connection = CreateHubConnection("http://foo/")) { var reconnectedEvent = new AsyncManualResetEvent(); connection.Reconnected += reconnectedEvent.Set; var hubProxy = connection.CreateHubProxy("groupChat"); var sendEvent = new AsyncManualResetEvent(); string sendMessage = null; hubProxy.On<string>("send", message => { sendMessage = message; sendEvent.Set(); }); var groupName = "group$&+,/:;=?@[]1"; var groupMessage = "hello"; // MemoryHost doesn't support WebSockets, and it is difficult to ensure that // the reconnected event is reliably fired with the LongPollingTransport. await connection.Start(new ServerSentEventsTransport(host)); await hubProxy.Invoke("Join", groupName); host.Restart(); Assert.True(await reconnectedEvent.WaitAsync(TimeSpan.FromSeconds(15)), "Timed out waiting for client side reconnect."); await hubProxy.Invoke("Send", groupName, groupMessage); Assert.True(await sendEvent.WaitAsync(TimeSpan.FromSeconds(15)), "Timed out waiting for message."); Assert.Equal(groupMessage, sendMessage); } } }
public void DisconnectFiresForHubsWhenConnectionGoesAway() { using (var host = new MemoryHost()) { var dr = new DefaultDependencyResolver(); var configuration = dr.Resolve<IConfigurationManager>(); var connectWh = new ManualResetEventSlim(); var disconnectWh = new ManualResetEventSlim(); host.Configure(app => { var config = new HubConfiguration { Resolver = dr }; app.MapHubs("/signalr", config); configuration.DisconnectTimeout = TimeSpan.Zero; configuration.HeartbeatInterval = TimeSpan.FromSeconds(5); dr.Register(typeof(MyHub), () => new MyHub(connectWh, disconnectWh)); }); var connection = new Client.Hubs.HubConnection("http://foo/"); connection.CreateHubProxy("MyHub"); // Maximum wait time for disconnect to fire (3 heart beat intervals) var disconnectWait = TimeSpan.FromTicks(configuration.HeartbeatInterval.Ticks * 3); connection.Start(host).Wait(); Assert.True(connectWh.Wait(TimeSpan.FromSeconds(10)), "Connect never fired"); connection.Stop(); Assert.True(disconnectWh.Wait(disconnectWait), "Disconnect never fired"); } }
public void CreatedHubsGetDisposed() { var mockHubs = new List<Mock<IHub>>(); using (var host = new MemoryHost()) { host.Configure(app => { var config = new HubConfiguration { Resolver = new DefaultDependencyResolver() }; app.MapHubs("/signalr", config); config.Resolver.Register(typeof(IHub), () => { var mockHub = new Mock<IHub>() { CallBase = true }; mockHubs.Add(mockHub); return mockHub.Object; }); }); var connection = new Client.Hubs.HubConnection("http://foo/"); var hub = connection.CreateHubProxy("demo"); connection.Start(host).Wait(); var result = hub.InvokeWithTimeout<string>("ReadStateValue"); foreach (var mockDemoHub in mockHubs) { mockDemoHub.Verify(d => d.Dispose(), Times.Once()); } connection.Stop(); } }
public void SendToSpecificClientFromOutsideOfHub() { using (var host = new MemoryHost()) { IHubContext hubContext = null; host.Configure(app => { var configuration = new HubConfiguration { Resolver = new DefaultDependencyResolver() }; app.MapHubs(configuration); hubContext = configuration.Resolver.Resolve<IConnectionManager>().GetHubContext("SendToSome"); }); var connection1 = new Client.Hubs.HubConnection("http://foo/"); var wh1 = new ManualResetEventSlim(initialState: false); var hub1 = connection1.CreateHubProxy("SendToSome"); connection1.Start(host).Wait(); hub1.On("send", wh1.Set); hubContext.Clients.Client(connection1.ConnectionId).send(); Assert.True(wh1.Wait(TimeSpan.FromSeconds(10))); connection1.Stop(); } }
public void Configuration(IAppBuilder app) { app.MapSignalR <SendingConnection>("/sending-connection"); app.MapSignalR <TestConnection>("/test-connection"); app.MapSignalR <RawConnection>("/raw-connection"); app.MapSignalR <StreamingConnection>("/streaming-connection"); app.Use(typeof(ClaimsMiddleware)); ConfigureSignalR(GlobalHost.DependencyResolver, GlobalHost.HubPipeline); var config = new HubConfiguration() { EnableDetailedErrors = true }; app.MapSignalR(config); app.Map("/cors", map => { map.UseCors(CorsOptions.AllowAll); map.MapSignalR <RawConnection>("/raw-connection"); map.MapSignalR(); }); app.Map("/cookieauth", map => { var options = new CookieAuthenticationOptions() { AuthenticationType = CookieAuthenticationDefaults.AuthenticationType, LoginPath = CookieAuthenticationDefaults.LoginPath, LogoutPath = CookieAuthenticationDefaults.LogoutPath, }; map.UseCookieAuthentication(options); map.Use(async(context, next) => { if (context.Request.Path.Value.Contains(options.LoginPath.Value)) { if (context.Request.Method == "POST") { var form = await context.Request.ReadFormAsync(); var userName = form["UserName"]; var password = form["Password"]; var identity = new ClaimsIdentity(options.AuthenticationType); identity.AddClaim(new Claim(ClaimTypes.Name, userName)); context.Authentication.SignIn(identity); } } else { await next(); } }); map.MapSignalR <AuthenticatedEchoConnection>("/echo"); map.MapSignalR(); }); BackgroundThread.Start(); }
public HubDispatcherHandler(AppFunc next, string path, HubConfiguration configuration) { _next = next; _path = path; _configuration = configuration; }
public void GroupsTokenIsPerConnectionId() { using (var host = new MemoryHost()) { IProtectedData protectedData = null; host.Configure(app => { var config = new HubConfiguration { Resolver = new DefaultDependencyResolver() }; app.MapSignalR <MyGroupConnection>("/echo", config); protectedData = config.Resolver.Resolve <IProtectedData>(); }); var connection = new Client.Connection("http://memoryhost/echo"); using (connection) { var inGroup = new ManualResetEventSlim(); connection.Received += data => { if (data == "group") { inGroup.Set(); } }; connection.Start(host).Wait(); inGroup.Wait(); Assert.NotNull(connection.GroupsToken); var spyWh = new ManualResetEventSlim(); var hackerConnection = new Client.Connection(connection.Url) { ConnectionId = "hacker" }; var url = GetUrl(protectedData, connection, connection.GroupsToken); var response = host.Get(url).Result; var reader = new EventSourceStreamReader(hackerConnection, response.GetStream()); reader.Message = sseEvent => { if (sseEvent.EventType == EventType.Data && sseEvent.Data != "initialized" && sseEvent.Data != "{}") { spyWh.Set(); } }; reader.Start(); connection.Send("random").Wait(); Assert.False(spyWh.Wait(TimeSpan.FromSeconds(5))); } } }
private static void InitializePlatform( IAppBuilder app, IUnityContainer container, IPathMapper pathMapper, string connectionString, HangfireLauncher hangfireLauncher, string modulesPath, ModuleInitializerOptions moduleInitializerOptions) { container.RegisterType <ICurrentUser, CurrentUser>(new HttpContextLifetimeManager()); container.RegisterType <IUserNameResolver, UserNameResolver>(); #region Setup database using (var db = new SecurityDbContext(connectionString)) { new IdentityDatabaseInitializer().InitializeDatabase(db); } using (var context = new PlatformRepository(connectionString, container.Resolve <AuditableInterceptor>(), new EntityPrimaryKeyGeneratorInterceptor())) { new PlatformDatabaseInitializer().InitializeDatabase(context); } hangfireLauncher.ConfigureDatabase(); #endregion Func <IPlatformRepository> platformRepositoryFactory = () => new PlatformRepository(connectionString, container.Resolve <AuditableInterceptor>(), new EntityPrimaryKeyGeneratorInterceptor()); container.RegisterType <IPlatformRepository>(new InjectionFactory(c => platformRepositoryFactory())); container.RegisterInstance(platformRepositoryFactory); var moduleCatalog = container.Resolve <IModuleCatalog>(); #region Caching //Cure for System.Runtime.Caching.MemoryCache freezing //https://www.zpqrtbnk.net/posts/appdomains-threads-cultureinfos-and-paracetamol app.SanitizeThreadCulture(); ICacheManager <object> cacheManager = null; var redisConnectionString = ConfigurationHelper.GetConnectionStringValue("RedisConnectionString"); //Try to load cache configuration from web.config first //Should be aware to using Web cache cache handle because it not worked in native threads. (Hangfire jobs) if (ConfigurationManager.GetSection(CacheManagerSection.DefaultSectionName) is CacheManagerSection cacheManagerSection) { CacheManagerConfiguration configuration = null; var defaultCacheManager = cacheManagerSection.CacheManagers.FirstOrDefault(p => p.Name.EqualsInvariant("platformCache")); if (defaultCacheManager != null) { configuration = ConfigurationBuilder.LoadConfiguration(defaultCacheManager.Name); } var redisCacheManager = cacheManagerSection.CacheManagers.FirstOrDefault(p => p.Name.EqualsInvariant("redisPlatformCache")); if (redisConnectionString != null && redisCacheManager != null) { configuration = ConfigurationBuilder.LoadConfiguration(redisCacheManager.Name); configuration.BackplaneChannelName = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Cache:Redis:ChannelName"); } if (configuration != null) { configuration.LoggerFactoryType = typeof(CacheManagerLoggerFactory); configuration.LoggerFactoryTypeArguments = new object[] { container.Resolve <ILog>() }; cacheManager = CacheFactory.FromConfiguration <object>(configuration); } } // Create a default cache manager if there is no any others if (cacheManager == null) { cacheManager = CacheFactory.Build("platformCache", settings => { settings.WithUpdateMode(CacheUpdateMode.Up) .WithSystemRuntimeCacheHandle("memCacheHandle") .WithExpiration(ExpirationMode.Sliding, TimeSpan.FromMinutes(5)); }); } container.RegisterInstance(cacheManager); #endregion #region Settings var platformModuleManifest = new ModuleManifest { Id = "VirtoCommerce.Platform", Version = PlatformVersion.CurrentVersion.ToString(), PlatformVersion = PlatformVersion.CurrentVersion.ToString(), Settings = new[] { new ModuleSettingsGroup { Name = "Platform|Notifications|SendGrid", Settings = new [] { new ModuleSetting { Name = "VirtoCommerce.Platform.Notifications.SendGrid.ApiKey", ValueType = ModuleSetting.TypeSecureString, Title = "SendGrid API key", Description = "Your SendGrid API key" } } }, new ModuleSettingsGroup { Name = "Platform|Notifications|SendingJob", Settings = new [] { new ModuleSetting { Name = "VirtoCommerce.Platform.Notifications.SendingJob.TakeCount", ValueType = ModuleSetting.TypeInteger, Title = "Job Take Count", Description = "Take count for sending job" } } }, new ModuleSettingsGroup { Name = "Platform|Notifications|SmtpClient", Settings = new [] { new ModuleSetting { Name = "VirtoCommerce.Platform.Notifications.SmptClient.Host", ValueType = ModuleSetting.TypeString, Title = "Smtp server host", Description = "Smtp server host" }, new ModuleSetting { Name = "VirtoCommerce.Platform.Notifications.SmptClient.Port", ValueType = ModuleSetting.TypeInteger, Title = "Smtp server port", Description = "Smtp server port" }, new ModuleSetting { Name = "VirtoCommerce.Platform.Notifications.SmptClient.Login", ValueType = ModuleSetting.TypeString, Title = "Smtp server login", Description = "Smtp server login" }, new ModuleSetting { Name = "VirtoCommerce.Platform.Notifications.SmptClient.Password", ValueType = ModuleSetting.TypeSecureString, Title = "Smtp server password", Description = "Smtp server password" }, new ModuleSetting { Name = "VirtoCommerce.Platform.Notifications.SmptClient.UseSsl", ValueType = ModuleSetting.TypeBoolean, Title = "Use SSL", Description = "Use secure connection" }, } }, new ModuleSettingsGroup { Name = "Platform|Security", Settings = new [] { new ModuleSetting { Name = "VirtoCommerce.Platform.Security.AccountTypes", ValueType = ModuleSetting.TypeString, Title = "Account types", Description = "Dictionary for possible account types", IsArray = true, ArrayValues = Enum.GetNames(typeof(AccountType)), DefaultValue = AccountType.Manager.ToString() } } }, new ModuleSettingsGroup { Name = "Platform|User Profile", Settings = new[] { new ModuleSetting { Name = "VirtoCommerce.Platform.UI.MainMenu.State", ValueType = ModuleSetting.TypeJson, Title = "Persisted state of main menu" }, new ModuleSetting { Name = "VirtoCommerce.Platform.UI.Language", ValueType = ModuleSetting.TypeString, Title = "Language", Description = "Default language (two letter code from ISO 639-1, case-insensitive). Example: en, de", DefaultValue = "en" }, new ModuleSetting { Name = "VirtoCommerce.Platform.UI.RegionalFormat", ValueType = ModuleSetting.TypeString, Title = "Regional format", Description = "Default regional format (CLDR locale code, with dash or underscore as delemiter, case-insensitive). Example: en, en_US, sr_Cyrl, sr_Cyrl_RS", DefaultValue = "en" }, new ModuleSetting { Name = "VirtoCommerce.Platform.UI.TimeZone", ValueType = ModuleSetting.TypeString, Title = "Time zone", Description = "Default time zone (IANA time zone name [tz database], exactly as in database, case-sensitive). Examples: America/New_York, Europe/Moscow" }, new ModuleSetting { Name = "VirtoCommerce.Platform.UI.ShowMeridian", ValueType = ModuleSetting.TypeBoolean, Title = "Meridian labels based on user preferences", Description = "When set to true (by default), system will display time in format like '12 hour format' when possible", DefaultValue = true.ToString() }, new ModuleSetting { Name = "VirtoCommerce.Platform.UI.UseTimeAgo", ValueType = ModuleSetting.TypeBoolean, Title = "Use time ago format when is possible", Description = "When set to true (by default), system will display date in format like 'a few seconds ago' when possible", DefaultValue = true.ToString() }, new ModuleSetting { Name = "VirtoCommerce.Platform.UI.FullDateThreshold", ValueType = ModuleSetting.TypeInteger, Title = "Full date threshold", Description = "Number of units after time ago format will be switched to full date format" }, new ModuleSetting { Name = "VirtoCommerce.Platform.UI.FullDateThresholdUnit", ValueType = ModuleSetting.TypeString, Title = "Full date threshold unit", Description = "Unit of full date threshold", DefaultValue = "Never", AllowedValues = new[] { "Never", "Seconds", "Minutes", "Hours", "Days", "Weeks", "Months", "Quarters", "Years" } }, new ModuleSetting { Name = "VirtoCommerce.Platform.UI.FourDecimalsInMoney", ValueType = ModuleSetting.TypeBoolean, Title = "Show 4 decimal digits for money", Description = "Set to true to show 4 decimal digits for money. By default - false, 2 decimal digits are shown.", DefaultValue = "false", }, } }, new ModuleSettingsGroup { Name = "Platform|User Interface", Settings = new[] { new ModuleSetting { Name = "VirtoCommerce.Platform.UI.Customization", ValueType = ModuleSetting.TypeJson, Title = "Customization", Description = "JSON contains personalization settings of manager UI", DefaultValue = "{\n" + " \"title\": \"Virto Commerce\",\n" + " \"logo\": \"Content/themes/main/images/logo.png\",\n" + " \"contrast_logo\": \"Content/themes/main/images/contrast-logo.png\",\n" + " \"favicon\": \"favicon.ico\"\n" + "}" } } } } }; var settingsManager = new SettingsManager(moduleCatalog, platformRepositoryFactory, cacheManager, new[] { new ManifestModuleInfo(platformModuleManifest) }); container.RegisterInstance <ISettingsManager>(settingsManager); #endregion #region Dynamic Properties container.RegisterType <IDynamicPropertyService, DynamicPropertyService>(new ContainerControlledLifetimeManager()); #endregion #region Notifications // Redis if (!string.IsNullOrEmpty(redisConnectionString)) { // Cache RedisConfigurations.AddConfiguration(new RedisConfiguration("redisConnectionString", redisConnectionString)); // SignalR // https://stackoverflow.com/questions/29885470/signalr-scaleout-on-azure-rediscache-connection-issues GlobalHost.DependencyResolver.UseRedis(new RedisScaleoutConfiguration(redisConnectionString, "VirtoCommerce.Platform.SignalR")); } // SignalR var tempCounterManager = new TempPerformanceCounterManager(); GlobalHost.DependencyResolver.Register(typeof(IPerformanceCounterManager), () => tempCounterManager); var hubConfiguration = new HubConfiguration { EnableJavaScriptProxies = false }; app.MapSignalR("/" + moduleInitializerOptions.RoutePrefix + "signalr", hubConfiguration); var hubSignalR = GlobalHost.ConnectionManager.GetHubContext <ClientPushHub>(); var notifier = new InMemoryPushNotificationManager(hubSignalR); container.RegisterInstance <IPushNotificationManager>(notifier); var resolver = new LiquidNotificationTemplateResolver(); container.RegisterInstance <INotificationTemplateResolver>(resolver); var notificationTemplateService = new NotificationTemplateServiceImpl(platformRepositoryFactory); container.RegisterInstance <INotificationTemplateService>(notificationTemplateService); var notificationManager = new NotificationManager(resolver, platformRepositoryFactory, notificationTemplateService); container.RegisterInstance <INotificationManager>(notificationManager); IEmailNotificationSendingGateway emailNotificationSendingGateway = null; var emailNotificationSendingGatewayName = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Notifications:Gateway", "Default"); if (string.Equals(emailNotificationSendingGatewayName, "Default", StringComparison.OrdinalIgnoreCase)) { emailNotificationSendingGateway = new DefaultSmtpEmailNotificationSendingGateway(settingsManager); } else if (string.Equals(emailNotificationSendingGatewayName, "SendGrid", StringComparison.OrdinalIgnoreCase)) { emailNotificationSendingGateway = new SendGridEmailNotificationSendingGateway(settingsManager); } if (emailNotificationSendingGateway != null) { container.RegisterInstance(emailNotificationSendingGateway); } ISmsNotificationSendingGateway smsNotificationSendingGateway = null; var smsNotificationSendingGatewayName = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Notifications:SmsGateway", "Default"); if (smsNotificationSendingGatewayName.EqualsInvariant("Twilio")) { smsNotificationSendingGateway = new TwilioSmsNotificationSendingGateway(new TwilioSmsGatewayOptions { AccountId = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Notifications:SmsGateway:AccountId"), AccountPassword = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Notifications:SmsGateway:AccountPassword"), Sender = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Notifications:SmsGateway:Sender"), }); } else if (smsNotificationSendingGatewayName.EqualsInvariant("ASPSMS")) { smsNotificationSendingGateway = new AspsmsSmsNotificationSendingGateway(new AspsmsSmsGatewayOptions { AccountId = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Notifications:SmsGateway:AccountId"), AccountPassword = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Notifications:SmsGateway:AccountPassword"), Sender = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Notifications:SmsGateway:Sender"), JsonApiUri = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Notifications:SmsGateway:ASPSMS:JsonApiUri"), }); } else { smsNotificationSendingGateway = new DefaultSmsNotificationSendingGateway(); } container.RegisterInstance(smsNotificationSendingGateway); #endregion #region Assets var blobConnectionString = BlobConnectionString.Parse(ConfigurationHelper.GetConnectionStringValue("AssetsConnectionString")); if (string.Equals(blobConnectionString.Provider, FileSystemBlobProvider.ProviderName, StringComparison.OrdinalIgnoreCase)) { var fileSystemBlobProvider = new FileSystemBlobProvider(NormalizePath(pathMapper, blobConnectionString.RootPath), blobConnectionString.PublicUrl); container.RegisterInstance <IBlobStorageProvider>(fileSystemBlobProvider); container.RegisterInstance <IBlobUrlResolver>(fileSystemBlobProvider); } else if (string.Equals(blobConnectionString.Provider, AzureBlobProvider.ProviderName, StringComparison.OrdinalIgnoreCase)) { var azureBlobProvider = new AzureBlobProvider(blobConnectionString.ConnectionString, blobConnectionString.CdnUrl); container.RegisterInstance <IBlobStorageProvider>(azureBlobProvider); container.RegisterInstance <IBlobUrlResolver>(azureBlobProvider); } container.RegisterType <IAssetEntryService, AssetEntryService>(new ContainerControlledLifetimeManager()); container.RegisterType <IAssetEntrySearchService, AssetEntryService>(new ContainerControlledLifetimeManager()); #endregion #region Modularity var modulesDataSources = ConfigurationHelper.SplitAppSettingsStringValue("VirtoCommerce:ModulesDataSources"); var externalModuleCatalog = new ExternalManifestModuleCatalog(moduleCatalog.Modules, modulesDataSources, container.Resolve <ILog>()); container.RegisterType <ModulesController>(new InjectionConstructor(externalModuleCatalog, new ModuleInstaller(modulesPath, externalModuleCatalog), notifier, container.Resolve <IUserNameResolver>(), settingsManager)); #endregion #region ChangeLogging var changeLogService = new ChangeLogService(platformRepositoryFactory); container.RegisterInstance <IChangeLogService>(changeLogService); #endregion #region Security container.RegisterInstance <IPermissionScopeService>(new PermissionScopeService()); container.RegisterType <IRoleManagementService, RoleManagementService>(new ContainerControlledLifetimeManager()); var apiAccountProvider = new ApiAccountProvider(platformRepositoryFactory, cacheManager); container.RegisterInstance <IApiAccountProvider>(apiAccountProvider); container.RegisterType <IClaimsIdentityProvider, ApplicationClaimsIdentityProvider>(new ContainerControlledLifetimeManager()); container.RegisterInstance(app.GetDataProtectionProvider()); container.RegisterType <SecurityDbContext>(new InjectionConstructor(connectionString)); container.RegisterType <IUserStore <ApplicationUser>, ApplicationUserStore>(); container.RegisterType <IAuthenticationManager>(new InjectionFactory(c => HttpContext.Current.GetOwinContext().Authentication)); container.RegisterType <ApplicationUserManager>(); container.RegisterType <ApplicationSignInManager>(); var nonEditableUsers = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:NonEditableUsers", string.Empty); container.RegisterInstance <ISecurityOptions>(new SecurityOptions(nonEditableUsers)); container.RegisterType <ISecurityService, SecurityService>(); container.RegisterType <IPasswordCheckService, PasswordCheckService>(); #endregion #region ExportImport container.RegisterType <IPlatformExportImportManager, PlatformExportImportManager>(); #endregion #region Serialization container.RegisterType <IExpressionSerializer, XmlExpressionSerializer>(); #endregion #region Events var inProcessBus = new InProcessBus(); container.RegisterInstance <IHandlerRegistrar>(inProcessBus); container.RegisterInstance <IEventPublisher>(inProcessBus); inProcessBus.RegisterHandler <UserChangedEvent>(async(message, token) => await container.Resolve <LogChangesUserChangedEventHandler>().Handle(message)); inProcessBus.RegisterHandler <UserPasswordChangedEvent>(async(message, token) => await container.Resolve <LogChangesUserChangedEventHandler>().Handle(message)); inProcessBus.RegisterHandler <UserResetPasswordEvent>(async(message, token) => await container.Resolve <LogChangesUserChangedEventHandler>().Handle(message)); #endregion }
public async Task DisconnectFiresForHubsWhenClientCallsStop() { using (var host = new MemoryHost()) { var dr = new DefaultDependencyResolver(); var configuration = dr.Resolve<IConfigurationManager>(); var connectWh = new AsyncManualResetEvent(); var disconnectWh = new AsyncManualResetEvent(); host.Configure(app => { var config = new HubConfiguration { Resolver = dr }; app.MapSignalR("/signalr", config); configuration.DisconnectTimeout = TimeSpan.FromSeconds(6); dr.Register(typeof(MyHub), () => new MyHub(connectWh, disconnectWh)); }); var connection = new HubConnection("http://foo/"); connection.CreateHubProxy("MyHub"); // Maximum wait time for disconnect to fire (3 heart beat intervals) var disconnectWait = TimeSpan.FromTicks(configuration.HeartbeatInterval().Ticks * 3); await connection.Start(host); Assert.True(await connectWh.WaitAsync(TimeSpan.FromSeconds(10)), "Connect never fired"); connection.Stop(); Assert.True(await disconnectWh.WaitAsync(disconnectWait), "Disconnect never fired"); } }
/// <summary> /// Maps Azure SignalR hubs to the app builder pipeline at "/signalr". /// </summary> /// <param name="builder">The app builder <see cref="IAppBuilder"/>.</param> /// <param name="applicationName">The name of your app, it is case-incensitive.</param> /// <param name="configuration">The hub configuration <see cref="HubConfiguration"/>.</param> /// <param name="optionsConfigure">A callback to configure the <see cref="ServiceOptions"/>.</param> /// <returns>The app builder</returns> public static IAppBuilder MapAzureSignalR(this IAppBuilder builder, string applicationName, HubConfiguration configuration, Action <ServiceOptions> optionsConfigure) { return(builder.MapAzureSignalR("/signalr", applicationName, configuration, optionsConfigure)); }
/// <summary> /// Maps Azure SignalR hubs to the app builder pipeline at the specified path. /// </summary> /// <param name="builder">The app builder <see cref="IAppBuilder"/>.</param> /// <param name="path">The path to map signalr hubs.</param> /// <param name="applicationName">The name of your app, it is case-incensitive.</param> /// <param name="configuration">The hub configuration <see cref="HubConfiguration"/>.</param> /// <param name="optionsConfigure">A callback to configure the <see cref="ServiceOptions"/>.</param> /// <returns>The app builder</returns> public static IAppBuilder MapAzureSignalR(this IAppBuilder builder, string path, string applicationName, HubConfiguration configuration, Action <ServiceOptions> optionsConfigure) { return(builder.Map(path, subApp => subApp.RunAzureSignalR(applicationName, configuration, optionsConfigure))); }
public ClientConnectionManager(HubConfiguration configuration, ILoggerFactory loggerFactory) { _configuration = configuration; _logger = loggerFactory?.CreateLogger <ClientConnectionManager>() ?? NullLogger <ClientConnectionManager> .Instance; }
public ClientConnectionHubDispatcher(HubConfiguration config, string connectionId) : base(config) { _connectionId = connectionId; }
// For more information on configuring authentication, please visit https://go.microsoft.com/fwlink/?LinkId=301864 public void ConfigureAuth(IAppBuilder app) { // Configure the db context, user manager and signin manager to use a single instance per request app.CreatePerOwinContext(ApplicationDbContext.Create); app.CreatePerOwinContext <ApplicationUserManager>(ApplicationUserManager.Create); app.CreatePerOwinContext <ApplicationSignInManager>(ApplicationSignInManager.Create); // Enable the application to use a cookie to store information for the signed in user // and to use a cookie to temporarily store information about a user logging in with a third party login provider // Configure the sign in cookie app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, LoginPath = new PathString("/Account/Login"), Provider = new CookieAuthenticationProvider { // Enables the application to validate the security stamp when the user logs in. // This is a security feature which is used when you change a password or add an external login to your account. OnValidateIdentity = SecurityStampValidator.OnValidateIdentity <ApplicationUserManager, ApplicationUser>( validateInterval: TimeSpan.FromMinutes(30), regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager)) }, CookieName = "ArktinMonitorCookie" }); app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie); // Configure the application for OAuth based flow PublicClientId = "self"; OAuthOptions = new OAuthAuthorizationServerOptions { TokenEndpointPath = new PathString("/Token"), Provider = new ApplicationOAuthProvider(PublicClientId), AuthorizeEndpointPath = new PathString("/Account/ExternalLogin"), AccessTokenExpireTimeSpan = TimeSpan.FromDays(30),//TODO: Change value later AllowInsecureHttp = false }; // Enable the application to use bearer tokens to authenticate users app.UseOAuthBearerTokens(OAuthOptions); // https://stackoverflow.com/questions/26657296/signalr-authentication-with-webapi-bearer-token app.Map("/signalr", map => { map.UseCors(CorsOptions.AllowAll); map.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions() { Provider = new QueryStringOAuthBearerProvider() }); var hubConfiguration = new HubConfiguration { Resolver = GlobalHost.DependencyResolver, }; map.RunSignalR(hubConfiguration); }); //app.Use(async (context, next) => //{ // if (context.Request.QueryString.HasValue) // { // foreach (var header in context.Request.Headers) // { // Debug.WriteLine($"Header: {header.Key}"); // foreach (var value in header.Value) // { // Debug.WriteLine($"Value: {value}"); // } // } // if (string.IsNullOrWhiteSpace(context.Request.Headers.Get("Authorization"))) // { // var queryString = HttpUtility.ParseQueryString(context.Request.QueryString.Value); // string token = queryString.Get("access_token"); // if (!string.IsNullOrWhiteSpace(token)) // { // context.Request.Headers.Add("Authorization", new[] { $"Bearer {token}" }); // } // } // } // await next.Invoke(); //}); // Enables the application to temporarily store user information when they are verifying the second factor in the two-factor authentication process. app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5)); // Enables the application to remember the second login verification factor such as phone or email. // Once you check this option, your second step of verification during the login process will be remembered on the device where you logged in from. // This is similar to the RememberMe option when you log in. app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie); // Uncomment the following lines to enable logging in with third party login providers //app.UseMicrosoftAccountAuthentication( // clientId: "", // clientSecret: ""); //app.UseTwitterAuthentication( // consumerKey: "", // consumerSecret: ""); //app.UseFacebookAuthentication( // appId: "", // appSecret: ""); //app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions() //{ // ClientId = "", // ClientSecret = "" //}); }
public void Configuration(IAppBuilder app) { // Modify the JSON serializer to serialize dates as UTC - otherwise, timezone will not be appended // to date strings and browsers will select whatever timezone suits them JsonSerializerSettings settings = JsonUtility.CreateDefaultSerializerSettings(); settings.DateTimeZoneHandling = DateTimeZoneHandling.Utc; JsonSerializer serializer = JsonSerializer.Create(settings); GlobalHost.DependencyResolver.Register(typeof(JsonSerializer), () => serializer); // Load security hub in application domain before establishing SignalR hub configuration try { using (new SecurityHub()) { } } catch (Exception ex) { throw new SecurityException($"Failed to load Security Hub, validate database connection string in configuration file: {ex.Message}", ex); } HubConfiguration hubConfig = new HubConfiguration(); HttpConfiguration httpConfig = new HttpConfiguration(); // Setup resolver for web page controller instances httpConfig.DependencyResolver = WebPageController.GetDependencyResolver(WebServer.Default, Program.Host.DefaultWebPage, new AppModel(), typeof(AppModel)); // Make sure any hosted exceptions get propagated to service error handling httpConfig.Services.Replace(typeof(IExceptionHandler), new HostedExceptionHandler()); // Enabled detailed client errors hubConfig.EnableDetailedErrors = true; // Enable GSF session management httpConfig.EnableSessions(AuthenticationOptions); // Enable GSF role-based security authentication app.UseAuthentication(AuthenticationOptions); // Enable cross-domain scripting default policy - controllers can manually // apply "EnableCors" attribute to class or an action to override default // policy configured here try { if (!string.IsNullOrWhiteSpace(Program.Host.Model.Global.DefaultCorsOrigins)) { httpConfig.EnableCors(new EnableCorsAttribute(Program.Host.Model.Global.DefaultCorsOrigins, Program.Host.Model.Global.DefaultCorsHeaders, Program.Host.Model.Global.DefaultCorsMethods) { SupportsCredentials = Program.Host.Model.Global.DefaultCorsSupportsCredentials }); } } catch (Exception ex) { Program.Host.LogException(new InvalidOperationException($"Failed to establish default CORS policy: {ex.Message}", ex)); } // Load ServiceHub SignalR class app.MapSignalR(hubConfig); // Set configuration to use reflection to setup routes httpConfig.MapHttpAttributeRoutes(); // Load the WebPageController class and assign its routes app.UseWebApi(httpConfig); // Check for configuration issues before first request httpConfig.EnsureInitialized(); }
public void RejoiningGroupsOnlyReceivesGroupsBelongingToHub() { var logRejoiningGroups = new LogRejoiningGroupsModule(); using (var host = new MemoryHost()) { host.Configure(app => { var config = new HubConfiguration { Resolver = new DefaultDependencyResolver() }; app.MapHubs("/signalr", config); config.Resolver.Resolve<IHubPipeline>().AddModule(logRejoiningGroups); var configuration = config.Resolver.Resolve<IConfigurationManager>(); // The following sets the heartbeat to 1 s configuration.DisconnectTimeout = TimeSpan.FromSeconds(6); configuration.KeepAlive = null; configuration.ConnectionTimeout = TimeSpan.FromSeconds(2); }); var connection = new Client.Hubs.HubConnection("http://foo"); var proxy = connection.CreateHubProxy("MultGroupHub"); var proxy2 = connection.CreateHubProxy("MultGroupHub2"); connection.Start(host).Wait(); var user = new User { Name = "tester" }; proxy.InvokeWithTimeout("login", user); proxy2.InvokeWithTimeout("login", user); // Force Reconnect Thread.Sleep(TimeSpan.FromSeconds(3)); proxy.InvokeWithTimeout("joinRoom", user); proxy2.InvokeWithTimeout("joinRoom", user); Thread.Sleep(TimeSpan.FromSeconds(3)); Assert.True(logRejoiningGroups.GroupsRejoined["MultGroupHub"].Contains("foo")); Assert.True(logRejoiningGroups.GroupsRejoined["MultGroupHub"].Contains("tester")); Assert.False(logRejoiningGroups.GroupsRejoined["MultGroupHub"].Contains("foo2")); Assert.False(logRejoiningGroups.GroupsRejoined["MultGroupHub"].Contains("tester2")); Assert.True(logRejoiningGroups.GroupsRejoined["MultGroupHub2"].Contains("foo2")); Assert.True(logRejoiningGroups.GroupsRejoined["MultGroupHub2"].Contains("tester2")); Assert.False(logRejoiningGroups.GroupsRejoined["MultGroupHub2"].Contains("foo")); Assert.False(logRejoiningGroups.GroupsRejoined["MultGroupHub2"].Contains("tester")); connection.Stop(); } }
public HubDispatcherMiddleware(OwinMiddleware next, HubConfiguration configuration) : base(next) { _configuration = configuration; }
public static void ConfigureSignalR(IAppBuilder app, HubConfiguration config) { //Changed this method to accept a HubConfiguration parameter //and pass it off to the MapSignalR method app.MapSignalR(config); }
public void Configuration(IAppBuilder app) { if (true) { app.Map("/signalr", map => { // Setup the CORS middleware to run before SignalR. // By default this will allow all origins. You can // configure the set of origins and/or http verbs by // providing a cors options with a different policy. map.UseCors(CorsOptions.AllowAll); var hubConfiguration = new HubConfiguration { EnableDetailedErrors = true //EnableJSONP = true // You can enable JSONP by uncommenting line below. // JSONP requests are insecure but some older browsers (and some // versions of IE) require JSONP to work cross domain // EnableJSONP = true }; // Run the SignalR pipeline. We're not using MapSignalR // since this branch already runs under the "/signalr" // path. map.RunSignalR(hubConfiguration); }); } else { //app.UseCors(CorsOptions.AllowAll); app.MapSignalR(); // replaced by the above } app.Map("/echo", a => a.Run(c => { var accept = c.Get <WebSocketAccept>("websocket.Accept"); if (accept == null) { c.Response.StatusCode = 500; return(Task.Delay(0)); } accept( null, async wsEnv => { var sendAsync = wsEnv.Get <WebSocketSendAsync>("websocket.SendAsync"); var receiveAsync = wsEnv.Get <WebSocketReceiveAsync>("websocket.ReceiveAsync"); var closeAsync = wsEnv.Get <WebSocketCloseAsync>("websocket.CloseAsync"); var buffer = new ArraySegment <byte>(new byte[1000]); var serverReceive = await receiveAsync(buffer, CancellationToken.None); await sendAsync(new ArraySegment <byte>(buffer.Array, 0, serverReceive.Item3), serverReceive.Item1, serverReceive.Item2, CancellationToken.None); await closeAsync((int)WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None); }); return(Task.Delay(0)); })); app.Run(async c => { var path = c.Request.Path.Value; if (path == "/") { c.Response.StatusCode = 200; c.Response.ContentType = "text/plain"; c.Response.Write("Hello World!"); return; } if (path == "/sse") { c.Response.StatusCode = 200; c.Response.ContentType = "text/event-stream"; c.Response.Headers.Add("Cache-Control", new[] { "no-cache" }); for (int i = 0; i < 10; i++) { await c.Response.WriteAsync("data: " + i.ToString() + "\n\n"); await c.Response.Body.FlushAsync(); await Task.Delay(500); } await c.Response.WriteAsync("data: Finish!\n\n"); return; } if (path.Contains("..")) { // hackers .. c.Response.StatusCode = 500; return; } var p = Path.Combine(@"..\..\..\SampleOwinApp\", path.Substring(1)); if (File.Exists(p)) { c.Response.StatusCode = 200; c.Response.ContentType = p.EndsWith(".js") ? "application/javascript" : "text/html"; await c.Response.WriteAsync(File.ReadAllBytes(p)); return; } c.Response.StatusCode = 404; return; }); }
public static IDisposable ManyUniqueGroups(int concurrency) { var host = new MemoryHost(); var threads = new List<Thread>(); var cancellationTokenSource = new CancellationTokenSource(); host.Configure(app => { var config = new HubConfiguration() { Resolver = new DefaultDependencyResolver() }; app.MapHubs(config); }); for (int i = 0; i < concurrency; i++) { var thread = new Thread(_ => { while (!cancellationTokenSource.IsCancellationRequested) { RunOne(host); } }); threads.Add(thread); thread.Start(); } return new DisposableAction(() => { cancellationTokenSource.Cancel(); threads.ForEach(t => t.Join()); host.Dispose(); }); }
private void ConfigureSignalR(IAppBuilder app, HubConfiguration config) { app.UseCors(CorsOptions.AllowAll); app.MapSignalR("/s", config); }
public void UnauthenticatedUserCannotInvokeMethodsWhenAuthenticationRequiredGlobally() { using (var host = new MemoryHost()) { host.Configure(app => { var configuration = new HubConfiguration { Resolver = new DefaultDependencyResolver() }; configuration.Resolver.Resolve<IHubPipeline>().RequireAuthentication(); WithUser(app, new GenericPrincipal(new GenericIdentity(""), new string[] { })); app.MapSignalR("/signalr", configuration); }); var connection = CreateHubConnection("http://foo/"); using (connection) { var hub = connection.CreateHubProxy("NoAuthHub"); var wh = new ManualResetEvent(false); hub.On<string, string>("invoked", (id, time) => { Assert.NotNull(id); wh.Set(); }); Assert.Throws<AggregateException>(() => connection.Start(host).Wait()); } } }
public static Func <AppFunc, AppFunc> Hub(HubConfiguration configuration, IDictionary <string, object> startupEnv) { return(next => BuildHubFunc(configuration, startupEnv, next)); }
public void UnauthorizedUserCannotInvokeMethodsInHubsAuthorizedSpecifyingUserAndRole() { using (var host = new MemoryHost()) { host.Configure(app => { var configuration = new HubConfiguration { Resolver = new DefaultDependencyResolver() }; WithUser(app, new GenericPrincipal(new GenericIdentity("test"), new string[] { "User", "Admin" })); app.MapSignalR("/signalr", configuration); }); var connection = CreateHubConnection("http://foo/"); using (connection) { var hub = connection.CreateHubProxy("UserAndRoleAuthHub"); var wh = new ManualResetEvent(false); hub.On<string, string>("invoked", (id, time) => { Assert.NotNull(id); wh.Set(); }); Assert.Throws<AggregateException>(() => connection.Start(host).Wait()); } } }
/// <summary> /// Maps SignalR hubs to the app builder pipeline at "/signalr". /// </summary> /// <param name="builder">The app builder</param> /// <param name="configuration">The <see cref="HubConfiguration"/> to use</param> public static IAppBuilder MapSignalR(this IAppBuilder builder, HubConfiguration configuration) { return(builder.MapSignalR("/signalr", configuration)); }
//protected abstract void RegisterSettingsFileInstance (ContainerBuilder builder); protected abstract void RegisterCustomComponents(ContainerBuilder builder, HubConfiguration hubCfg);
/// <summary> /// Adds SignalR hubs to the app builder pipeline. /// </summary> /// <param name="builder">The app builder</param> /// <param name="configuration">The <see cref="HubConfiguration"/> to use</param> public static void RunSignalR(this IAppBuilder builder, HubConfiguration configuration) { builder.UseSignalRMiddleware <HubDispatcherMiddleware>(configuration); }
public void UnauthenticatedUserCanReceiveHubMessagesFromIncomingAuthorizedHubs() { using (var host = new MemoryHost()) { host.Configure(app => { var configuration = new HubConfiguration { Resolver = new DefaultDependencyResolver() }; WithUser(app, new GenericPrincipal(new GenericIdentity(""), new string[] { "User", "NotAdmin" })); app.MapHubs("/signalr", configuration); }); var connection = CreateHubConnection("http://foo/"); var hub = connection.CreateHubProxy("IncomingAuthHub"); var wh = new ManualResetEvent(false); hub.On<string, string, object>("joined", (id, time, authInfo) => { Assert.NotNull(id); wh.Set(); }); connection.Start(host).Wait(); Assert.True(wh.WaitOne(TimeSpan.FromSeconds(3))); connection.Stop(); } }
private static void RunAzureSignalRCore(IAppBuilder builder, string applicationName, HubConfiguration configuration, ServiceOptions options) { // applicationName is case insensitive, it will be lower cased in the service side if (string.IsNullOrEmpty(applicationName)) { throw new ArgumentException(nameof(applicationName), "Empty application name is not allowed."); } var hubs = GetAvailableHubNames(configuration); // TODO: Update to use Middleware when SignalR SDK is ready // Replace default HubDispatcher with a custom one, which has its own negotiation logic // https://github.com/SignalR/SignalR/blob/dev/src/Microsoft.AspNet.SignalR.Core/Hosting/PersistentConnectionFactory.cs#L42 configuration.Resolver.Register(typeof(PersistentConnection), () => new ServiceHubDispatcher(configuration, applicationName)); builder.RunSignalR(typeof(PersistentConnection), configuration); RegisterServiceObjects(configuration, options, applicationName, hubs); ILoggerFactory logger; var traceManager = configuration.Resolver.Resolve <ITraceManager>(); if (traceManager != null) { logger = new LoggerFactory(new ILoggerProvider[] { new TraceManagerLoggerProvider(traceManager) }); } else { logger = NullLoggerFactory.Instance; } if (hubs?.Count > 0) { // Start the server->service connection asynchronously _ = new ConnectionFactory(hubs, configuration).StartAsync(); } else { logger.CreateLogger <IAppBuilder>().Log(LogLevel.Warning, "No hubs found."); } }
public void ChangeHubUrl() { using (var host = new MemoryHost()) { host.Configure(app => { var config = new HubConfiguration() { Resolver = new DefaultDependencyResolver() }; app.MapHubs("/foo", config); }); var connection = new Client.Hubs.HubConnection("http://site/foo", useDefaultUrl: false, queryString: new Dictionary<string, string> { { "test", "ChangeHubUrl" } }); var hub = connection.CreateHubProxy("demo"); var wh = new ManualResetEventSlim(false); hub.On("signal", id => { Assert.NotNull(id); wh.Set(); }); connection.Start(host).Wait(); hub.InvokeWithTimeout("DynamicTask"); Assert.True(wh.Wait(TimeSpan.FromSeconds(10))); connection.Stop(); } }
private static IReadOnlyList <string> GetAvailableHubNames(HubConfiguration configuration) { var hubManager = configuration.Resolver.Resolve <IHubManager>(); return(hubManager?.GetHubs().Select(s => s.Name).ToList()); }
public void JoiningGroupMultipleTimesGetsMessageOnce(MessageBusType messagebusType) { using (var host = new MemoryHost()) { host.Configure(app => { var config = new HubConfiguration { Resolver = new DefaultDependencyResolver() }; UseMessageBus(messagebusType, config.Resolver); app.MapHubs(config); }); var connection = new HubConnection("http://foo"); var hub = connection.CreateHubProxy("SendToSome"); int invocations = 0; connection.Start(host).Wait(); hub.On("send", () => { invocations++; }); // Join the group multiple times hub.InvokeWithTimeout("JoinGroup", "a"); hub.InvokeWithTimeout("JoinGroup", "a"); hub.InvokeWithTimeout("JoinGroup", "a"); hub.InvokeWithTimeout("SendToGroup", "a"); Thread.Sleep(TimeSpan.FromSeconds(3)); Assert.Equal(1, invocations); connection.Stop(); } }
/// <summary> /// Maps Azure SignalR hubs to the app builder pipeline at the specified path. /// </summary> /// <param name="builder">The app builder <see cref="IAppBuilder"/>.</param> /// <param name="path">The path to map signalr hubs.</param> /// <param name="applicationName">The name of your app, it is case-incensitive.</param> /// <param name="configuration">The hub configuration <see cref="HubConfiguration"/>.</param> /// <returns>The app builder</returns> public static IAppBuilder MapAzureSignalR(this IAppBuilder builder, string path, string applicationName, HubConfiguration configuration) { return(builder.Map(path, subApp => subApp.RunAzureSignalR(applicationName, configuration))); }
public void ReturningNullFromReconnectAccepted() { var mockHub = new Mock<SomeHub>() { CallBase = true }; mockHub.Setup(h => h.OnReconnected()).Returns<Task>(null).Verifiable(); using (var host = new MemoryHost()) { host.Configure(app => { var config = new HubConfiguration { Resolver = new DefaultDependencyResolver() }; app.MapHubs("/signalr", config); var configuration = config.Resolver.Resolve<IConfigurationManager>(); // The following sets the heartbeat to 1 s configuration.DisconnectTimeout = TimeSpan.FromSeconds(6); configuration.KeepAlive = null; configuration.ConnectionTimeout = TimeSpan.FromSeconds(2); config.Resolver.Register(typeof(SomeHub), () => mockHub.Object); }); var connection = new Client.Hubs.HubConnection("http://foo"); var hub = connection.CreateHubProxy("SomeHub"); connection.Start(host).Wait(); // Force Reconnect Thread.Sleep(TimeSpan.FromSeconds(3)); hub.InvokeWithTimeout("AllFoo"); Thread.Sleep(TimeSpan.FromSeconds(3)); connection.Stop(); mockHub.Verify(); } }
public static void SetupContainer(IAppBuilder app, IUnityContainer container, IPathMapper pathMapper, string virtualRoot, string routePrefix, string modulesPhysicalPath) { container.RegisterInstance(app); var moduleInitializerOptions = (ModuleInitializerOptions)container.Resolve <IModuleInitializerOptions>(); moduleInitializerOptions.VirtualRoot = virtualRoot; moduleInitializerOptions.RoutePrefix = routePrefix; //Initialize Platform dependencies var connectionString = ConfigurationHelper.GetConnectionStringValue("VirtoCommerce"); var hangfireOptions = new HangfireOptions { StartServer = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Jobs.Enabled", true), JobStorageType = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Jobs.StorageType", "Memory"), DatabaseConnectionString = connectionString, WorkerCount = ConfigurationHelper.GetNullableAppSettingsValue("VirtoCommerce:Jobs.WorkerCount", (int?)null) }; var hangfireLauncher = new HangfireLauncher(hangfireOptions); var authenticationOptions = new AuthenticationOptions { AllowOnlyAlphanumericUserNames = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Authentication:AllowOnlyAlphanumericUserNames", false), RequireUniqueEmail = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Authentication:RequireUniqueEmail", false), PasswordRequiredLength = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Authentication:Password.RequiredLength", 5), PasswordRequireNonLetterOrDigit = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Authentication:Password.RequireNonLetterOrDigit", false), PasswordRequireDigit = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Authentication:Password.RequireDigit", false), PasswordRequireLowercase = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Authentication:Password.RequireLowercase", false), PasswordRequireUppercase = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Authentication:Password.RequireUppercase", false), UserLockoutEnabledByDefault = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Authentication:UserLockoutEnabledByDefault", true), DefaultAccountLockoutTimeSpan = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Authentication:DefaultAccountLockoutTimeSpan", TimeSpan.FromMinutes(5)), MaxFailedAccessAttemptsBeforeLockout = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Authentication:MaxFailedAccessAttemptsBeforeLockout", 5), DefaultTokenLifespan = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Authentication:DefaultTokenLifespan", TimeSpan.FromDays(1)), CookiesEnabled = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Authentication:Cookies.Enabled", true), CookiesValidateInterval = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Authentication:Cookies.ValidateInterval", TimeSpan.FromDays(1)), BearerTokensEnabled = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Authentication:BearerTokens.Enabled", true), BearerTokensExpireTimeSpan = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Authentication:BearerTokens.AccessTokenExpireTimeSpan", TimeSpan.FromHours(1)), HmacEnabled = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Authentication:Hmac.Enabled", true), HmacSignatureValidityPeriod = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Authentication:Hmac.SignatureValidityPeriod", TimeSpan.FromMinutes(20)), ApiKeysEnabled = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Authentication:ApiKeys.Enabled", true), ApiKeysHttpHeaderName = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Authentication:ApiKeys.HttpHeaderName", "api_key"), ApiKeysQueryStringParameterName = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Authentication:ApiKeys.QueryStringParameterName", "api_key"), }; container.RegisterInstance(authenticationOptions); InitializePlatform(app, container, pathMapper, connectionString, hangfireLauncher, modulesPhysicalPath); var moduleManager = container.Resolve <IModuleManager>(); var moduleCatalog = container.Resolve <IModuleCatalog>(); var applicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase.EnsureEndSeparator(); // Register URL rewriter for platform scripts var scriptsPhysicalPath = pathMapper.MapPath(VirtualRoot + "/Scripts").EnsureEndSeparator(); var scriptsRelativePath = MakeRelativePath(applicationBase, scriptsPhysicalPath); var platformUrlRewriterOptions = new UrlRewriterOptions(); platformUrlRewriterOptions.Items.Add(PathString.FromUriComponent("/$(Platform)/Scripts"), ""); app.Use <UrlRewriterOwinMiddleware>(platformUrlRewriterOptions); app.UseStaticFiles(new StaticFileOptions { FileSystem = new Microsoft.Owin.FileSystems.PhysicalFileSystem(scriptsRelativePath) }); // Register URL rewriter before modules initialization if (Directory.Exists(modulesPhysicalPath)) { var modulesRelativePath = MakeRelativePath(applicationBase, modulesPhysicalPath); var urlRewriterOptions = new UrlRewriterOptions(); foreach (var module in moduleCatalog.Modules.OfType <ManifestModuleInfo>()) { var urlRewriteKey = string.Format(CultureInfo.InvariantCulture, "/Modules/$({0})", module.ModuleName); var urlRewriteValue = MakeRelativePath(modulesPhysicalPath, module.FullPhysicalPath); urlRewriterOptions.Items.Add(PathString.FromUriComponent(urlRewriteKey), "/" + urlRewriteValue); moduleInitializerOptions.ModuleDirectories.Add(module.ModuleName, module.FullPhysicalPath); } app.Use <UrlRewriterOwinMiddleware>(urlRewriterOptions); app.UseStaticFiles(new StaticFileOptions { FileSystem = new Microsoft.Owin.FileSystems.PhysicalFileSystem(modulesRelativePath) }); } container.RegisterInstance(GlobalConfiguration.Configuration); // Ensure all modules are loaded foreach (var module in moduleCatalog.Modules.OfType <ManifestModuleInfo>().Where(x => x.State == ModuleState.NotStarted)) { moduleManager.LoadModule(module.ModuleName); } SwaggerConfig.RegisterRoutes(container); // Post-initialize // Register MVC areas unless running in the Web Platform Installer mode if (IsApplication) { AreaRegistration.RegisterAllAreas(); } // Register other MVC resources GlobalConfiguration.Configure(WebApiConfig.Register); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); if (IsApplication) { RouteConfig.RegisterRoutes(RouteTable.Routes); } BundleConfig.RegisterBundles(BundleTable.Bundles); AuthConfig.RegisterAuth(); // Security OWIN configuration OwinConfig.Configure(app, container); hangfireLauncher.ConfigureOwin(app, container); RecurringJob.AddOrUpdate <SendNotificationsJobs>("SendNotificationsJob", x => x.Process(), "*/1 * * * *"); var notificationManager = container.Resolve <INotificationManager>(); notificationManager.RegisterNotificationType(() => new RegistrationEmailNotification(container.Resolve <IEmailNotificationSendingGateway>()) { DisplayName = "Registration notification", Description = "This notification is sent by email to a client when he finishes registration", NotificationTemplate = new NotificationTemplate { Subject = PlatformNotificationResource.RegistrationNotificationSubject, Body = PlatformNotificationResource.RegistrationNotificationBody, Language = "en-US", } }); notificationManager.RegisterNotificationType(() => new ResetPasswordEmailNotification(container.Resolve <IEmailNotificationSendingGateway>()) { DisplayName = "Reset password notification", Description = "This notification is sent by email to a client upon reset password request", NotificationTemplate = new NotificationTemplate { Subject = PlatformNotificationResource.ResetPasswordNotificationSubject, Body = PlatformNotificationResource.ResetPasswordNotificationBody, Language = "en-US", } }); notificationManager.RegisterNotificationType(() => new TwoFactorEmailNotification(container.Resolve <IEmailNotificationSendingGateway>()) { DisplayName = "Two factor authentication", Description = "This notification contains a security token for two factor authentication", NotificationTemplate = new NotificationTemplate { Subject = PlatformNotificationResource.TwoFactorNotificationSubject, Body = PlatformNotificationResource.TwoFactorNotificationBody, Language = "en-US", } }); notificationManager.RegisterNotificationType(() => new TwoFactorSmsNotification(container.Resolve <ISmsNotificationSendingGateway>()) { DisplayName = "Two factor authentication", Description = "This notification contains a security token for two factor authentication", NotificationTemplate = new NotificationTemplate { Subject = PlatformNotificationResource.TwoFactorNotificationSubject, Body = PlatformNotificationResource.TwoFactorNotificationBody, Language = "en-US", } }); //Get initialized modules list sorted by dependency order var postInitializeModules = moduleCatalog.CompleteListWithDependencies(moduleCatalog.Modules.OfType <ManifestModuleInfo>()) .Where(m => m.ModuleInstance != null && m.State == ModuleState.Initialized) .ToArray(); foreach (var module in postInitializeModules) { moduleManager.PostInitializeModule(module); } var redisConnectionString = ConfigurationManager.ConnectionStrings["RedisConnectionString"]; // Redis if (redisConnectionString != null && !string.IsNullOrEmpty(redisConnectionString.ConnectionString)) { // Cache RedisConfigurations.AddConfiguration(new RedisConfiguration("redisConnectionString", redisConnectionString.ConnectionString)); // SignalR // https://stackoverflow.com/questions/29885470/signalr-scaleout-on-azure-rediscache-connection-issues GlobalHost.DependencyResolver.UseRedis(new RedisScaleoutConfiguration(redisConnectionString.ConnectionString, "VirtoCommerce.Platform.SignalR")); } // SignalR var tempCounterManager = new TempPerformanceCounterManager(); GlobalHost.DependencyResolver.Register(typeof(IPerformanceCounterManager), () => tempCounterManager); var hubConfiguration = new HubConfiguration { EnableJavaScriptProxies = false }; app.MapSignalR("/" + moduleInitializerOptions.RoutePrefix + "signalr", hubConfiguration); // Initialize InstrumentationKey from EnvironmentVariable var appInsightKey = Environment.GetEnvironmentVariable("APPINSIGHTS_INSTRUMENTATIONKEY"); if (!string.IsNullOrEmpty(appInsightKey)) { TelemetryConfiguration.Active.InstrumentationKey = appInsightKey; } }
public static void ConfigureRoutes(IAppBuilder app, IDependencyResolver resolver) { var hubConfig = new HubConfiguration { Resolver = resolver, EnableDetailedErrors = true }; app.MapSignalR(hubConfig); app.MapSignalR("/signalr2/test", new HubConfiguration() { Resolver = resolver }); var config = new ConnectionConfiguration { Resolver = resolver }; app.Map("/multisend", map => { map.UseCors(CorsOptions.AllowAll); map.RunSignalR<MySendingConnection>(config); }); app.Map("/autoencodedjson", map => { map.UseCors(CorsOptions.AllowAll); map.RunSignalR<EchoConnection>(config); }); app.Map("/redirectionConnection", map => { map.UseCors(CorsOptions.AllowAll); map.RunSignalR<RedirectionConnection>(config); }); app.Map("/statusCodeConnection", map => { map.UseCors(CorsOptions.AllowAll); map.RunSignalR<StatusCodeConnection>(config); }); app.Map("/jsonp", map => { var jsonpConfig = new ConnectionConfiguration { Resolver = resolver, EnableJSONP = true }; map.MapSignalR<EchoConnection>("/echo", jsonpConfig); var jsonpHubsConfig = new HubConfiguration { Resolver = resolver, EnableJSONP = true }; map.MapSignalR(jsonpHubsConfig); }); app.MapSignalR<MyBadConnection>("/ErrorsAreFun", config); app.MapSignalR<MyGroupEchoConnection>("/group-echo", config); app.MapSignalR<MyReconnect>("/my-reconnect", config); app.MapSignalR<ExamineHeadersConnection>("/examine-request", config); app.MapSignalR<ExamineReconnectPath>("/examine-reconnect", config); app.MapSignalR<MyGroupConnection>("/groups", config); app.MapSignalR<MyRejoinGroupsConnection>("/rejoin-groups", config); app.MapSignalR<BroadcastConnection>("/filter", config); app.MapSignalR<ConnectionThatUsesItems>("/items", config); app.MapSignalR<SyncErrorConnection>("/sync-error", config); app.MapSignalR<AddGroupOnConnectedConnection>("/add-group", config); app.MapSignalR<UnusableProtectedConnection>("/protected", config); app.MapSignalR<FallbackToLongPollingConnection>("/fall-back", config); app.MapSignalR<FallbackToLongPollingConnectionThrows>("/fall-back-throws", config); app.MapSignalR<PreserializedJsonConnection>("/preserialize", config); // This subpipeline is protected by basic auth app.Map("/basicauth", map => { map.UseBasicAuthentication(new BasicAuthenticationProvider()); var subConfig = new ConnectionConfiguration { Resolver = resolver }; map.MapSignalR<AuthenticatedEchoConnection>("/echo", subConfig); var subHubsConfig = new HubConfiguration { Resolver = resolver }; map.MapSignalR(subHubsConfig); }); app.Map("/force-lp-reconnect", map => { map.Use((context, next) => { if (context.Request.Path.Value.Contains("poll")) { context.Response.StatusCode = 500; return TaskAsyncHelper.Empty; } return next(); }); map.MapSignalR<ExamineReconnectPath>("/examine-reconnect", config); map.MapSignalR(hubConfig); }); // Perf/stress test related var performanceConfig = new ConnectionConfiguration { Resolver = resolver }; app.MapSignalR<StressConnection>("/echo", performanceConfig); performanceConfig.Resolver.Register(typeof(IProtectedData), () => new EmptyProtectedData()); // IMPORTANT: This needs to run last so that it runs in the "default" part of the pipeline // Session is enabled for ASP.NET on the session path app.Map("/session", map => { map.MapSignalR(); }); }
public void Configuration(IAppBuilder appBuilder) { // Setup the cors middleware to run before other pipeline entries. // By default this will allow all origins. You can // configure the set of origins and/or http verbs by // providing a cors options with a different policy. appBuilder.UseCors(CorsOptions.AllowAll); appBuilder.Use <GlobalExceptionMiddleware>(); appBuilder.Map("/api", api => { // Create our config object we'll use to configure the API // var config = new HttpConfiguration(); config.UseStructureMap <DefaultRegistry>(); // Use attribute routing // config.MapHttpAttributeRoutes(); config.Services.Replace(typeof(IExceptionHandler), new GlobalExceptionHandler()); // clear the supported mediatypes of the xml formatter config.Formatters.XmlFormatter.SupportedMediaTypes.Clear(); //Remove the XM Formatter from the web api config.Formatters.Remove(config.Formatters.XmlFormatter); var jsonFormatter = config.Formatters.JsonFormatter; jsonFormatter.UseDataContractJsonSerializer = false; var settings = jsonFormatter.SerializerSettings; settings.ContractResolver = new CamelCasePropertyNamesContractResolver(); #if DEBUG settings.Formatting = Formatting.Indented; // Pretty json for developers. #else settings.Formatting = Formatting.None; #endif // Now add in the WebAPI middleware // api.UseWebApi(config); }); appBuilder.Map("/signalr", map => { var hubConfiguration = new HubConfiguration { // You can enable JSONP by uncommenting line below. // JSONP requests are insecure but some older browsers (and some // versions of IE) require JSONP to work cross domain // EnableJSONP = true EnableDetailedErrors = true, EnableJavaScriptProxies = true, EnableJSONP = true }; hubConfiguration.UseStructureMap <DefaultRegistry>(); // camelcase contract resolver var serializer = JsonSerializer.Create(new JsonSerializerSettings { ContractResolver = new SignalRContractResolver() }); hubConfiguration.Resolver.Register(typeof(JsonSerializer), () => serializer); // Run the SignalR pipeline. We're not using MapSignalR // since this branch is already runs under the "/signalr" // path. map.RunSignalR(hubConfiguration); }); var webRoot = @"./wwwroot"; var cfg = ConfigurationManager.AppSettings["web:wwwroot"]; if (!string.IsNullOrEmpty(cfg)) { if (Directory.Exists(cfg)) { if (File.Exists(Path.Combine(cfg, "index.html"))) { webRoot = cfg; } } } var physicalFileSystem = new PhysicalFileSystem(webRoot); var options = new FileServerOptions { EnableDefaultFiles = true, FileSystem = physicalFileSystem, EnableDirectoryBrowsing = false }; options.StaticFileOptions.FileSystem = physicalFileSystem; options.StaticFileOptions.ServeUnknownFileTypes = true; options.DefaultFilesOptions.DefaultFileNames = new[] { "index.html" }; appBuilder.UseFileServer(options); }
public async Task DisconnectFiresForHubsWhenClientDisconnects() { using (var host = new MemoryHost()) { var dr = new DefaultDependencyResolver(); var configuration = dr.Resolve<IConfigurationManager>(); var connectWh = new AsyncManualResetEvent(); var disconnectWh = new AsyncManualResetEvent(); host.Configure(app => { var config = new HubConfiguration { Resolver = dr }; app.MapSignalR("/signalr", config); configuration.DisconnectTimeout = TimeSpan.FromSeconds(6); dr.Register(typeof(MyHub), () => new MyHub(connectWh, disconnectWh)); }); var connection = new HubConnection("http://foo/"); connection.CreateHubProxy("MyHub"); await connection.Start(host); Assert.True(await connectWh.WaitAsync(TimeSpan.FromSeconds(10)), "Connect never fired"); ((Client.IConnection)connection).Disconnect(); Assert.True(await disconnectWh.WaitAsync(TimeSpan.FromSeconds(20)), "Disconnect never fired"); } }
/// <summary> /// Adds Azure SignalR hubs to the app builder pipeline at "/signalr" using the connection string specified in web.config /// </summary> /// <param name="builder">The app builder <see cref="IAppBuilder"/>.</param> /// <param name="applicationName">The name of your app, it is case-insensitive.</param> /// <param name="configuration">The hub configuration <see cref="HubConfiguration"/>.</param> public static void RunAzureSignalR(this IAppBuilder builder, string applicationName, HubConfiguration configuration) { RunAzureSignalR(builder, applicationName, configuration, null); }
public static IDisposable RunConnectDisconnect(int connections) { var host = new MemoryHost(); host.Configure(app => { var config = new HubConfiguration() { Resolver = new DefaultDependencyResolver() }; app.MapHubs(config); }); for (int i = 0; i < connections; i++) { var connection = new Client.Hubs.HubConnection("http://foo"); var proxy = connection.CreateHubProxy("EchoHub"); var wh = new ManualResetEventSlim(false); proxy.On("echo", _ => wh.Set()); try { connection.Start(host).Wait(); proxy.Invoke("Echo", "foo").Wait(); if (!wh.Wait(TimeSpan.FromSeconds(10))) { Debugger.Break(); } } finally { connection.Stop(); } } return host; }
/// <summary> /// Adds Azure SignalR hubs to the app builder pipeline at "/signalr". /// </summary> /// <param name="builder">The app builder <see cref="IAppBuilder"/>.</param> /// <param name="applicationName">The name of your app, it is case-insensitive.</param> /// <param name="connectionString">The connection string of an Azure SignalR Service instance.</param> /// <param name="configuration">The hub configuration <see cref="HubConfiguration"/>.</param> public static void RunAzureSignalR(this IAppBuilder builder, string applicationName, string connectionString, HubConfiguration configuration) { RunAzureSignalR(builder, applicationName, configuration, s => s.ConnectionString = connectionString); }
public static void ConfigureRoutes(IAppBuilder app, IDependencyResolver resolver) { var hubConfig = new HubConfiguration { Resolver = resolver, EnableDetailedErrors = true }; app.MapSignalR(hubConfig); app.MapSignalR("/signalr2/test", new HubConfiguration() { Resolver = resolver }); var config = new ConnectionConfiguration { Resolver = resolver }; app.Map("/multisend", map => { map.UseCors(CorsOptions.AllowAll); map.RunSignalR<MySendingConnection>(config); }); app.Map("/echo", map => { map.UseCors(CorsOptions.AllowAll); map.RunSignalR<EchoConnection>(config); }); app.Map("/redirectionConnection", map => { map.UseCors(CorsOptions.AllowAll); map.RunSignalR<RedirectionConnection>(config); }); app.Map("/statusCodeConnection", map => { map.UseCors(CorsOptions.AllowAll); map.RunSignalR<StatusCodeConnection>(config); }); app.Map("/jsonp", map => { var jsonpConfig = new ConnectionConfiguration { Resolver = resolver, EnableJSONP = true }; map.MapSignalR<EchoConnection>("/echo", jsonpConfig); var jsonpHubsConfig = new HubConfiguration { Resolver = resolver, EnableJSONP = true }; map.MapSignalR(jsonpHubsConfig); }); app.MapSignalR<MyBadConnection>("/ErrorsAreFun", config); app.MapSignalR<MyGroupEchoConnection>("/group-echo", config); app.MapSignalR<MyReconnect>("/my-reconnect", config); app.MapSignalR<ExamineHeadersConnection>("/examine-request", config); app.MapSignalR<ExamineReconnectPath>("/examine-reconnect", config); app.MapSignalR<MyGroupConnection>("/groups", config); app.MapSignalR<MyRejoinGroupsConnection>("/rejoin-groups", config); app.MapSignalR<BroadcastConnection>("/filter", config); app.MapSignalR<ConnectionThatUsesItems>("/items", config); app.MapSignalR<SyncErrorConnection>("/sync-error", config); app.MapSignalR<AddGroupOnConnectedConnection>("/add-group", config); app.MapSignalR<UnusableProtectedConnection>("/protected", config); app.MapSignalR<FallbackToLongPollingConnectionThrows>("/fall-back-throws", config); app.MapSignalR<PreserializedJsonConnection>("/preserialize", config); app.MapSignalR<AsyncOnConnectedConnection>("/async-on-connected", config); // This subpipeline is protected by basic auth app.Map("/basicauth", map => { map.Use(async (context, next) => { var authorization = context.Request.Headers.Get("Authorization"); if (string.IsNullOrEmpty(authorization)) { context.Response.StatusCode = 401; context.Response.Headers.Add("WWW-Authenticate", new string[] { "Basic" }); } else { var base64Encoded = authorization.Replace("Basic ", ""); byte[] base64EncodedBytes = Convert.FromBase64String(base64Encoded); var base64Decoded = System.Text.ASCIIEncoding.ASCII.GetString(base64EncodedBytes); var credentials = base64Decoded.Split(':'); var identity = new ClaimsIdentity("Basic"); identity.AddClaim(new Claim(ClaimTypes.Name, credentials[0])); context.Request.User = new ClaimsPrincipal(identity); await next(); } }); var subConfig = new ConnectionConfiguration { Resolver = resolver }; map.MapSignalR<AuthenticatedEchoConnection>("/echo", subConfig); var subHubsConfig = new HubConfiguration { Resolver = resolver }; map.MapSignalR(subHubsConfig); }); // This subpipeline is protected by cookie auth app.Map("/cookieauth", map => { var options = new CookieAuthenticationOptions() { AuthenticationType = CookieAuthenticationDefaults.AuthenticationType, LoginPath = CookieAuthenticationDefaults.LoginPath, LogoutPath = CookieAuthenticationDefaults.LogoutPath, }; map.UseCookieAuthentication(options); map.Use(async (context, next) => { if (context.Request.Path.Value.Contains(options.LoginPath.Value)) { if (context.Request.Method == "POST") { var form = await context.Request.ReadFormAsync(); var userName = form["UserName"]; var password = form["Password"]; var identity = new ClaimsIdentity(options.AuthenticationType); identity.AddClaim(new Claim(ClaimTypes.Name, userName)); context.Authentication.SignIn(identity); } } else { await next(); } }); var subConfig = new ConnectionConfiguration { Resolver = resolver }; map.MapSignalR<AuthenticatedEchoConnection>("/echo", subConfig); var subHubsConfig = new HubConfiguration { Resolver = resolver }; map.MapSignalR(subHubsConfig); }); app.Map("/fall-back", map => { map.Use((context, next) => { if (!context.Request.Path.Value.Contains("negotiate") && !context.Request.QueryString.Value.Contains("longPolling")) { context.Response.Body = new MemoryStream(); } return next(); }); map.RunSignalR<FallbackToLongPollingConnection>(); }); app.Map("/no-init", map => { map.Use((context, next) => { if (context.Request.Path.Value.Contains("connect")) { context.Response.Body = new MemoryStream(); } return next(); }); }); app.Map("/force-lp-reconnect", map => { map.Use((context, next) => { if (context.Request.Path.Value.Contains("poll")) { context.Response.StatusCode = 500; return TaskAsyncHelper.Empty; } return next(); }); map.MapSignalR<ExamineReconnectPath>("/examine-reconnect", config); map.MapSignalR(hubConfig); }); // Perf/stress test related var performanceConfig = new ConnectionConfiguration { Resolver = resolver }; app.MapSignalR<StressConnection>("/echo", performanceConfig); performanceConfig.Resolver.Register(typeof(IProtectedData), () => new EmptyProtectedData()); // IMPORTANT: This needs to run last so that it runs in the "default" part of the pipeline // Session is enabled for ASP.NET on the session path app.Map("/session", map => { map.MapSignalR(); }); }
internal static ServiceHubDispatcher PrepareAndGetDispatcher(IAppBuilder builder, HubConfiguration configuration, ServiceOptions options, string applicationName, ILoggerFactory loggerFactory) { // Ensure we have the conversions for MS.Owin so that // the app builder respects the OwinMiddleware base class SignatureConversions.AddConversions(builder); // ServiceEndpointManager needs the logger var hubs = GetAvailableHubNames(configuration); var endpoint = new ServiceEndpointManager(options, loggerFactory); configuration.Resolver.Register(typeof(IServiceEndpointManager), () => endpoint); // Get the one from DI or new a default one var router = configuration.Resolver.Resolve <IEndpointRouter>() ?? new DefaultEndpointRouter(); var serverNameProvider = configuration.Resolver.Resolve <IServerNameProvider>(); if (serverNameProvider == null) { serverNameProvider = new DefaultServerNameProvider(); configuration.Resolver.Register(typeof(IServerNameProvider), () => serverNameProvider); } var requestIdProvider = configuration.Resolver.Resolve <IConnectionRequestIdProvider>(); if (requestIdProvider == null) { requestIdProvider = new DefaultConnectionRequestIdProvider(); configuration.Resolver.Register(typeof(IConnectionRequestIdProvider), () => requestIdProvider); } builder.Use <NegotiateMiddleware>(configuration, applicationName, endpoint, router, options, serverNameProvider, requestIdProvider, loggerFactory); builder.RunSignalR(configuration); // Fetch the trace manager from DI and add logger provider var traceManager = configuration.Resolver.Resolve <ITraceManager>(); if (traceManager != null) { loggerFactory.AddProvider(new TraceManagerLoggerProvider(traceManager)); } configuration.Resolver.Register(typeof(ILoggerFactory), () => loggerFactory); // TODO: Using IOptions looks wierd, thinking of a way removing it // share the same object all through var serviceOptions = Options.Create(options); // For safety, ALWAYS register abstract classes or interfaces // Some third-party DI frameworks such as Ninject, implicit self-binding concrete types: // https://github.com/ninject/ninject/wiki/dependency-injection-with-ninject#skipping-the-type-binding-bit--implicit-self-binding-of-concrete-types configuration.Resolver.Register(typeof(IOptions <ServiceOptions>), () => serviceOptions); var serviceProtocol = new ServiceProtocol(); configuration.Resolver.Register(typeof(IServiceProtocol), () => serviceProtocol); // allow override from tests var scm = configuration.Resolver.Resolve <IServiceConnectionManager>(); if (scm == null) { scm = new ServiceConnectionManager(applicationName, hubs); configuration.Resolver.Register(typeof(IServiceConnectionManager), () => scm); } var ccm = configuration.Resolver.Resolve <IClientConnectionManager>(); if (ccm == null) { ccm = new ClientConnectionManager(configuration, loggerFactory); configuration.Resolver.Register(typeof(IClientConnectionManager), () => ccm); } var atm = new AzureTransportManager(configuration.Resolver); configuration.Resolver.Register(typeof(ITransportManager), () => atm); var parser = new SignalRMessageParser(hubs, configuration.Resolver); configuration.Resolver.Register(typeof(IMessageParser), () => parser); var smb = new ServiceMessageBus(configuration.Resolver); configuration.Resolver.Register(typeof(IMessageBus), () => smb); var scf = configuration.Resolver.Resolve <IServiceConnectionFactory>(); if (scf == null) { var connectionFactory = new ConnectionFactory(serverNameProvider, loggerFactory); scf = new ServiceConnectionFactory(serviceProtocol, ccm, connectionFactory, loggerFactory, serverNameProvider); configuration.Resolver.Register(typeof(IServiceConnectionFactory), () => scf); } var sccf = new ServiceConnectionContainerFactory(scf, endpoint, router, options, loggerFactory); if (hubs?.Count > 0) { return(new ServiceHubDispatcher(hubs, scm, sccf, serviceOptions, loggerFactory)); } else { loggerFactory.CreateLogger <DispatcherHelper>().Log(LogLevel.Warning, "No hubs found."); return(null); } }
public async Task AuthenticatedUserCanInvokeMethodsWhenAuthenticationRequiredGlobally() { using (var host = new MemoryHost()) { host.Configure(app => { var configuration = new HubConfiguration { Resolver = new DefaultDependencyResolver() }; configuration.Resolver.Resolve<IHubPipeline>().RequireAuthentication(); WithUser(app, new GenericPrincipal(new GenericIdentity("test"), new string[] { })); app.MapSignalR("/signalr", configuration); }); var connection = CreateHubConnection("http://foo/"); using (connection) { var hub = connection.CreateHubProxy("NoAuthHub"); var wh = new ManualResetEvent(false); hub.On<string, string>("invoked", (id, time) => { Assert.NotNull(id); wh.Set(); }); await connection.Start(host); hub.InvokeWithTimeout("InvokedFromClient"); Assert.True(wh.WaitOne(TimeSpan.FromSeconds(3))); } } }
private static void RunAzureSignalRCore(IAppBuilder builder, string applicationName, HubConfiguration configuration, ServiceOptions options) { // applicationName is case insensitive, it will be lower cased in the service side if (string.IsNullOrEmpty(applicationName)) { throw new ArgumentException("Empty application name is not allowed.", nameof(applicationName)); } options.ApplicationName = applicationName; if (configuration == null) { // Keep the same as SignalR's exception throw new ArgumentException("A configuration object must be specified."); } // MaxPollInterval should be [1,300] seconds if (options.MaxPollIntervalInSeconds.HasValue && (options.MaxPollIntervalInSeconds < 1 || options.MaxPollIntervalInSeconds > 300)) { throw new AzureSignalRInvalidServiceOptionsException("MaxPollIntervalInSeconds", "[1,300]"); } var loggerFactory = DispatcherHelper.GetLoggerFactory(configuration) ?? NullLoggerFactory.Instance; var dispatcher = DispatcherHelper.PrepareAndGetDispatcher(builder, configuration, options, applicationName, loggerFactory); if (dispatcher != null) { // Start the server->service connection asynchronously _ = dispatcher.StartAsync(); } }
public void UnauthorizedUserCannotReceiveHubMessagesFromHubsAuthorizedWithRoles() { using (var host = new MemoryHost()) { host.Configure(app => { var configuration = new HubConfiguration { Resolver = new DefaultDependencyResolver() }; WithUser(app, new GenericPrincipal(new GenericIdentity("test"), new string[] { "User", "NotAdmin" })); app.MapSignalR("/signalr", configuration); }); var connection = CreateHubConnection("http://foo/"); using (connection) { var hub = connection.CreateHubProxy("AdminAuthHub"); var wh = new ManualResetEvent(false); hub.On<string, string, object>("joined", (id, time, authInfo) => { Assert.NotNull(id); wh.Set(); }); Assert.Throws<AggregateException>(() => connection.Start(host).Wait()); } } }
/// <summary> /// Maps Azure SignalR hubs to the app builder pipeline at "/signalr". /// </summary> /// <param name="builder">The app builder <see cref="IAppBuilder"/>.</param> /// <param name="applicationName">The name of your app, it is case-insensitive.</param> /// <param name="configuration">The hub configuration <see cref="HubConfiguration"/>.</param> /// <returns>The app builder</returns> public static IAppBuilder MapAzureSignalR(this IAppBuilder builder, string applicationName, HubConfiguration configuration) { return(builder.MapAzureSignalR("/signalr", applicationName, configuration)); }
public async Task UnauthenticatedUserCannotInvokeMethodsInIncomingAuthorizedHubs() { using (var host = new MemoryHost()) { host.Configure(app => { var configuration = new HubConfiguration { Resolver = new DefaultDependencyResolver() }; WithUser(app, new GenericPrincipal(new GenericIdentity(""), new string[] { "User", "NotAdmin" })); app.MapSignalR("/signalr", configuration); }); var connection = CreateHubConnection("http://foo/"); using (connection) { var hub = connection.CreateHubProxy("IncomingAuthHub"); var wh = new ManualResetEvent(false); hub.On<string, string>("invoked", (id, time) => { Assert.NotNull(id); wh.Set(); }); await connection.Start(host); Assert.Throws<AggregateException>(() => hub.InvokeWithTimeout("InvokedFromClient")); Assert.False(wh.WaitOne(TimeSpan.FromSeconds(3))); } } }
public async Task GroupsTokenIsPerConnectionId() { using (var host = new MemoryHost()) { IProtectedData protectedData = null; host.Configure(app => { var config = new HubConfiguration { Resolver = new DefaultDependencyResolver() }; app.MapSignalR<MyGroupConnection>("/echo", config); protectedData = config.Resolver.Resolve<IProtectedData>(); }); var connection = new Client.Connection("http://memoryhost/echo"); using (connection) { var inGroup = new AsyncManualResetEvent(); connection.Received += data => { if (data == "group") { inGroup.Set(); } }; await connection.Start(host); await inGroup.WaitAsync(TimeSpan.FromSeconds(10)); Assert.NotNull(connection.GroupsToken); var spyWh = new AsyncManualResetEvent(); var hackerConnection = new Client.Connection(connection.Url) { ConnectionId = "hacker" }; var url = GetUrl(protectedData, connection, connection.GroupsToken); var response = await host.Get(url, r => { }, isLongRunning: true); var reader = new EventSourceStreamReader(hackerConnection, response.GetStream()); reader.Message = sseEvent => { if (sseEvent.EventType == EventType.Data && sseEvent.Data != "initialized" && sseEvent.Data != "{}") { spyWh.Set(); } }; reader.Start(); await connection.Send("random"); Assert.False(await spyWh.WaitAsync(TimeSpan.FromSeconds(5))); } } }
public static IDisposable StressGroups(int max = 100) { var host = new MemoryHost(); host.Configure(app => { var config = new HubConfiguration() { Resolver = new DefaultDependencyResolver() }; app.MapSignalR(config); var configuration = config.Resolver.Resolve <IConfigurationManager>(); // The below effectively sets the heartbeat interval to five seconds. configuration.KeepAlive = TimeSpan.FromSeconds(10); }); var countDown = new CountDownRange <int>(Enumerable.Range(0, max)); var connection = new HubConnection("http://foo"); var proxy = connection.CreateHubProxy("HubWithGroups"); proxy.On <int>("Do", i => { if (!countDown.Mark(i)) { Debugger.Break(); } }); try { connection.Start(new Client.Transports.LongPollingTransport(host)).Wait(); proxy.Invoke("Join", "foo").Wait(); for (int i = 0; i < max; i++) { proxy.Invoke("Send", "foo", i).Wait(); } proxy.Invoke("Leave", "foo").Wait(); for (int i = max + 1; i < max + 50; i++) { proxy.Invoke("Send", "foo", i).Wait(); } if (!countDown.Wait(TimeSpan.FromSeconds(10))) { Console.WriteLine("Didn't receive " + max + " messages. Got " + (max - countDown.Count) + " missed " + String.Join(",", countDown.Left.Select(i => i.ToString()))); Debugger.Break(); } } finally { connection.Stop(); } return(host); }
public void Configuration(IAppBuilder appBuilder) { SnLog.Instance = new SnEventLogger(Web.Configuration.LogName, Web.Configuration.LogSourceName); SnLog.WriteInformation("Starting TaskManagement.Web", EventId.TaskManagement.Lifecycle); // make Web API use the standard ASP.NET error configuration ConfigureErrorHandling(); // Branch the pipeline here for requests that start with "/signalr" appBuilder.Map("/signalr", map => { // Setup the CORS middleware to run before SignalR. // By default this will allow all origins. You can // configure the set of origins and/or http verbs by // providing a cors options with a different policy. map.UseCors(CorsOptions.AllowAll); var hubConfiguration = new HubConfiguration { // You can enable JSONP by uncommenting line below. // JSONP requests are insecure but some older browsers (and some // versions of IE) require JSONP to work cross domain // EnableJSONP = true }; // add SQL server backend if SignalR SQL is enabled if (SenseNet.TaskManagement.Web.Configuration.SignalRSqlEnabled) { GlobalHost.DependencyResolver.UseSqlServer(SenseNet.TaskManagement.Web.Configuration.SignalRDatabaseConnectionString); } SnLog.WriteInformation( $"SignalR SQL backplane is{(SenseNet.TaskManagement.Web.Configuration.SignalRSqlEnabled ? string.Empty : " NOT")} enabled.", EventId.TaskManagement.Lifecycle); // Run the SignalR pipeline. We're not using MapSignalR // since this branch already runs under the "/signalr" // path. map.RunSignalR(hubConfiguration); }); var httpConfiguration = new HttpConfiguration(); httpConfiguration.Formatters.Clear(); httpConfiguration.Formatters.Add(new JsonMediaTypeFormatter()); httpConfiguration.Formatters.JsonFormatter.SerializerSettings = new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }; // Web API routes (moved here from WebApiConfig) httpConfiguration.MapHttpAttributeRoutes(); httpConfiguration.Routes.MapHttpRoute( name: "TaskManagementRegisterTaskApi", routeTemplate: "api/{controller}/{action}/{taskRequest}", defaults: new { taskRequest = RouteParameter.Optional, controller = "Task", action = "RegisterTask" } ); httpConfiguration.Routes.MapHttpRoute( name: "TaskManagementRegisterAppApi", routeTemplate: "api/{controller}/{action}/{appRequest}", defaults: new { taskRequest = RouteParameter.Optional, controller = "Task", action = "RegisterApplication" } ); httpConfiguration.Routes.MapHttpRoute( name: "TaskManagementApi", routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional }); // configure global error logging httpConfiguration.Services.Add(typeof(IExceptionLogger), new WebExceptionLogger()); appBuilder.UseWebApi(httpConfiguration); // initialize dead task timer InitializeDeadTaskTimer(); SnLog.WriteInformation("SenseNet TaskManagement app started.", EventId.TaskManagement.Lifecycle); // load apps ApplicationHandler.Initialize(); }
/// <summary> /// Adds Azure SignalR hubs to the app builder pipeline at "/signalr". /// </summary> /// <param name="builder">The app builder</param> /// <param name="applicationName">The name of your app, it is case-insensitive</param> /// <param name="configuration">The hub configuration</param> /// <param name="optionsConfigure">A callback to configure the <see cref="ServiceOptions"/>.</param> public static void RunAzureSignalR(this IAppBuilder builder, string applicationName, HubConfiguration configuration, Action <ServiceOptions> optionsConfigure) { var serviceOptions = new ServiceOptions(); optionsConfigure?.Invoke(serviceOptions); RunAzureSignalRCore(builder, applicationName, configuration, serviceOptions); }
// For more information on configuring authentication, please visit https://go.microsoft.com/fwlink/?LinkId=301864 public void ConfigureAuth(IAppBuilder app) { // Configure the db context, user manager and signin manager to use a single instance per request app.CreatePerOwinContext(ShopOnlineDbContext.Create); app.CreatePerOwinContext <ApplicationUserManager>(ApplicationUserManager.Create); app.CreatePerOwinContext <ApplicationSignInManager>(ApplicationSignInManager.Create); app.CreatePerOwinContext <ApplicationUserManager>(ApplicationUserManager.Create); app.CreatePerOwinContext <ApplicationRoleManager>(ApplicationRoleManager.Create); app.CreatePerOwinContext <UserManager <AppUser> >(CreateManager); //Allow Cross origin for API app.UseCors(CorsOptions.AllowAll); app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions { TokenEndpointPath = new PathString("/api/oauth/token"), Provider = new AuthorizationServerProvider(), AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(1440), AllowInsecureHttp = true }); app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()); app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie); // Configure the sign in cookie app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, LoginPath = new PathString("/login.html"), Provider = new CookieAuthenticationProvider { // Enables the application to validate the security stamp when the user logs in. // This is a security feature which is used when you change a password or add an external login to your account. OnValidateIdentity = SecurityStampValidator.OnValidateIdentity <ApplicationUserManager, AppUser>( validateInterval: TimeSpan.FromMinutes(10080), regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager, DefaultAuthenticationTypes.ApplicationCookie)) } }); app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie); app.Map("/signalr", map => { // Setup the CORS middleware to run before SignalR. // By default this will allow all origins. You can // configure the set of origins and/or http verbs by // providing a cors options with a different policy. map.UseCors(CorsOptions.AllowAll); map.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions() { Provider = new QueryStringOAuthBearerProvider() }); var hubConfiguration = new HubConfiguration { // You can enable JSONP by uncommenting line below. // JSONP requests are insecure but some older browsers (and some // versions of IE) require JSONP to work cross domain EnableJSONP = true, EnableDetailedErrors = true }; // Run the SignalR pipeline. We're not using MapSignalR // since this branch already runs under the "/signalr" // path. map.RunSignalR(hubConfiguration); }); // Branch the pipeline here for requests that start with "/signalr" // Uncomment the following lines to enable logging in with third party login providers //app.UseMicrosoftAccountAuthentication( // clientId: "", // clientSecret: ""); //app.UseTwitterAuthentication( // consumerKey: "", // consumerSecret: ""); //app.UseFacebookAuthentication( // appId: "", // appSecret: ""); //app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions() //{ // ClientId = "", // ClientSecret = "" //}); }