What determines the SignalR connectionID and how to set it manually - c#

I'm playing around with SignalR and was wandering how SignalR creates a connectionID is this based on my IP adress, the device I connect with or something else? And wether it is possible to set this ID manually. Let say I have a database with users which I give a unique number, can I use that number for the connectionID?
Kind regards

The SignalR connection Id is a generated guid. If you'd like to target users in a more meaningful way with your data, I found it useful to pass something with your client connection, such as a user Id and some other data from your database, along to the signalr hub and craft up a group based on what you provide. It should be a 1:1 mapping if you're trying to isolate users with your own identifiers.
you can do this by overriding OnConnected() in your hub, and implementing something like this, which would map the generated Id to your own. You can then target these groups (remember, 1:1, emulating an Id selector) to your liking.
public override Task OnConnected()
{
var user = new User()
{
Id = Context.QueryString["Id"]
Name = Context.QueryString["Name"]
}
Groups.Add(Context.ConnectionId, user.Id);
return base.OnConnected();
}
Mapping SignalR Users to Connections goes into more detail as well.

Related

Find SignalR client by ID in its context

So I want to send a message to a specific client via SignalR. That client is not Clients.Caller - currently I can only identify it by let's call it "ID", a property in the context: this.Context.Items["ID"]
So to find a client by its ID, how do I...access all clients or contexts? Or should I save this ID in a different way? This is not the connection ID, it is an ID that maps to something in the database.
Basically I'd like to go Clients.Single(c => c.Items["ID"] == specificId).SendMessage(msg);
In the OnConnectedAsync method in your hub, you can group a user by their "ID" each time they connect.
E.G:
public async override Task OnConnectedAsync()
{
var currentUserId = /*get your current users id here*/
await Groups.AddToGroupAsync(Context.ConnectionId, $"user-{currentUserId}");
await base.OnConnectedAsync();
}
Then when you need to send that person a message, you can just broadcast it to their 'personal' group. (One person may have multiple connections, so the group approach work perfectly for us).
E.G:
Clients.Group($"user-{userId}").SendAsync("UserSpecificMessage", message);
When users disconnect, SignalR will handle the removing of connections from the groups automatically.
In using this approach, we do not have to unnecessarily broadcast a message to every single client with the intention of only one client filtering out the message based on the id.
You can send the ID down to the clients using context.Clients.User(...) or context.Clients.All(). Then in JavaScript, read the ID and compare it to what's on the page. If it's a match, carry out some action; else ignore.
As an example, let's say your app's processing a specific record on an edit screen. The record ID is on the page as a form field. You send a SignalR message down from C# with the ID. You do a comparison in JavaScript between the ID and the form field value; if they match, you display a toaster message, perform other processing, etc.

Searching for certain mail addresses: The Method "Contains" is not supported

