1

I am trying to use web socket with my bot to communicate with the server. But on run time it throws the System.NullReferenceException. I am running socket in background on a different thread so that it does not interfear with the bot.

I am using WebsocketSharp library.

First message comes in just fine but on second message it throws exception at following line in HumanCollaboratorDialog class.

await  context.PostAsync(e.Data);

My Socket Stream Class is as following:

public static class SocketStream
{
    public static WebSocket ws;
    private static List<string> serverMsg = new List<string>();

    public static void initializeSocket()
    {

        ws = new WebSocket("ws://Some IP:8080/human-collaborator/data");
        Debug.WriteLine("****** INITIALIZED SOCKET (should happen only once) *****");
        Task.Run(() => startSocketStream());

    }

    private static void startSocketStream()
    {
        int attempts = 0;
        while (!ws.IsAlive)
        {
            try
            {
                attempts++;
                ws.Connect();
            }
            catch (WebSocketException)
            {

                Debug.WriteLine("Connection attempts: " + attempts.ToString());
            }

        }

        ws.OnOpen += (sender, args) =>
        {
            Debug.WriteLine("# SOCKET OPENED");

        };

        ws.OnError += (sender, args) =>
        {
            Debug.WriteLine("# SOME ERROR OCCURED");
        };

        ws.OnClose += (sender, args) =>
       {
           Debug.WriteLine("# SOCKET CLOSED");

        };
    }
}

I am calling the initializeSocket() method in Global.asx to run it on application level

public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        GlobalConfiguration.Configure(WebApiConfig.Register);
        SocketStream.initializeSocket();

    }
}

My HumanCollaboratorDialog class is as following:

[Serializable]
public class HumanCollaboratorDialog : IDialog<object>
{

    public async Task StartAsync(IDialogContext context)
    {

        context.Wait(this.MessageReceivedAsync);

    }

    private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> result)
    {

        var message = await result;

        SocketStream.ws.OnMessage += async (sender, e) =>
        {
            try
            {
                await  context.PostAsync(e.Data);
            }
            catch (HttpRequestException ex)
            {
                throw ex;
            }
        };

            Thread.Sleep(500);
            string output = message.Text;
            SocketStream.ws.Send(output);
            Thread.Sleep(500);

        context.Wait(MessageReceivedAsync);

    }
}

My MessagesController has following POST method:

public virtual async Task<HttpResponseMessage> Post([FromBody]Activity activity)
    {
        if (activity.Type == ActivityTypes.Message)
        {
            await Conversation.SendAsync(activity, () => new HumanCollaboratorDialog());
        }
        else
        {
            HandleSystemMessage(activity);
        }
        var response = Request.CreateResponse(HttpStatusCode.OK);
        return response;
    }

Neithet e.Data nor context is empty. I think problem is with socket connection or may be i am doing something wrong in SocketStream class. following is the image

Exception-Image enter image description here

Ehsan Ul Haq
  • 209
  • 3
  • 12

1 Answers1

1

Your bot is a web service. Messages are sent to the service by the client (a web page, an application, another service, etc.) and received in the MessagesController's Post method. There's no need to have the socket code on the server for what you're trying to do. Web Sockets are useful for receiving messages on a client from the bot via a Direct Line connection.


Here is an example of using the Bot Framework's Direct Line Client and creating a web socket connection. Notice how the web socket is created from a conversation's StreamUrl:

DirectLineClientCredentials creds = new DirectLineClientCredentials(directLineSecret);
DirectLineClient directLineClient = new DirectLineClient(creds);
Conversation conversation = await directLineClient.Conversations.StartConversationAsync();

using (var webSocketClient = new WebSocket(conversation.StreamUrl))
{
    webSocketClient.OnMessage += WebSocketClient_OnMessage;
    webSocketClient.Connect();
    while (true)

    {
        string input = Console.ReadLine().Trim();

        if (input.ToLower() == "exit")
        {
            break;
        }
        else
        {
            if (input.Length > 0)
            {
                Activity userMessage = new Activity
                {
                    From = new ChannelAccount(fromUser),
                    Text = input,
                    Type = ActivityTypes.Message
                };

                await directLineClient.Conversations.PostActivityAsync(conversation.ConversationId, userMessage);
            }
        }
    }
}
private static void WebSocketClient_OnMessage(object sender, MessageEventArgs e)
{
    // avoid null reference exception when no data received
    if (string.IsNullOrWhiteSpace(e.Data))
    {
        return;
    }

    var activitySet = JsonConvert.DeserializeObject<ActivitySet>(e.Data);
    var activities = from x in activitySet.Activities
                        where x.From.Id == botId
                        select x;

    foreach (Activity activity in activities)
    {
        Console.WriteLine(activity.Text);
    }
}

This is from a console application that is using the Direct Line to communicate with the Bot and is listening for messages using web sockets here: https://github.com/Microsoft/BotBuilder-Samples/tree/master/CSharp/core-DirectLineWebSockets

Eric Dahlvang
  • 8,252
  • 4
  • 29
  • 50