App crashes when trying to connect to SignalR serv

2019-09-10 12:21发布

问题:

I'm building a Xamarin Android app that uses SignalR for the purpose of real time chat. The app crashes when I try to connect to the server again after I disconnect it and when the app relaunches, it connects fine. I have a singleton class that used for the same reference across my solution. The singleton class has the following method to connect to the server:

public async Task<string> StartConnection()
    {
        hubConnection.Headers.Add("User-Agent", "mobile");
        hubConnection.Headers.Add("username", loggedUser);
        try
        {
            await hubConnection.Start();
            return "Connected..";
        }
        catch (Exception e)
        {
            return e.Message;
        }

    }

Following method disconnects the connection:

public void StopConnection()
    {
        hubConnection.Stop();

    }

The connection is started in the MainActivity of the app as shown in below:

      Task.Factory.StartNew(async () =>
        {
            await SignalRClientHelper.StartConnection();
            SignalRClientHelper.InvokeGetPendingConversations(loggedonuser.UserName);

        });

The connection is disconnected when the user is logged out as shown below:

SignalRClientHelper.StopConnection();

The client can connect to the signalR server for the first time without any problem but when they logout and login in to the app again, the app crashes when trying to server the second time. Here's the error log:

    ava.lang.RuntimeException: java.lang.reflect.InvocationTargetException
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:747)
    at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.reflect.InvocationTargetException
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:511)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:980)
    ... 2 more
Caused by: md52ce486a14f4bcd95899665e9d932190b.JavaProxyThrowable: System.InvalidOperationException: Data cannot be sent because the connection is in the disconnected state. Call start before sending any data.
  at Microsoft.AspNet.SignalR.Client.Connection.Send (System.String data) [0x0001e] in <filename unknown>:0 
  at Microsoft.AspNet.SignalR.Client.Hubs.HubProxy.Invoke[TResult,TProgress] (System.String method, System.Action`1 onProgress, System.Object[] args) [0x000e1] in <filename unknown>:0 
  at Microsoft.AspNet.SignalR.Client.Hubs.HubProxy.Invoke[T] (System.String method, System.Object[] args) [0x00000] in <filename unknown>:0 
  at Microsoft.AspNet.SignalR.Client.Hubs.HubProxy.Invoke (System.String method, System.Object[] args) [0x00000] in <filename unknown>:0 
  at Yourtime.SignalRClientHelper+<InvokeSendMessage>d__11.MoveNext () [0x0000d] in <filename unknown>:0 
--- End of stack trace from previous location where exception was thrown ---
  at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <filename unknown>:0 
  at System.Runtime.CompilerServices.AsyncMethodBuilderCore.<ThrowAsync>m__0 (System.Object state) [0x00000] in <filename unknown>:0 
  at Android.App.SyncContext+<Post>c__AnonStorey0.<>m__0 () [0x00000] in <filename unknown>:0 
  at Java.Lang.Thread+RunnableImplementor.Run () [0x0000b] in <filename unknown>:0 
  at Java.Lang.IRunnableInvoker.n_Run (IntPtr jnienv, IntPtr native__this) [0x00009] in <filename unknown>:0 
  at (wrapper dynamic-method) System.Object:44f67f43-349f-4a1b-8234-1604bc812b68 (intptr,intptr)
    at mono.java.lang.RunnableImplementor.n_run(Native Method)
    at mono.java.lang.RunnableImplementor.run(RunnableImplementor.java:29)
    at android.os.Handler.handleCallback(Handler.java:605)
    at android.os.Handler.dispatchMessage(Handler.java:92)
    at android.os.Looper.loop(Looper.java:137)
    at android.app.ActivityThread.main(ActivityThread.java:4511)

Does anyone have any idea what might be wrong here?

回答1:

SignalR disconnection is bit buggy IMO, but your error clearly says you are trying to invoke something when in disconnected state.

I suggest you change the way you connect/disconnect as follows:

Disconnect

var connectionToDispose = _connection; // _connection is the current connection
_connection = null;
_proxy = null;

// connection disposing can block the UI thread for about 20 seconds
// this doesn´t always happen but just in case we run it on a new thread
Task.Run(() =>
{
    try
    {
        connectionToDispose.Dispose();
    }
    catch (Exception ex)
    {
        _tracer?.WriteLine($"[{_className}] Connection could not be disposed: {ex.Message}");
    }
});

Connect

if (_connection != null)
{
    return false;
}

// always create a new Hub
_connection = new HubConnection(_endpointUri);
// TODO add headers
// TODO create proxy again and subscribe to server events (proxy.On...), etc

try
{
    _tracer?.WriteLine($"[{_className}] CONNECTING...");
    await _connection.Start();

    return true;
}
catch (Exception ex)
{
    _tracer?.WriteLine($"[{_className}] CONNECTION START ERROR: {ex.Message}");
    return false;
}

Just for reference, take a look a this class. I´ve used in an app that connects/disconnects many times with no issues. You can take some ideas from it.