using Microsoft.Azure.ActiveDirectory.GraphClient, I want to get twenty accounts from Azure Active Directory; given their email addresses. I could now send twenty requests to the Azure AD server, but in the meantime, my script times out. So I tried a single request:
public override IEnumerable<IDirectoryEntry> GetEntriesForMails(IEnumerable<MailAddress> emails)
{
foreach(IUser user in _connection.Client.Users.Where(x => emails.Contains(x.Mail)).FlattenPages())
{
yield return new AzureDirectoryEntry(user, this);
}
This throws the error that
"Contains" is not supported.
Is there another, supported, way to get all user accounts for twenty email addresses in a single round trip to the server?
Try the code :
List<IUser> users = activeDirectoryClient.Users.ExecuteAsync().Result.CurrentPage.ToList();
List<IUser> user1 = users.Where(u => emails.Any(e => e.Contains(u.Mail))).ToList();
As per a Microsoft employee, there is no direct solution in the library.
The best solution we could come up with is to keep a client-side lookup table that maps email adresses to ObjectIds; and update that table regularly (daily/weekly, and whenever a lookup failed).
One can then get the Objects for 20 ObjectIds from Azure AD in a single call (GetObjectsByObjectIdsAsync method).

How to send notification to a particular employee using signalR

I am working on a crm where Jobs are assigned to employees automatically and when a job is created application looks for the employee with maximum idle time.I am able to broad cast notification to all the employees but I want to know how to send notification to the employee for which job is assigned.Just like facebook each user recieves his notifications only.I am using this statement in hub class
Clients.All.broadcastMessage( message);
You are currently broadcasting your messages to everyone I suggest you useClients.User(userid)
Get the current logged in user string userName = HttpContext.Current.User.Identity.Name;
And then to send out notification to the particular user you can have something like.
Clients.User(userName).broadcastMessage(message);
You have to recognize user depending on connectionId.
Here is a good blog post describing this:
http://www.tugberkugurlu.com/archive/mapping-asp-net-signalr-connections-to-real-application-users
I was struggling with this just 3 days ago, and finally got it working.
Suppose you have a Hub class called YourHub, your javascript code should look like this
$(function () {
var yourHub = $.connection.YourHub;
yourHub.client.OnMessage = function ( message) {
console.log(message):
};
});
Then you need to implement IUserIdProvider on the server, which receives a IRequest (there should be a cookie or something for you to identify the person), and implement the method
public string GetUserId(IRequest request)
Then as Izzy told you use Clients.User(userId).OnMessage(message)
where userId is the id you return on the GetUserId and OnMessage is the method in your javascript file.
Be carefull to use Clients.User(userId) not Clients.Client(userId)

SignalR - Send message to user using UserID Provider

Using SignalR, I believe I should be able to send messages to specific connected users by using UserID Provider
Does anyone have an example of how this would be implemented? I've searched and searched and can not find any examples. I would need to target a javascript client.
The use case is, users to my site will have an account. They may be logged in from multiple devices / browsers. When some event happens, I will want to send them a message.
I have not looked into SignalR 2.0 but I think this is an extension of what the previous versions of SignalR used to have. When you connect to the hub you can decorate it with an Authorize attribute
[HubName("myhub")]
[Authorize]
public class MyHub1 : Hub
{
public override System.Threading.Tasks.Task OnConnected()
{
var identity = Thread.CurrentPrincipal.Identity;
var request = Context.Request;
Clients.Client(Context.ConnectionId).sayhello("Hello " + identity.Name);
return base.OnConnected();
}
}
As you can see you are able to access the Identity of the user accessing the Hub. I believe the new capability would be nothing more than an extension of this. Since the connection is always kept alive between the client and the hub you will always have the principal identity which will give you the UserId.
I believe this can help you: (linked from here)
A specific user, identified by userId.
Clients.User(userid).addContosoChatMessageToPage(name, message);
The userId can be determined using the IUserId interface:
public interface IUserIdProvider
{
string GetUserId(IRequest request);
}
The default implementation of IUserIdProvider is PrincipalUserIdProvider. To use this default implementation, first register it in GlobalHost when the application starts up:
var idProvider = new PrincipalUserIdProvider();
GlobalHost.DependencyResolver.Register (typeof(IUserIdProvider), () => idProvider);
The user name can then be determined by passing in the Request object from the client.

Way to get updates from database with SignalR (real time)?

Is there a way to get database's exist fields and new fields with SignalR?
I would like to make a multi chat application with MVC; and I would like to store all messages etc. in sql server database...
Planned rotation of the data will be client=>sql server=>client...
The technology is new or unknown so I couldn't find smart examples...
check this article and you should be able to save all incomming messages to DB on OnReceivedAsync Method.
http://visualstudiomagazine.com/articles/2013/01/22/build-a-signal-r-app-part-1.aspx
if you need to send last 20 records to any specific user or broadcast you can use below statement once you fetched last 20 records from you DB.
Connection.Broadcast(chatData); // this will broadcast data to all connected clients.
protected override Task OnConnectedAsync(IRequest request, string connectionId)
{
_clients.Add(connectionId, string.Empty);
ChatData chatData = new ChatData("Server", "A new user has joined the room.");
return Connection.Broadcast(chatData);
}

Categories