Coroutines using websockets

Hello!

I am having a little trouble when i get some data from websockets and try to display it through coroutines.

First, I have a classA attached to an object that opens the websocket and displays the data i receive:

 public class ClassA : MonoBehaviour {
    
     ...
    
     public IEnumerator ConnectWebSocket(url)
     {
       // in the websocket class, start the websocket connection, which
       // will return data through a callback inside the return string
       WebSocketClass.WebSocketStart(url, delegate(string result)
       {
         // receive websocket data and call the functions that displays it
         WebSocketData(result);
       });

       // wait for the socket connection
       while (WebSocketClass.WebSocketGetState() == WebSocketSharp.WebSocketState.CONNECTING)
       {
         yield return 0;
       }
    
       if (WebSocketClass.WebSocketGetState() == WebSocketSharp.WebSocketState.OPEN)
       {
          break;
       }
    
       ...
    
     }

     // function that gets websocket data and starts couroutine to display it
     public void WebSocketData(string data)
     {
       StartCoroutine(DisplayMessage(data));       
     }
   }

But Unity complains with the next error:

StartCoroutine_Auto can only be called
from the main thread. Constructors and
field initializers will be executed
from the loading thread when loading a
scene. Don’t use this function in the
constructor or field initializers,
instead move initialization code to
the Awake or Start function.

I searched in the unity forum and found this solution:
StartCoroutine_Auto can only be called from the main thread.

So I applied it doing this:

public class ClassA : MonoBehaviour {
 
  ...
 
  public IEnumerator ConnectWebSocket(url)
  {
    // in the websocket class, start the websocket connection, which
    // will return data through a callback inside the return string
    WebSocketClass.WebSocketStart(url, delegate(string result)
    {
      // receive websocket data and call the functions that displays it
      WebSocketData(result);
    });

    // wait for the socket connection
    while (WebSocketClass.WebSocketGetState() == WebSocketSharp.WebSocketState.CONNECTING)
    {
      yield return 0;
    }
 
    if (WebSocketClass.WebSocketGetState() == WebSocketSharp.WebSocketState.OPEN)
    {
       break;
    }
 
    ...
 
  }

  // function that gets websocket data and starts couroutine to display it
  public void WebSocketData(string data)
  {
    DoOnMainThread.ExecuteOnMainThread.Enqueue(() => { StartCoroutine(DisplayMessage(data)); });    
  }
}

// class to manage the websocket data display inside the main thread
public class DoOnMainThread : MonoBehaviour 
{

  public readonly static Queue<Action> ExecuteOnMainThread = new Queue<Action>();

  public virtual void Update()
  {
    // dispatch stuff on main thread
    while (ExecuteOnMainThread.Count > 0)
    {
      ExecuteOnMainThread.Dequeue().Invoke();
    }
  }
}

And it works! the problem is that even though I wrote the two classes in the same cs file and attached to an object, when I change the scene, return to that scene, and receive any data from the websocket, the next error is displayed:

MissingReferenceException: The object
of type ‘ClassA’ has been destroyed
but you are still trying to access it.
Your script should either check if it
is null or you should not destroy the
object.
UnityEngine.MonoBehaviour.StartCoroutine
(IEnumerator routine) (at
C:/BuildAgent/work/d63dfc6385190b60/artifacts/EditorGenerated/UnityEngineMonoBehaviour.cs:62)

I tried not destroying the object when a new scene is loaded, as the documentation says:

 void Awake()
    {
        DontDestroyOnLoad(transform.gameObject);
    }

But the error still appears.
The weird thing is that although there is an error, the data received from the websocket is displayed without any problem.

Does someone know how to avoid this problem? Any way to trigger a coroutine inside the main thread without using a second class? Or other solution to avoid this error?

Thanks!

Kevek

I found the problem:

public readonly static Queue<Action> ExecuteOnMainThread = new Queue<Action>();

It is static, so it becomes a problem when a public class is instantiated and generates another ExecuteOnMainThread.

So just deleted “static” and made it destroy and generate itself every time ClassA is created by Unity.

Now it works like a charm : )