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
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
Related
I have a class with project code below. I would like to get the value of Program.Log(GetHallo(result)); and publish this as a message payload to an mqtt broker.
I found a class Publisher with this mqtt code from https://www.youtubecom/watch?v=lcsnsj1yBs0 and I'm wondering how to get the value of Program.Log(GetHallo(result)); from my code and then publish this to mqtt. How can I integrate the code from publisher.cs in my own class that generates the Program.Log(GetHallo(result));
class Publisher
{
static async Task Main(string[] args)
{
var mqttFactory = new MqttFactory();
IMqttClient client = mqttFactory.CreateMqttClient();
var options = new MqttClientOptionsBuilder()
.WithClientId(Guid.NewGuid().ToString())
.WithTcpServer("192.168.4.33", 1883)
.WithCleanSession()
.Build();
client.UseConnectedHandler(e =>
{
Console.WriteLine("Connected to the broker successfully");
});
client.UseDisconnectedHandler(e =>
{
Console.WriteLine("Disconnected from the broker successfully");
});
await client.ConnectAsync(options);
Console.WriteLine("Please press a key to publish the message");
//Console.ReadLine();
await PublishmessageAsync(client);
await client.DisconnectAsync();
}
private static async Task PublishmessageAsync(IMqttClient client)
{
string messagePayload = "xxxxxxxx!";
var message = new MqttApplicationMessageBuilder()
.WithTopic("RishabhRharma")
.WithPayload(messagePayload)
.WithAtLeastOnceQoS()
.Build();
if (client.IsConnected)
{
await client.PublishAsync(message);
}
}
}
private void Completed(IAsyncResult ar)
{
Action completed = ar.AsyncState as Action;
try
{
var result = new Hallo(this.Panel.EndSend(ar));
Program.Log(GetHallo(result));
}
catch (AtsFaultException e)
{
string message = string.Format("Fault response {0}, {1}", e.Code, e.Message);
Program.Error(message);
}
catch (Exception e)
{
Program.Error(e.Message);
}
finally
{
completed?.Invoke();
}
}
I am working with Azure Event Hub producer client and reading messages off of a kafka stream then pass it along to deserialize/map, then pass to Event Hub. I have the consume loop which is creating a task for each consume and then two methods to do processing(this seems to have greatly improved the speed from the kafka lag perspective. However, Event hub makes you create an event batch which I don't necessarily want to use. I just want to send the data one message at a time for now. In order to create a new batch I have to call Dispose(). I am running into an issue where there's another call to the function by the the time I call Dispose() and I get an error saying the object is being used by event hub.
I've also tried using the overload for eventHubProducerClient.SendAsync that allows you to pass in a IEnumerable but i'm running into the same issue with that.
So I believe this to be a synchronization issue, or maybe I need to do a lock somewhere?
Any help would be appreciated.
public void Execute()
{
using (_consumer)
{
try
{
_consumer.Subscribe(_streamConsumerSettings.Topic);
while (true)
{
var result = _consumer.Consume(1000);
if (result == null)
{
continue;
}
var process = Task.Factory.StartNew(() => ProcessMessage(result?.Message?.Value));
var send = process.ContinueWith(t => SendMessage(process.Result));
}
}
catch (ConsumeException e)
{
_logger.LogError(e, e.StackTrace ?? e.Message);
_cancelConsume = true;
_consumer.Close();
RestartConsumer();
}
}
}
public static EquipmentJson ProcessMessage(byte[] result)
{
var json = _messageProcessor.DeserializeAndMap(result);
return json;
}
public static void SendMessage(EquipmentJson message)
{
try
{
_eventHubClient.AddToBatch(message);
}
catch (Exception e)
{
_logger.LogError(e, e.StackTrace ?? e.Message);
}
}
public async Task AddToBatch(EquipmentJson message)
{
if
(!string.IsNullOrEmpty(message.EquipmentLocation))
{
try
{
var batch = await _equipmentLocClient.CreateBatchAsync();
batch.TryAdd(new EventData(Encoding.UTF8.GetBytes(message.EquipmentLocation)));
await _eventHubProducerClient.SendAsync(batch);
batch.Dispose();
_logger.LogInformation($"Data sent {DateTimeOffset.UtcNow}");
}
catch (Exception e)
{
_logger.LogError(e, e.StackTrace ?? e.Message);
}
}
}
public class EventHubClient : IEventHubClient
{
private readonly ILoggerAdapter<EventHubClient> _logger;
private readonly EventHubClientSettings _eventHubClientSettings;
private IMapper _mapper;
private static EventHubProducerClient _equipmentLocClient;
public EventHubClient(ILoggerAdapter<EventHubClient> logger, EventHubClientSettings eventHubClientSettings, IMapper mapper)
{
_logger = logger;
_eventHubClientSettings = eventHubClientSettings;
_mapper = mapper;
_equipmentLocClient = new EventHubProducerClient(_eventHubClientSettings.ConnectionString, _eventHubClientSettings.EquipmentLocation);
}
}
}
Based on my speculation in comments, I'm curious if refactoring to use async/await rather than the explicit continuation in the main loop may help. Perhaps something similar to the following LinqPad snippet:
async Task Main()
{
while (true)
{
var message = await Task.Factory.StartNew(() => GetText());
var events = new[] { new EventData(Encoding.UTF8.GetBytes(message)) };
await Send(events).ConfigureAwait(false);
}
}
public EventHubProducerClient client = new EventHubProducerClient("<< CONNECTION STRING >>");
public async Task Send(EventData[] events)
{
try
{
await client.SendAsync(events).ConfigureAwait(false);
"Sent".Dump();
}
catch (Exception ex)
{
ex.Dump();
}
}
public string GetText()
{
Thread.Sleep(250);
return "Test";
}
If you're set on keeping the continuation, I wonder if a slight structural refactoring in the continuation may help, both to push up creation of the events and to honor the await statements. Perhaps something similar to the following LinqPad snippet:
async Task Main()
{
while(true)
{
var t = Task.Factory.StartNew(() => GetText());
var _ = t.ContinueWith(async q =>
{
var events = new[] { new EventData(Encoding.UTF8.GetBytes(t.Result)) };
await Send(events).ConfigureAwait(false);
});
await Task.Yield();
}
}
public EventHubProducerClient client = new EventHubProducerClient("<< CONNECTION STRING >>");
public async Task Send(EventData[] events)
{
try
{
await client.SendAsync(events).ConfigureAwait(false);
"Sent".Dump();
}
catch (Exception ex)
{
ex.Dump();
}
}
public string GetText()
{
Thread.Sleep(250);
return "Test";
}
I have created a chat using SignalR2. The client and server itself works fine. Now, I'm trying to implement a 'users online' function. The server code seems about right, but I'm struggling to make the client receive the data that the server pushes back to the client.
This is the server code below:
public static List<string> Users = new List<string>();
public void Send(string name, string message)
{
// Call the broadcastMessage method to update clients.
Clients.All.broadcastMessage(name, message);
Clients.All.addMessage(name, message);
}
public void SendUserList(List<string> users)
{
var context = GlobalHost.ConnectionManager.GetHubContext<chatHub>();
context.Clients.All.updateUserList(users);
}
public override Task OnConnected()
{
string clientId = GetClientId();
//if (Users.IndexOf(clientId) == -1)
//{
Users.Add(clientId);
//}
SendCount(Users.Count);
return base.OnConnected();
}
public override Task OnDisconnected(bool stopCalled)
{
System.Diagnostics.Debug.WriteLine("Disconnected");
SendCount(Users.Count);
return base.OnDisconnected(stopCalled);
}
private string GetClientId()
{
string clientId = "";
if (Context.QueryString["clientId"] != null)
{
// clientId passed from application
clientId = this.Context.QueryString["clientId"];
}
if (string.IsNullOrEmpty(clientId.Trim()))
{
clientId = Context.ConnectionId;
}
return clientId;
}
public void SendCount(int count)
{
// Call the addNewMessageToPage method to update clients.
var context = GlobalHost.ConnectionManager.GetHubContext<chatHub>();
context.Clients.All.updateUsersOnlineCount(count);
}
Below is the client code for connecting / receiving messages:
public static async void ConnectAsync(RadChat ChatInternal)
{
ChatInternal.Author = new Author(null, Varribles.Agent);
var querystringData = new Dictionary<string, string>();
querystringData.Add("clientId", Varribles.Agent);
Connection = new HubConnection(ServerURI, querystringData);
HubProxy = Connection.CreateHubProxy("chatHub");
//Handle incoming event from server: use Invoke to write to console from SignalR's thread
HubProxy.On<string, string>("AddMessage", (name, message) =>
ChatInternal.Invoke((Action)(() =>
Backend.GET.Messages(ChatInternal)
)));
try
{
await Connection.Start();
Backend.GET.Messages(ChatInternal);
}
catch (System.Net.Http.HttpRequestException)
{
//No connection: Don't enable Send button or show chat UI
return;
}
}
Now, my question is, how can I retrieve the 'Users' list from the server?
Thanks in advance
I need to prepare a console application with 3 buttons, one that adds elements to a Redis queue, one that pops elements out of it and one that displays elements in the queue. I am new to C# and Redis. Can anyone help me with this, or provide me some resources.
I have coded up the connection to the Redis DB and am able to set and get variables.
using System;
using StackExchange.Redis;
namespace RedisConsoleApp1
{
class Program
{
static void Main(string[] args)
{
ConnectionMultiplexer redisCon = ConnectionMultiplexer.Connect("localhost");
IDatabase db = redisCon.GetDatabase();
//db.Lis
db.StringSet("foo", "dog");
string val = db.StringGet("foo");
Console.WriteLine("output is {0}", val);
Console.ReadKey();
}
}
}
Write a channel subscriber like that
public class RedisHostingRunner : HostedService
{
private readonly IServiceProvider _serviceProvider;
IRedisSubscriber _subscriber;
public RedisHostingRunner(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
_subscriber = _serviceProvider.GetRequiredService<RedisSubscriber>();
}
protected override async Task ExecuteAsync(CancellationToken cancellationToken)
{
//while (!cancellationToken.IsCancellationRequested)
//{
_subscriber.SubScribeChannel();
//await Task.Delay(TimeSpan.FromSeconds(60), cancellationToken);
//}
}
public Task ShutdownAsync(CancellationToken cancellationToken = default)
{
return Task.CompletedTask;
}
}
And in your subscriber set a message handler
public void SubScribeChannel()
{
_logger.LogInformation("!SubScribeChannel started!!");
string channelName = _config.ActiveChannelName;
var pubSub = _connectionMultiplexer.GetSubscriber();
try
{
pubSub.Subscribe(channelName, async (channel, message) => await MessageActionAsync(message, channel));
}
catch(Exception ex)
{
_logger.LogInformation(String.Format("!error: {0}", ex.Message));
}
Debug.WriteLine("EOF");
}
In your handler do your job
private async Task MessageActionAsync(RedisValue message, string channel)
{
try
{
Transformer t = new Transformer(_logger);
_logger.LogInformation(String.Format("!SubScribeChannel message received on message!! channel: {0}, message: {1}", channel, message));
string transformedMessage = Transformer.TransformJsonStringData2Message(message);
List<Document> documents = Transformer.Deserialize<List<Document>>(transformedMessage);
await MergeToMongoDb(documents, channel);
_logger.LogInformation("!Merged");
}
catch (Exception ex)
{
_logger.LogInformation(String.Format("!error: {0}", ex.Message));
}
}
I'm trying to create a UWP service app on the Raspberry Pi3 which provides the access to the on board UART. I'm facing an issue about the AppConnection Request/response.
this is the service method that handles the incoming requests from client apps
internal class Inbound
{
public static async void OnRequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
{
var messageDeferral = args.GetDeferral();
var response = new ValueSet();
bool success = false;
var msg = args.Request.Message.Keys;
if (args.Request.Message.TryGetValue(ServiceApiRequests.Keys.Command, out object command))
{
try
{
switch (command)
{
case ServiceApiRequests.CommandValues.UartWrite:
if (args.Request.Message.TryGetValue(ServiceApiRequests.Keys.UartTxBuffer, out object txBuffer))
{
string rxBuff = "";
success = await Pi3.Peripherals.Uart.GerInstance(57600).Write((string)txBuffer);
if (success)
{
Debug.WriteLine("Tx: " + (string)txBuffer);
if (args.Request.Message.TryGetValue(ServiceApiRequests.Keys.ReadUartResponse, out object getResponse))
{
if ((string)getResponse == ServiceApiRequests.ReadUartResponse.Yes)
{
rxBuff = await Pi3.Peripherals.Uart.GerInstance(57600).Read();
Debug.WriteLine("Rx: " + rxBuff);
}
}
}
response.Add(ServiceApiRequests.Keys.UartRxBuffer, rxBuff);
}
break;
}
}
catch (Exception ex)
{
success = false;
}
}
response.Add(new KeyValuePair<string, object>(ServiceApiRequests.Keys.Result, success ? ServiceApiRequests.ResultValues.Ok : ServiceApiRequests.ResultValues.Ko));
var result = await args.Request.SendResponseAsync(response);
if (result == AppServiceResponseStatus.Failure)
{
Debug.WriteLine("Failed to send the response");
}
messageDeferral.Complete();
}
}
As you can figure out, the Uart class is get using the Singleton pattern using the method Pi3.Peripherals.Uart.GerInstance(57600).
Following the code i using for send the request from the client app.
public static class Uart
{
public static IAsyncOperation<string> SendCommand(this AppServiceConnection DriverControllerConnection, string txBuffer, string awaitResponse = ServiceApiRequests.ReadUartResponse.Yes)
{
return _SendCommand(DriverControllerConnection, txBuffer, awaitResponse).AsAsyncOperation();
}
private static async Task<string> _SendCommand(AppServiceConnection DriverControllerConnection, string txBuffer, string awaitResponse)
{
AppServiceResponse response = null;
string response_str = "";
try
{
if (DriverControllerConnection != null)
{
response = await DriverControllerConnection.SendMessageAsync(new ServiceApiRequests.UartWrite().GetCommand(txBuffer, awaitResponse));
if (response.Status == AppServiceResponseStatus.Success)
{
if (response.Message.TryGetValue(ServiceApiRequests.Keys.Result, out object result))
{
if ((string)result == ServiceApiRequests.ResultValues.Ok && awaitResponse == ServiceApiRequests.ReadUartResponse.Yes)
{
response_str = response.Message[ServiceApiRequests.Keys.UartRxBuffer] as string;
}
}
}
}
}
catch (Exception ex)
{
// TODO: log
}
return response_str;
}
}
The system works well just for a while, until i have response.Status == AppServiceResponseStatus.Success , then the result of the request changes and it becomes AppServiceResponseStatus.Failure. This way the program counter never steps into the condition if (response.Status == AppServiceResponseStatus.Success).
Any idea about the cause?
Thank you so much for the help.
EDIT
Follow the suggestions, i added an handler for the ServiceClosed event. This is the main class.
public sealed class DriverListener : IBackgroundTask
{
private BackgroundTaskDeferral backgroundTaskDeferral;
private AppServiceConnection appServiceConnection;
public void Run(IBackgroundTaskInstance taskInstance)
{
backgroundTaskDeferral = taskInstance.GetDeferral();
// taskInstance.Canceled += OnTaskCanceled;
var triggerDetails = taskInstance.TriggerDetails as AppServiceTriggerDetails;
appServiceConnection = triggerDetails.AppServiceConnection;
appServiceConnection.RequestReceived += Inbound.OnRequestReceived;
appServiceConnection.ServiceClosed += OnTaskCanceled;
}
private void OnTaskCanceled(AppServiceConnection sender, AppServiceClosedEventArgs reason)
{
if (this.backgroundTaskDeferral != null)
{
Debug.WriteLine("ServiceClosed");
// Complete the service deferral.
this.backgroundTaskDeferral.Complete();
}
}
}
Placing a breakpoint in this function, i see that it was never triggered.
The app connection is opened using the singleton pattern, and putted in a dll that i use in the client app
public static AppServiceConnection GetDriverConnectionInstance()
{
if (_DriverConnectionInstance == null)
{
try
{
_DriverConnectionInstance = OpenDriverConnection().AsTask().GetAwaiter().GetResult();
}
catch
{
}
}
return _DriverConnectionInstance;
}
I also add a Request to the service that toggles a led, and i noticed that the led status changes but the response from the app service is still "Failure" and the message is null.
The AppService has a default lifetime of 25sec, unless it is being requested by the foreground experience. When the service shuts down the connection, your client process will receive the ServiceClosed event, so you know you will need to reopen the connection the next time you want to send a request.