I am writing a ReactNative application with a C# Rest Api server. The application communicates via POST and GET requests (transfer of database records, user profiles, etc.). Now there is a need to create an internal chat in this application. I send messages from the client with POST requests, in which I pass the client token, the message text and the user name to which the message is sent (everything is encrypted). But there was a problem. As a chat user, receive new messages instantly. The first thing that came to mind was to also send a request to the server every 100 milliseconds to receive new messages. If there are messages, the server will return them to the client, if not, it will return an empty response. But I understand that this is some kind of crutch method and there may be a big load on the server. I started reading about SignalR and hubs. But I didn't find high-quality information. As far as I understand, messages will be delivered only if the second user is also connected to the hub. What if it's offline? Then the messages will not be delivered to him? I still don't understand in which direction I should work and which path to choose. Maybe this SignalR is not required at all. Which way should I choose? What kind of management architecture is needed to create such a chat between users inside the application? I hope for your understanding and desire to help the beginner).If possible, provide an example of the server (C#) and client (ReactNative js) code. Thank u.
[AcceptVerbs("POST")]
[Route("GetNewMessages")]
public List<BDMMessenge> GetNewMessages([FromBody] string token)
{
string user = db.bdmuser.Where(x => x.Token == token).Single().Email;
var messages = db.bdmmessenge.Where(x => x.ToUser == user && x.ClientGet == 0).ToList();
SetGetStatus(messages.Select(x => x.Id).ToList());
return messages;
}
[AcceptVerbs("POST")]
[Route("SendTextMessage")]
public DateTime SendTextMessage([FromBody] MMessageText _message)
{
string user = db.bdmuser.Where(x => x.Token == _message.Token).Single().Email;
var dataStatus = DateTimeOffset.Now.UtcDateTime;
db.bdmmessenge.Add(new BDMMessenge()
{
FromUser = user,
ToUser = _message.ToUser,
Type = "Text",
Content = _message.Content,
DataStatus = dataStatus,
ClientGet = 0
});
db.SaveChanges();
return dataStatus;
}
Related
I have Chat Bot created using C# SDK V4 and it has multiple water fall dialog classes each for performing specific action when a certain option is selected. The BOT has authentication also embedded using Oauth Prompt.
Channel: Web Channel
SDK: SDKV4
Language: C#
Now, I want to have the state management handled or kept in the water fall dialog as the example i see is on top of normal echo bot and if i implement the same lines on my existing bot having water fall dialog it is not working.
Coming to reason why i want state management as After authenticating the user using Oauth Prompt i am displaying the options based upon the logged in User
Now 2 or more users log in simultaneously or one after the other the other login is getting taken and data of second logged in user is getting displayed for the first user when he toggles back and forth with in the options displayed for selection.
When i logged a query on how to maintain the logged in user or refresh the logged in user i was suggested to have state management technique hence this query on how to do it in a water all dialog.
If state management is not the correct option then can you please let me know how to refresh or maintain the logged in user id?
This suspect the issue is tied to the props you are passing to Direct Line when you start up Web Chat. Referenced under Integrate with Javascript, the docs state:
Assigning userID as a static value is not recommended since this will cause all users to share state. Please see the API userID entry for more information.
When you make a call to generate a token, the userID (which should be unique to the user) should be passed along at that point, else you will run into issues of shared state.
Here is a bit of the code I run for accessing a local API that gets and returns a direct line token. As you can see, the userID is passed in the request which is then baked into the token when returned.
// Listen for incoming requests.
server.post('/directline/token', (req, res) => {
// userId must start with `dl_`
const userId = (req.body && req.body.id) ? req.body.id : `dl_${ Date.now() + Math.random().toString(36) }`;
const options = {
method: 'POST',
uri: 'https://directline.botframework.com/v3/directline/tokens/generate',
headers: {
Authorization: `Bearer ${ process.env.directLineSecret }`,
'Access-Control-Allow-Origin': '*'
},
json: {
user: {
ID: userId
}
}
};
request.post(options, (error, response, body) => {
if (!error && response.statusCode < 300) {
res.send(body);
console.log('Someone requested a token...');
} else if (response.statusCode >= 400 && response.statusCode < 500) {
res.send(response.statusCode);
} else if (response.statusCode >= 500) {
res.status(response.statusCode);
res.send('Call to retrieve token from DirectLine failed');
}
});
});
Hope of help!
I am using Bot Framework v4 with c# and deploying to Slack channel. I want to create a timer in the bot or outside using Azure functions. In case of no user input for x mins, the bot should send a message like "Are you there?"
Having read many article on Internet I couldn't find the desired solution
I tired to follow this Automatically Bot display rating card after few seconds to take user feedback
but do not fully understand what this person says there. Can any one help me out?
My method works for Directline Webchat, but you may be able to take this concept and use it in a solution that will work for Slack.
When using botframework-webchat, you are able to set up a custom store to track inactivity. In my example below, I'm using a combination of a page title "notification" with sending a message. But you could simply set the interval and send the message without any of the page title changes.
let interval;
var PageTitleNotification = {
Vars:{
OriginalTitle: document.title,
Interval: null
},
On: function(notification, intervalSpeed){
var _this = this;
_this.Vars.Interval = setInterval(function(){
document.title = (_this.Vars.OriginalTitle == document.title)
? notification
: _this.Vars.OriginalTitle;
}, (intervalSpeed) ? intervalSpeed : 1000);
},
Off: function(){
clearInterval(this.Vars.Interval);
document.title = this.Vars.OriginalTitle;
}
}
// We are using a customized store to add hooks to connect event
const store = window.WebChat.createStore({}, ({ dispatch }) => next => action => {
if (action.type === 'WEB_CHAT/SEND_MESSAGE') {
// Message sent by the user
PageTitleNotification.Off();
clearTimeout(interval);
} else if (action.type === 'DIRECT_LINE/INCOMING_ACTIVITY' && action.payload.activity.name !== "inactive") {
// Message sent by the bot
clearInterval(interval);
interval = setTimeout(() => {
// Change title to flash the page
PageTitleNotification.On('Are you still there?');
// Notify bot the user has been inactive
dispatch({
type: 'WEB_CHAT/SEND_EVENT',
payload: {
name: 'inactive',
value: ''
}
});
}, 300000)
}
return next(action);
});
The challenge when you are using Slack channel is that you can't inject something like this on Slack client side, so you will need to do it externally. The best guidance I can give you is to start from the proactive notification sample. You will need to get the conversation reference from turnContext via something like turnContext.getConversationReference() and store it. You can then send it to a function and start a timer. If the function doesn't receive another message for that reference during your specified time period, you can send the proactive message.
I think you would want to do this as a local function in your bot, not an Azure Function, because you want to reset the timer every time the user sends a new message. I'm not sure how you would keep track of that using an external Azure Function. Hopefully this will be enough to give you some ideas on implementing this functionality in Slack channel.
I am developing a small chat implementation in my app and I want to be notified when someone has joined/left the channel and who that person is.
On the client side I am listening to OnJoin and OnLeave, which take a ServerEventCommand object, in order to showcase the message, but the ServerEventCommand object is populated with some seemingly random properties on the server side after I have registered on the client side.
I'm looking into the ServerEventsClient object and all of its properties but cannot find a way for me to set the properties I want before invoking Start().
The displayName isn't a property you set, it's sent by the server to identify which users are joining/leaving the channels you're subscribed to. It will either contain the UserName of the User or if your Auth Provider doesn't use UserNames (e.g. Uses Email or id number instead) it will use the DisplayName property of the Users Session.
You need to register event handlers in your Server Events Client before calling .start(), e.g using the TypeScript ServerEventsClient:
const channels = ["home"];
const client = new ServerEventsClient("/", channels, {
handlers: {
onConnect: (sub:ServerEventConnect) => { // Successful SSE connection
console.log("You've connected! welcome " + sub.displayName);
},
onJoin: (msg:ServerEventJoin) => { // User has joined subscribed channel
console.log("Welcome, " + msg.displayName);
},
onLeave: (msg:ServerEventLeave) => { // User has left subscribed channel
console.log(msg.displayName + " has left the building");
},
}).start();
Only after you've started your subscription and are subscribed to your channel will you receive any events.
Channel Subscribers
Most Server Event Clients also allow you fetch a list of Users, e.g. with the TypeScript client you can call getChannelSubscribers():
client.getChannelSubscribers()
.then(users => users.forEach(x =>
console.log(`#${x.userId} #${x.displayName} ${x.profileUrl} ${x.channels}`)));
Alternatively you can call /event-subscribers directly to fetch the list of users in each channel, e.g:
$.getJSON("/event-subscribers?channels={{ channels }}", function (users) {
});
Example Chat Apps
For reference there are a number of simple Apps written in different languages which uses the different Server Event Clients available to create a simple Chat App:
JavaScript Client
Chat https://github.com/NetCoreApps/Chat
React Chat https://github.com/ServiceStackApps/ReactChat
TypeScript Client
Web, Node.js and React Native Chat https://github.com/ServiceStackApps/typescript-server-events
C# Server Events Client
Xamarin.Android Chat https://github.com/ServiceStackApps/AndroidXamarinChat
Java Client
Android Java Chat https://github.com/ServiceStackApps/AndroidJavaChat
I'm developing a graphic user interface where the user can send a message to mutuple user using Twilio API in c#
I'm trying to bind a list view to the status of each number being sent and I also want to know the status of the message every time the user click on refresh list view
public void sendSMS(string ssid, string token , string fromNumber, List<string>TOnumbersList ,string msgBody )
{
TwilioClient.Init(ssid, token);
foreach (var toNumber in TOnumbersList)
{
var message = MessageResource.Create(
to: new PhoneNumber(toNumber),
from: new PhoneNumber(fromNumber),
body: msgBody,
provideFeedback: true,
statusCallback: new Uri("http://requestb.in/1jnk4451"));
ListViewItem items = new ListViewItem(message.To);//This show the number being sent to ( delivered number)
items.SubItems.Add(message.Status.ToString()); //Refresh the status WHERE number = message.To
items.SubItems.Add(message.ErrorCode.ToString());//Show error code in case
items.SubItems.Add(message.ErrorMessage); // In case error message show them
listView1.Items.AddRange(new ListViewItem[] { items });
}
}
Twilio API is doing the perfect job updating the status so everytime I go click the link I can see the status. as explained in this documentation Track Delivery Status of Messages in C#
But is It possible to bind a list view so it can be updated everytime the user click on refresh list view ?
Or what is the best way to dynamically show the message status from the URI http://requestb.in/1jnk4451? Maybe embedding a webpage would be better ?
Thank you
Twilio developer evangelist here.
Rather than using the RequestBin URL, if you provide a URL to your own application then you can write an endpoint that receives the status updates of the messages. That way you can store the status yourself and update the list view without having to loop through all the messages.
[Edit] In more detail:
When you send an SMS message with Twilio using the REST API you can set a statusCallback URL to receive updates about the message as it processes through from Twilio to the network and the device.
Twilio will make HTTP requests to this URL as the message goes through each state, the possible states being queued, failed, sent, delivered, or undelivered. Twilio sends a number of parameters as part of this request, some are general ones about the message and some are about the actual status.
To receive these requests you need to set up a web server. I'm not a C# developer I'm afraid, however we have a guide on how to set up a C# and ASP.NET MVC environment that can receive webhooks that should be able to help you there.
Let me know if this helps a bit more!
I want to be able to send messages to a specific client, I have working code but I cannot find a way to identify users, as on each page load/refresh the client id will change, so I cannot rely on that.
I have tried to append a querystring to the connection, but I have only been able to find the querystring of the same context.
This is my hub, and within the send method i want to be able to match the id that is sent in to a particular connection id at the point of sending the message:
public class Chat : Hub
{
public string addMsg()
{
return "";
}
public void Send(string message, string id)
{
Clients.Client(Context.ConnectionId).receiveMessage(message);
}
}
Here is my client code, i want to pass the id of the person to send a message to to the server send method, and use the querystring value of the other connected user to match it to the id i am sending.
var chat = $.connection.chat;
chat.client.receiveMessage = function (message) {
alert("Received from server: " + message);
};
chat.addMsg = function (message) {
};
$("#sendMessage").click(function () {
chat.server.send($('#newMessage').val(), 6);
});
$.connection.hub.qs = "id=1";
$.connection.hub.start().done(function () {
var myClientId = $.connection.hub.id;
var qs = $.connection.hub.qs;
});
I hope my question makes sense, I have been trying to crack this for a while now, below are some links to some of the articles i have used to get to where i am now, I am just missing the last piece of the puzzle, please go easy on me :)
http://weblogs.asp.net/davidfowler/archive/2012/11/11/microsoft-asp-net-signalr.aspx
SignalR- send data to a specific client
https://github.com/SignalR/SignalR/wiki/QuickStart-Hubs
I don't think this is going to work the way you want it to. The connection ID is just that -- an identifier for a particular connection. SignalR itself doesn't know anything about authenticating users. It is, however, built on top of ASP.NET and all of your familiar authentication methods (Windows, Forms, etc.) work as you would expect.
Once ASP.NET has authenticated the user, you have access to this in your hubs as Context.User. It's now up to you to maintain a mapping between this user and one or more connection IDs. Besides browser refreshes, you might need to deal with a user accessing your service from multiple browsers or machines. Sending a message to this user means sending it to all of those browsers and machines.
Jabbr does all this and more. You really should take a look at that code for a good way to implement this.
How about using the Clients.Caller object int he hub, and overriding the OnConnected method:
public override Task OnConnected()
{
Clients.Caller.sendInitMessage(...);
return base.OnConnected();
}