I'm trying to get the connected user id in my signleR application but I didn't manage to find it. Is there any way to get it because I want when two users are chatting just the two of them will receive each other's messages and not the whole group they are connected to, or all clients connected to signleR hub. My main goal is to send private messages between two connected clients.
My code is so complicated but all I have found is how to broadcast my message to all the clients or to a specific group, but I couldn't manage to send a private message. I did this to send user typing message:
public void UserTyping(string msg, int ToClient) { // display User is Typing Msg
Clients.Others.OtherUserIsTyping(msg, ToClient);
}
ClientSide:
var keyPressCount = 0;
$("#<%=MsgToSend.ClientID %>").keypress(function () {
// Throttle the server call with some logic
// Don't want to call the server on every keypress
var ToClientID = $("#ToClientID").val();
if (keyPressCount++ % 10 == 0) {
chat.server.userTyping("Is typing...", ToClientID); // call the server side function
}
});
chat.client.OtherUserIsTyping = function (msg, ToClient) { // declare the function on the chat hub so the server can invoke it
$("#UserTyping").html(msg);
}
Related
I want to implement single session enforcement in my application. Meaning if another login activity found for the same user in different browser/different machine then then first session should get auto logoff. If I use the Ajax polling then unnecessary network traffic will happen. So am planning to use signalR.
For that i tried simple click event. Its working without refreshing the page from browser 1 to browser 2.
I created hubclass and my cshtml as follows
var myHub = $.connection.myHub;
$.connection.hub.logging = true;
$.connection.hub.start();
myHub.client.Postmessage = function (message) {
$('#message1').append('<li><strong>'+ htmlEncode(messaage) + '</li>')
$("btnClick").click(function () (
var message = $('message').val();
myHub.server.helloServer(message);
$('#message1').val('').focus();
External service class to find the session details
private static ISSEnforcementSvc ssEnforcement;
public static SSEnforcementSVC GetSSEnforcementService()
{
if (ssEnforcement == null)
{
var localService GetLocalizationsvc;
var configurationSvc = GetConfigurationSvc();
var cacheSvc = GetCacheSvc();
ssessionEnforcement Service = new
SinglesessionEnforcementService(localService,
configurationSvc,cacheSvc)
}
return ssEnforcement;
}
Please suggest how to implement same way to push the 1st browser to logoff.
When I try to broadcast a message to all clients, I can trigger client's javascript code from server and get the job done.
But this time my aim is to trigger a method in all servers. For example, when roles of a user changed in one server, I want to warn other servers about this operation and I want to make other servers retrieve updated user role list for particular user.
Is it possible to do this with SignalR? Can a server behave like a client (browser)?
Yes you can do that.
Let's say you have the following hub:
public class TheHub : Hub
{
public void RoleChanged(int userId)
{
Clients.All.roleChanged(userId);
}
}
On all the listening servers, you'd have to do:
var _connection = new HubConnection("http://localhost:1234/signalr");
var _theHub = _connection.CreateHubProxy("TheHub");
_myHub.On<int>("RoleChanged", userId =>
{
System.Diagnostics.Debug.WriteLine("Changed user's Id: " + userId);
});
_connection.Start().Wait();
To invoke the RoleChanged event, do:
_myHub.Invoke("RoleChanged").Wait();
I'm trying to replicate behavior like a client browser but in C# (Performance reason). What I'm trying to set out to achieve is that for every new events received, my program should trigger the server side (Hub) which would then notify the client. Rather than having a while loop which would repeatedly hit the hub method every time even if theres no messages, is there a way to treat it as a trigger/detection so that once message is detected then execute Hub method ? Hope this makes sense
Snapshot of Client code below:
IHubProxy _hub;
string url = #"http://localhost:8080/";
var connection = new HubConnection(url);
_hub = connection.CreateHubProxy("PersonHub");
connection.Start().Wait();
//client side method
_hub.On("checkedIn", x => Console.WriteLine(x));
Console.WriteLine("Enter Person Name");
var answer = Console.ReadLine();
while (true) // Better way doing this? trigger or detect new message?
{
//server side method
_hub.Invoke("GetByName", answer).Wait();
}
Snapshot of Hub code below:
[HubName("PersonHub")]
public class PersonHub: Hub
{
public Person GetByName(string name)
{
//logic and etc ...
Clients.All.checkedIn(name);
}
}
By setting the while loop to true this means this will always call the server side method (Hub method) which I dont want to. If theres new events triggered then it should hit the hub method. Is there a way to somehow listen for new message but not to execute if no messages has been detected?
A possible solution is:
string line;
while ((line = Console.ReadLine()) != "exit")
{
_hub.Invoke("GetByName", line).Wait();
}
Hello every one I am new to signalR I need little help to follow right approach in my chat module .
My Refernce :
http://www.codeproject.com/Articles/562023/Asp-Net-SignalR-Chat-Room but this article does not uses dataBase.
Steps which I have used to build my chat module are :
1 - Created chatHub class inherited from Hub class.
2 - On Connect(string enryptedId) function in chatHub class I am adding to List<UserDetail>.
3 - On SendPrivateMessage(string toData) I am saving it to database if it saved successfully to dataBase without any exception then sending it to both sender and reciever and binding on their communication messages <div>.
Problem in this approach - If after saving it to database if sender got disconnected due to network problem then sender will not recieve message from chathub class to client function so message is not appended to <div> which shows user communications but actually message sent successfully. Please can any one tell me the right approach to do this.
I would do it something like this, keep in mind its Pseduo code not tested or anything
private Dictionary<Guid, TaskCompletionSource<bool>> transactions = new Dictionary<Guid, TaskCompletionSource<bool>>();
public Task SendPrivateMessage(string content)
{
var taskCompletion = new TaskCompletionSource<bool>();
var transactionId = Guid.NewGuid();
transactions[transactionId] = taskCompletion;
var message = new Message
{
TransactionId = transactionId,
Content = content
};
GlobalHost
.ConnectionManager
.GetHubContext<MyHub>()
.Clients
.Client(connectionId)
.OnMessage(message);
return taskCompletion.Task;
}
public void OnTransactionConfirmed(Guid transactionId)
{
var taskCompletion = transactions[transactionId];
transactions.Remove(transactionId);
taskCompletion.SetResult(true);
}
Message is just a DTO
public class Message
{
public Guid TransactionId { get; set; }
public string Content { get; set; }
}
Basically you send a message to the client using the client method called OnMessage then you wait asynchronously until client confirms with the Hub method called OnTransactionConfirmed
Using a task makes it easier to work asynchronous in a synchronous way, the consumer of SendPrivateMessage could be asynchronous itself (If its called from a WebApi method or similar).
public Task MyWebApiMethod()
{
return myChatLogic.SendPrivateMessage("foo");
}
Or in a synchronous manner
public void MySyncMethod()
{
myChatLogic.SendPrivateMessage("foo").Wait(); //Thread will wait here until client asnwers
}
Note
To make this code failsafe you need to timeout the wait for confirmation and complete the task and remove the transactionId etc
your send message, receive message and display message should be handled separately. you did well with the send message except that you need to add a datetime stamp generated by the Server (do not use time from client) to each message and store it in sql. whenever there is a new message received, the Server should send this message to all online senders' and receivers' client browser or app.
here I said senderS because user A may login using a phone and at the same time login using office desktop browser, if user A send a message to user B mobile phone using the desktop browser, this message should be appear in 3 client device: user A desktop browser, user A mobile phone and user B mobile phone.
for the receiver, whenever go from offline to online, check the last message datetime stored in client side using cookie or file or clientside sqlite or clientside internal storage, with the Server database and get all related messages since last offline by comparing the last message datetime from clientside and message dt from server database.
for the display message, only read from client side storage so that the apps can run offline.
When sending a message, append a random string of 8 characters to the start of the message. On your message received function, cut out the first 8 characters and send those back to the original sender.
If you receive the same characters back from the receiver, then you know that receiver has received the message and has not been disconnected.
You can use this method to generate a random string.
private static IEnumerable<string> RandomStrings(
string allowedChars,
int minLength,
int maxLength,
Random rng)
{
char[] chars = new char[maxLength];
int setLength = allowedChars.Length;
int length = rng.Next(minLength, maxLength + 1);
for (int i = 0; i < length; ++i)
{
chars[i] = allowedChars[rng.Next(setLength)];
}
return new string(chars, 0, length);
}
you will can call the method like this
private string GetRandomStrings(){
const string AllowedChars =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz##$^*()";
Random rng = new Random();
return RandomStrings(AllowedChars, 8, 8, 1, rng)
}
I want to create html5 web multiroom chat, based on HTML5 websocket.
But I need some little help to start.
I want to do server side code in c#, but I can not find any tutorials how to do chat websocket server with multi room in c#.
Is there any server which is already implemented in .net, or which I can update to multi room chat ?
It is a little project, one room for 10 peoples. Could you help to me how to start ?
Thank you very much !
I prepare example code structure:
Main server class:
class Program
{
// List of courses, which are currentli avalible ( REPRESENT CHAT ROOM)
protected static ConcurrentDictionary<Course, string> OnlineUsers = new ConcurrentDictionary<Course, string>();
static void Main(string[] args)
{
// Initialize the server on port 81, accept any IPs, and bind events.
var aServer = new WebSocketServer(81, IPAddress.Any)
{
OnReceive = OnReceive,
OnSend = OnSend,
OnConnected = OnConnect,
OnDisconnect = OnDisconnect,
TimeOut = new TimeSpan(0, 5, 0)
};
aServer.Start();
// Accept commands on the console and keep it alive
var command = string.Empty;
while (command != "exit")
{
command = Console.ReadLine();
}
aServer.Stop();
}
// event when the clients connect to server
// Server send to client list of Lessons which are avalible, after
private static void OnConnect(UserContext context)
{
throw new NotImplementedException();
}
// event whent the client, want to disconnect from server
private static void OnDisconnect(UserContext context)
{
throw new NotImplementedException();
}
// event, when client is sending some data
private static void OnSend(UserContext context)
{
throw new NotImplementedException();
}
// event, when server receive data from client
// client choose which room want to join and, we add cleint to list of lessons which he choose
// another method ... Register, Rename, LogOff ...
private static void OnReceive(UserContext context)
{
throw new NotImplementedException();
}
}
Course class: (ROOMS)
class Course
{
// Every course has list of active users
protected static ConcurrentDictionary<User, string> OnlineUsers = new ConcurrentDictionary<User, string>();
// Name of course
public String CourseName { get; set; }
}
User class:
class User
{
// Name of User
public string Name = String.Empty;
// UserContext - Contains data we will export to the Event Delegates.
public UserContext Context { get; set; }
}
It is good structure for my purpose ? I have many courses (room), with one teacher, in one course can be 20 pupils example .. In one course the pupils can talk with techer using chat (web socket) and drawing board ..
That's how I would build the object hierarchy:
The chat server should have a list of ChatRooms.
Each ChatRoom should have a list of ChatUsers.
Each ChatUser should have one or no ChatRoom and an outbound socket.
(this assumes that a user is only in one room at a time. Allowing multiple rooms would make things a bit more complex)
That's how room selection could work:
When a client connects, a ChatUser is created. The first thing the server does is send the list of chatrooms to the user. The client then responds with the name of the chatroom it wants to join. When a chatroom of that name doesn't exist, it is created and added to the global list of rooms.
The client is then added to the room, and the room is set on the client.
That's how chatting could work:
When the socket of the user receives a chat message, it should call a SendToAllClients method on the room the user is currently in (when the room is null, it should return an error message to the user that they must join a room first).
The SendToAll method of the room should then call a SendToClient of all users which are on its list of users.
The SendToClient method of the class would then send the chat message to the client.
How to expand this for multiple chatrooms per user
To allow a client to join multiple chatrooms at once and have separate conversations in them, the client must be able to:
request a list of rooms at any time, not just at startup
join rooms at any time, not just at startup
leave rooms
specify the room when sending a message
That means that the action the client wants to perform can not be deduced from the state it is currently in. You need to add this information to the messages of the user. You could, for example, do this as prefixes. Like
!list
requests the list of rooms
!join:asdf
join/create the room asdf
_asdf:Hello
sends the message Hello to the room asdf.
The messages from the server should have similar prefixes, so that the client can deduce if a message is a room list or a chat message and from what room it originates.
You should try to look into SignalR for ASP.NET (example : jabbr.net/). This may be more helpful and handy.