Asp.Net Core在多个浏览器选项卡中运行SignalR

时间:2018-03-19 11:13:14

标签: c# angular asp.net-core asp.net-core-2.0 asp.net-core-signalr

我正在使用Angular前端创建一个运行在4.7上的ASP.NET核心应用程序。因为我需要通知用户有关状态更改的信息,我试图添加SignalR。我使用以下版本:

  • AspNetCore 2.0.1
  • Angular 5.x
  • SignalR 1.0.0-alpha2-final

下面你可以看到我的代码。如果我运行这个应用程序,我可以在日志中看到两个集线器连接都已开始。如果我打开具有相同URL的第二个浏览器选项卡,则只有一个连接成功。对于第二个集线器,我总是会收到此错误:

Error: Not Found
    at XMLHttpRequest.xhr.onload [as __zone_symbol__ON_PROPERTYload] (http://localhost:51616/dist/estructuring_main.js?v=fBx34vrzWnqBIPjAm71NaWQz0TEeQZWcx2ixKnjADWI:36168:28)
    at XMLHttpRequest.wrapFn (http://localhost:51616/dist/vendor.js?v=rp1X6LsN5SJnsTJrd-749xunuUaKAA_WINwoqzbaeqE:120085:39)
    at ZoneDelegate.invokeTask (http://localhost:51616/dist/vendor.js?v=rp1X6LsN5SJnsTJrd-749xunuUaKAA_WINwoqzbaeqE:119340:31) 
    at Object.onInvokeTask (http://localhost:51616/dist/vendor.js?v=rp1X6LsN5SJnsTJrd-749xunuUaKAA_WINwoqzbaeqE:5013:33)
    at ZoneDelegate.invokeTask (http://localhost:51616/dist/vendor.js?v=rp1X6LsN5SJnsTJrd-749xunuUaKAA_WINwoqzbaeqE:119339:36)
    at Zone.runTask (http://localhost:51616/dist/vendor.js?v=rp1X6LsN5SJnsTJrd-749xunuUaKAA_WINwoqzbaeqE:119107:47)
    at ZoneTask.invokeTask [as invoke] (http://localhost:51616/dist/vendor.js?v=rp1X6LsN5SJnsTJrd-749xunuUaKAA_WINwoqzbaeqE:119415:34)
    at invokeTask (http://localhost:51616/dist/vendor.js?v=rp1X6LsN5SJnsTJrd-749xunuUaKAA_WINwoqzbaeqE:120436:14)
    at XMLHttpRequest.globalZoneAwareCallback (http://localhost:51616/dist/vendor.js?v=rp1X6LsN5SJnsTJrd-749xunuUaKAA_WINwoqzbaeqE:120462:17) 

错误说404找不到,即使我可以在我的请求 - 中间件中看到请求。

我需要更改集线器连接是否也适用于多个标签?

Startup.cs

    public IServiceProvider ConfigureServices(IServiceCollection services)
    {
        services.AddSignalR();
        services.AddSingleton(typeof(IUserTracker<>), typeof(InMemoryUserTracker<>));
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IApplicationLifetime appLifetime)
    {
        app.UseSignalR(routes =>
        {
            routes.MapHub<StatusHub>("status", (options) =>
            {
                options.Transports = TransportType.LongPolling;
            });

            routes.MapHub<AutopricerHub>("autopricer", (options) =>
            {
                options.Transports = TransportType.LongPolling;
            });
        });
    }

InMemoryUserTracker.cs

    public class InMemoryUserTracker<THub> : IUserTracker<THub>
    {
        private readonly ConcurrentDictionary<HubConnectionContext, UserDetails> usersOnline
            = new ConcurrentDictionary<HubConnectionContext, UserDetails>();

        public IEnumerable<UserDetails> UsersOnline()
            => usersOnline.Values.AsEnumerable();

        public Task AddUser(HubConnectionContext connection, UserDetails userDetails)
        {
            usersOnline.TryAdd(connection, userDetails);
            return Task.CompletedTask;
        }

        public Task RemoveUser(HubConnectionContext connection)
        {
            usersOnline.TryRemove(connection, out var userDetails);
            return Task.CompletedTask;
        }
    }

BaseHubWithPresence.cs

    public abstract class BaseHubWithPresence : Hub
    {
        protected readonly IUserTracker<BaseHubWithPresence> userTracker;

        protected BaseHubWithPresence(IUserTracker<BaseHubWithPresence> userTracker)
        {
            this.userTracker = userTracker;
        }

        public virtual async Task Join(long userId)
        {
            await userTracker.AddUser(Context.Connection, new UserDetails(Context.ConnectionId, userId));
            await Task.CompletedTask;
        }

        public virtual async Task Leave()
        {
            await userTracker.RemoveUser(Context.Connection);
            await Task.CompletedTask;
        }
    }

AutopricerHub.cs

    public class AutopricerHub : BaseHubWithPresence
    {
        public AutopricerHub(IUserTracker<AutopricerHub> userTracker)
           : base(userTracker) {}

        public async Task SendToAll()
        {
            await Clients.All.InvokeAsync("All", "data");
        }

        public async Task SendUpdateAsync(long userId)
        {
            foreach (var user in userTracker.UsersOnline().Where(o => o.UserId == userId))
            {
                await Clients.Client(user.ConnectionId).InvokeAsync("Update", "data");
            }
        }
    }

StatusHub.cs

    public class StatusHub : BaseHubWithPresence
    {
        public StatusHub(IUserTracker<BaseHubWithPresence> userTracker)
           : base(userTracker)
        {
        }

        public async Task SendSingleAsync(long listener)
        {
            foreach (var user in userTracker.UsersOnline().Where(o => o.UserId == listener))
            {
                await Clients.Client(user.ConnectionId).InvokeAsync("Update", "data");
            }
        }

        public async Task SendMultipleAsync(IReadOnlyCollection<long> listeners)
        {
            foreach (var listener in listeners)
            {
                foreach (var user in userTracker.UsersOnline().Where(o => o.UserId == listener))
                {
                    await Clients.Client(user.ConnectionId).InvokeAsync("Update", "data");
                }
            }
        }
    }

price-notification.service.ts

    @Injectable()
    export class PriceNotificationService {
        private hubConnection: HubConnection;
        private destroy$ = new Subject<boolean>();

        constructor(
            private appContextService: AppContextService,
            private messageService: MessageService) { 

            this.init();
        }

        private init(): void {
            this.hubConnection = new HubConnection('/autopricer', { transport: TransportType.LongPolling });

            this.hubConnection.start()
                .then(() => {
                    this.appContextService.getAppContext().takeUntil(this.destroy$).subscribe(appContext => {
                        this.hubConnection.invoke('join', appContext.FirmuserId);
                    });
                    DEBUG.init && debug('Price Notification Hub connection started');
                })
                .catch(err => {
                    DEBUG.init && debug('Error while establishing Price Notification Hub connection');
                });

            this.hubConnection.onclose = e => {
                DEBUG.functionCalls && debug('On close Price Notification Hub connection');
                this.hubConnection.invoke('leave');
            };

            this.hubConnection.off('leave', null);
        }

        private showUpdateNotification(data: string) {

        }

        private showAllNotification(data: string) {

        }
    }

status-notification.service.ts

    @Injectable()
    export class StatusNotificationService {
        private hubConnection: HubConnection;
        private destroy$ = new Subject<boolean>();

        constructor(
            private appContextService: AppContextService,
            private messageService: MessageService) {

            this.init();
        }

        private init(): void {
            this.hubConnection = new HubConnection('/status', { transport: TransportType.LongPolling });

            this.hubConnection.start()
                .then(() => {
                    this.appContextService.getAppContext().takeUntil(this.destroy$).subscribe(appContext => {
                        this.hubConnection.invoke('join', appContext.FirmuserId);
                    });
                    DEBUG.init && debug('Status Notification Hub connection started');
                })
                .catch(err => {
                    DEBUG.init && debug('Error while establishing Status Notification Hub connection');
                });

            this.hubConnection.onclose = e => {
                DEBUG.functionCalls && debug('On close Status Notification Hub connection');
                this.hubConnection.invoke('leave');
            };

            this.hubConnection.off('leave', null);
        }

        private showUpdateNotification(data: string) {

        }
    }

每个Angular服务的服务提供者都在一个单独的组件中。

浏览器network标签: enter image description here

0 个答案:

没有答案