角度2,信号器在断开连接时自动重新连接到集线器

我有一个带有signlar 2.2.2的角度2应用程序,这是我的信号器连接服务类..

import { Injectable, Inject } from "@angular/core";
import { Subject } from "rxjs/Subject";
import { Observable } from "rxjs/Observable";

/**
 * When SignalR runs it will add functions to the global $ variable 
 * that you use to create connections to the hub. However, in this
 * class we won't want to depend on any global variables, so this
 * class provides an abstraction away from using $ directly in here.
 */
export class SignalrWindow extends Window {
    $: any;
}

export enum ConnectionState {
    Connecting = 1,
    Connected = 2,
    Reconnecting = 3,
    Disconnected = 4
}

export class ChannelConfig {
    url: string;
    hubName: string;
    channel: string;
}



@Injectable()
export class SignalrService {

    /**
     * starting$ is an observable available to know if the signalr 
     * connection is ready or not. On a successful connection this
     * stream will emit a value.
     */
    starting$: Observable<any>;

    /**
     * connectionState$ provides the current state of the underlying
     * connection as an observable stream.
     */
    connectionState$: Observable<ConnectionState>;

    /**
     * error$ provides a stream of any error messages that occur on the 
     * SignalR connection
     */
    error$: Observable<string>;

    // These are used to feed the public observables 
    //
    private connectionStateSubject = new Subject<ConnectionState>();
    private startingSubject = new Subject<any>();
    private errorSubject = new Subject<any>();

    // These are used to track the internal SignalR state 
    //
    private hubConnection: any;
    private hubProxy: any;
    private cuurentHub: any;

    // An internal array to track what channel subscriptions exist 


    // This Part* is to maintain componants which contains methods to call when message is receieved
    // Observable string sources
    private newStrokeComponentMethodCallSource = new Subject<any>();
    private newPhsycComponentMethodCallSource = new Subject<any>();

    // Observable string streams
    newStrokecomponentMethodCalled$ = this.newStrokeComponentMethodCallSource.asObservable();
    newPhsyccomponentMethodCalled$ = this.newPhsycComponentMethodCallSource.asObservable();

    // Service message commands
    callNewStrokeComponentMethod(phone: string) {
        this.newStrokeComponentMethodCallSource.next(phone);
    }

    callNewPhsycComponentMethod(phone: string) {
        this.newPhsycComponentMethodCallSource.next(phone);
    }

    //----- End of Part*

    constructor(
        @Inject(SignalrWindow) private window: SignalrWindow,
        @Inject("channel.config") private channelConfig: ChannelConfig
    ) {
        if (this.window.$ === undefined || this.window.$.hubConnection === undefined) {
            throw new Error("The variable '$' or the .hubConnection() function are not defined...please check the SignalR scripts have been loaded properly");
        }

        // Set up our observables
        //
        this.connectionState$ = this.connectionStateSubject.asObservable();
        this.error$ = this.errorSubject.asObservable();
        this.starting$ = this.startingSubject.asObservable();

        this.hubConnection = this.window.$.hubConnection();
        this.hubConnection.url = channelConfig.url;
        this.hubProxy = this.hubConnection.createHubProxy(channelConfig.hubName);

        // Define handlers for the connection state events
        //
        this.hubConnection.stateChanged((state: any) => {
            let newState = ConnectionState.Connecting;

            switch (state.newState) {
                case this.window.$.signalR.connectionState.connecting:
                    newState = ConnectionState.Connecting;
                    break;
                case this.window.$.signalR.connectionState.connected:
                    newState = ConnectionState.Connected;
                    break;
                case this.window.$.signalR.connectionState.reconnecting:
                    newState = ConnectionState.Reconnecting;
                    break;
                case this.window.$.signalR.connectionState.disconnected:
                    newState = ConnectionState.Disconnected;
                    break;
            }

            // Push the new state on our subject
            //
            this.connectionStateSubject.next(newState);
        });



        // Define handlers for any errors
        //
        this.hubConnection.error((error: any) => {
            // Push the error on our subject
            //
            this.hubConnection.start()
                .done(() => {
                    this.startingSubject.next();

                    //Invoke connect method on Hub
                    //  this.hubProxy.invoke("Connect", userId, usertype);

                })
                .fail((error: any) => {
                    this.startingSubject.error(error);
                });
        });



        this.hubProxy.on("PushRequestToClient", (data: string) => {
            //console.log(`onEvent - ${channel} channel`, ev);

            // This method acts like a broker for incoming messages. We 
            //  check the interal array of subjects to see if one exists
            //  for the channel this came in on, and then emit the event
            //  on it. Otherwise we ignore the message.
            //
            var request = JSON.parse(data);
            if (request !== null && request.TargetClientMethod === "OnPhsycConsultantRespond") {
                this.callNewPhsycComponentMethod(data);
            }
            else {
                this.callNewStrokeComponentMethod(data);
            }
          //  this.callNewStrokeComponentMethod(data);

            // If we found a subject then emit the event on it
            //

        });


    }

    /**
     * Start the SignalR connection. The starting$ stream will emit an 
     * event if the connection is established, otherwise it will emit an
     * error.
     */
    start(userId,usertype): void {
        // Now we only want the connection started once, so we have a special
        //  starting$ observable that clients can subscribe to know know if
        //  if the startup sequence is done.
        //
        // If we just mapped the start() promise to an observable, then any time
        //  a client subscried to it the start sequence would be triggered
        //  again since it's a cold observable.
        //
        this.hubConnection.start()
            .done(() => {
                this.startingSubject.next();

                //Invoke connect method on Hub
                this.hubProxy.invoke("Connect", userId, usertype);

            })
            .fail((error: any) => {
                this.startingSubject.error(error);
            });
    }



    // Invoke Server Methods
    /** publish provides a way for calles to emit events on any channel. In a 
     * production app the server would ensure that only authorized clients can
     * actually emit the message, but here we're not concerned about that.
     */

    PushRequest(targetUserId, userType, data): void {
        this.hubProxy.invoke("PushRequest", targetUserId, userType, data);
    }


    // -- End of Invoke Server Methods
}

使用此代码,我可以成功连接到集线器,并将请求从客户端推送到集线器和集线器到客户端 .

问题是客户端有时会断开与集线器的连接 . 所以我尝试使用下面url中显示的事件和方法为这个类添加自动重新连接功能

https://msdn.microsoft.com/en-us/library/microsoft.aspnet.signalr.client.hubconnection(v=vs.118).aspx

例如:

this.hubConnection.closed((error: any) => {

            this.hubConnection.start()
                .done(() => {
                    this.startingSubject.next();

                    //Invoke connect method on Hub
                  //  this.hubProxy.invoke("Connect", userId, usertype);

                })
                .fail((error: any) => {
                    this.startingSubject.error(error);
                });
        });

但是说

this.hubConnection.closed不是函数

如何重新 Build 与集线器的连接?

我正在使用 Angular 2 & signalr 2.2.2

回答(1)

2 years ago

onclose 事件是无参数操作,因此您的方法应如下所示:

this.hubConnection.onclose(() => { 
          // ....
        });

但最好在断开连接后尝试重新连接几秒钟:

this.hubConnection.onclose(() => { 
    setTimeout(function(){
    this.hubConnection.start()
               .done(() => {
                    this.startingSubject.next();

                        //Invoke connect method on Hub
                      //  this.hubProxy.invoke("Connect", userId, usertype);

                   })
                  .fail((error: any) => {
                        this.startingSubject.error(error);
                   });
       },3000); 
   });