C
C#3y ago
PontiacGTX

Signalr not sending message(s) to specific user(s)

in the hub i have setup this signature for a method
public async Task SendMessage(string sender, string receiver, string message)
{
await Clients.Users(sender, receiver).SendAsync("ReceiveMessage", receiver, message);
}
public async Task SendMessage(string sender, string receiver, string message)
{
await Clients.Users(sender, receiver).SendAsync("ReceiveMessage", receiver, message);
}
and in the client side(the page on blazor server) i have set this up for the ReceiveMessage method
public async Task OnInitializeAsync()
{

if(hub is null)
hub = new HubConnectionBuilder()
.WithUrl(_NavigationManager.ToAbsoluteUri("/ConnectionsHub"))
.Build();
hub.On<string, string>($"ReceiveMessage", // this is never triggered
async (sender, message) =>
{
var encodedMsg = $"{sender}: {message}";
ChatBox.MessageList.Add(encodedMsg);
await ChatBox.ComponentStateHasChanged();
});
hub.ServerTimeout = TimeSpan.FromMilliseconds(100000);
await hub.StartAsync();
}
public async Task OnInitializeAsync()
{

if(hub is null)
hub = new HubConnectionBuilder()
.WithUrl(_NavigationManager.ToAbsoluteUri("/ConnectionsHub"))
.Build();
hub.On<string, string>($"ReceiveMessage", // this is never triggered
async (sender, message) =>
{
var encodedMsg = $"{sender}: {message}";
ChatBox.MessageList.Add(encodedMsg);
await ChatBox.ComponentStateHasChanged();
});
hub.ServerTimeout = TimeSpan.FromMilliseconds(100000);
await hub.StartAsync();
}
and how I call this method
private async Task SendMessage(string message)
{
if(string.IsNullOrEmpty(message))
{
await PrintMessage("Error", "Cannot send an empty message");
return;
}
if (hub is not null)
{

foreach (var user in _UserList)
{
await hub.SendAsync("SendMessage", ThisUser.Email, user.User.Email,ChatBox.Message);
}

// await ChatBox.ComponentStateHasChanged();
}
}
private async Task SendMessage(string message)
{
if(string.IsNullOrEmpty(message))
{
await PrintMessage("Error", "Cannot send an empty message");
return;
}
if (hub is not null)
{

foreach (var user in _UserList)
{
await hub.SendAsync("SendMessage", ThisUser.Email, user.User.Email,ChatBox.Message);
}

// await ChatBox.ComponentStateHasChanged();
}
}
68 Replies
Yawnder
Yawnder3y ago
@PontiacGTX Right now, what is your problem? Your message isn't received by the user, or it's received by too many users?
PontiacGTX
PontiacGTXOP3y ago
it isnt recieved by me (who sent it) it moves into the SendAsync method in SendMessage and then it doesnt trigger the Action (I am the sender and the receiving user)
Yawnder
Yawnder3y ago
Have you debugged the service for when you connect with the client to make sure that part works, and when you try to send a message to the user, what's the value you're using for it's client?
PontiacGTX
PontiacGTXOP3y ago
some ranodm string but i see that the client is repeated twice maybe i shoudl use an if else
Yawnder
Yawnder3y ago
A random string? How do you expect that to work?
PontiacGTX
PontiacGTXOP3y ago
if it is the use myself only send it to me and not twice my username i mean the message is what i have sent (some random thing) lol
Yawnder
Yawnder3y ago
Ok, but I'm talking about the recipient. What's the value? You're actually sending the message twice, once to the recipient and once to the sender.
PontiacGTX
PontiacGTXOP3y ago
my username in identity i am senidn ti twice yeah but not receiving it once
Yawnder
Yawnder3y ago
Then that's probably the problem. SignalR doesn't care about your identity itself, it wants the clientId.
PontiacGTX
PontiacGTXOP3y ago
mmm
PontiacGTX
PontiacGTXOP3y ago
Stack Overflow
SignalR - Sending a message to a specific user using (IUserIdProvid...
In the latest version of Asp.Net SignalR, was added a new way of sending a message to a specific user, using the interface "IUserIdProvider". public interface IUserIdProvider { string GetUserId(
PontiacGTX
PontiacGTXOP3y ago
await _userManager.AddClaimAsync(user, new Claim(ClaimTypes.Email, Model.Email)); this line
Yawnder
Yawnder3y ago
Did you create and register the CustomEmailProvider? (And is the email part of the claims of the user?)
PontiacGTX
PontiacGTXOP3y ago
well i dont know if i setup the custom email provider where do i set it?
Yawnder
Yawnder3y ago
It's in the SO post.
PontiacGTX
PontiacGTXOP3y ago
i have this
builder.Services
.AddDbContext<AppDbContext>(options => { options.UseNpgsql(conString); })
.AddIdentity<AppUser, IdentityRole>(options =>
{
options.SignIn.RequireConfirmedAccount = true;
options.SignIn.RequireConfirmedEmail = true;
options.User.RequireUniqueEmail = true;
})
.AddUserStore<AppUserStore>()
.AddDefaultUI()
.AddSignInManager()
.AddEntityFrameworkStores<AppDbContext>()
.AddTokenProvider<DataProtectorTokenProvider<AppUser>>(TokenOptions.DefaultProvider);
builder.Services
.AddDbContext<AppDbContext>(options => { options.UseNpgsql(conString); })
.AddIdentity<AppUser, IdentityRole>(options =>
{
options.SignIn.RequireConfirmedAccount = true;
options.SignIn.RequireConfirmedEmail = true;
options.User.RequireUniqueEmail = true;
})
.AddUserStore<AppUserStore>()
.AddDefaultUI()
.AddSignInManager()
.AddEntityFrameworkStores<AppDbContext>()
.AddTokenProvider<DataProtectorTokenProvider<AppUser>>(TokenOptions.DefaultProvider);
then builder.Services.AddSingleton<IUserIdProvider, CustomEmailProvider>(); builder.Services.AddSignalR();
public class CustomEmailProvider : IUserIdProvider
{
public virtual string GetUserId(HubConnectionContext connection)
{
return connection.User?.FindFirst(ClaimTypes.Email)?.Value;
}
}
public class CustomEmailProvider : IUserIdProvider
{
public virtual string GetUserId(HubConnectionContext connection)
{
return connection.User?.FindFirst(ClaimTypes.Email)?.Value;
}
}
Yawnder
Yawnder3y ago
Oh, then you have the custom email provider. If you put a breakpoint in there, what happens?
PontiacGTX
PontiacGTXOP3y ago
PontiacGTX
PontiacGTXOP3y ago
just starting up (i havent sent anything)
Yawnder
Yawnder3y ago
Humn... what's the value of res?
PontiacGTX
PontiacGTXOP3y ago
loggged int
PontiacGTX
PontiacGTXOP3y ago
it skips it i think this is wrong let me try something different var res = connection.User?.Claims.FirstOrDefault(x=>x.Type==ClaimTypes.Email)?.Value; this worked somehow the other method didnt lol
Yawnder
Yawnder3y ago
Good. Then res is a Guid (well, string representation) and your message gets sent?
PontiacGTX
PontiacGTXOP3y ago
it si my username
public virtual string GetUserId(HubConnectionContext connection)
{

var res = connection.User?.Claims.FirstOrDefault(x=>x.Type==ClaimTypes.Email && x.Value == connection.User.Identity.Name);
return res?.Value;
}
public virtual string GetUserId(HubConnectionContext connection)
{

var res = connection.User?.Claims.FirstOrDefault(x=>x.Type==ClaimTypes.Email && x.Value == connection.User.Identity.Name);
return res?.Value;
}
so my email
Yawnder
Yawnder3y ago
That's not what you want.
PontiacGTX
PontiacGTXOP3y ago
why?? oh well i see the method says the Id connection User contains the id also i would like to use my email a smy idnetifier but if you say i must return the id...
Yawnder
Yawnder3y ago
Well, I might be wrong. I always used the plain SignalR UserId. Give me a sec to read on it. OH! Nevermind, it's now how I thought it was. It must return the email, you're right What it's doing is not "map the email to the userId". It's, when a connection is established, SignalR asks that provider "What do you want me to use as Id" So to recap: This must return your email in your context.
PontiacGTX
PontiacGTXOP3y ago
well in my context let me check
PontiacGTX
PontiacGTXOP3y ago
PontiacGTX
PontiacGTXOP3y ago
this si what the context returns no user
Yawnder
Yawnder3y ago
But you're not in the same context there.
PontiacGTX
PontiacGTXOP3y ago
where do you want me to check the context
Yawnder
Yawnder3y ago
In the code of the UserIdProvider, it's when you're establishing the connection as the user. There, you were sending the message. In GetUserId, the value returned is the email now, right? (if you put a breakpoint and check when you establish the connection.)
PontiacGTX
PontiacGTXOP3y ago
i mean it does only when I login
Yawnder
Yawnder3y ago
Of course
PontiacGTX
PontiacGTXOP3y ago
i have a cascade parameter on my nav and on my body fragment but wheni click to send the message it just doesnt moves onto GetUserId
Yawnder
Yawnder3y ago
Wait, you're losing me. What are you talking about now? No, it's ok. It's when the SignalR connection is established only.
PontiacGTX
PontiacGTXOP3y ago
I am talking about triggering the SendMessage method oh well so where do i check that the user is within the context it isnt in the hub on the server? .
MODiX
MODiX3y ago
Yawnder#7904
In GetUserId, the value returned is the email now, right?
React with ❌ to remove this embed.
PontiacGTX
PontiacGTXOP3y ago
it does
Yawnder
Yawnder3y ago
Great
PontiacGTX
PontiacGTXOP3y ago
but then it doesnt really send the mssage
Yawnder
Yawnder3y ago
Not at that moment no. Now, when you send the message, you send the same email address as recipient, correct?
PontiacGTX
PontiacGTXOP3y ago
yeah who is myself who sends it
Yawnder
Yawnder3y ago
And you still don't receive messages, right?
PontiacGTX
PontiacGTXOP3y ago
PontiacGTX
PontiacGTXOP3y ago
i dont recieve anything i wrote it like this and nothing triggers this
PontiacGTX
PontiacGTXOP3y ago
PontiacGTX
PontiacGTXOP3y ago
this action doesnt trigger this method
Yawnder
Yawnder3y ago
You have a breakpoint in HubOnReceiveMessage... and it doesn't get hit? Ok
PontiacGTX
PontiacGTXOP3y ago
it doesnt
Yawnder
Yawnder3y ago
In your hub, add this override and put a breakpoint in there: public override async Task OnDisconnectedAsync(Exception exception) Also, in SendMessage, can you check the content of Clients and see if you still have some.
PontiacGTX
PontiacGTXOP3y ago
ok
PontiacGTX
PontiacGTXOP3y ago
PontiacGTX
PontiacGTXOP3y ago
PontiacGTX
PontiacGTXOP3y ago
user seems null
Yawnder
Yawnder3y ago
If you send to Clients.All, does it work?
PontiacGTX
PontiacGTXOP3y ago
i will restart again and check that out yes it works so why it isnt binding the user to the email
Yawnder
Yawnder3y ago
Then I don't know. I would have to try it and play around
PontiacGTX
PontiacGTXOP3y ago
can i send you my repository?
Yawnder
Yawnder3y ago
I don't really have the time for that, sorry
PontiacGTX
PontiacGTXOP3y ago
so what can I do to make sure that it beinds the userid to the email
Yawnder
Yawnder3y ago
No idea. As I said, I always worked with the raw UserId. Maybe if you put a breakpoint in SendMessage and you check this.Users to see what's in there.
PontiacGTX
PontiacGTXOP3y ago
this.Clients?
Yawnder
Yawnder3y ago
There is no list of users?
PontiacGTX
PontiacGTXOP3y ago
Users isa method that calls certain users
PontiacGTX
PontiacGTXOP3y ago
PontiacGTX
PontiacGTXOP3y ago
there is a connection but no claims or users
Want results from more Discord servers?
Add your server