I am trying to use the new User Id provider specified in signalr 2 to send messages to a specific user. When I call the Clients.All method, I see this working as my javascript code gets called from the server and the ui produces some expected text for my test case. However, when I switch to Clients.User the client side code is never called from the server. I followed the code outlined in this example: SignalR - Sending a message to a specific user using (IUserIdProvider) *NEW 2.0.0*.
NotificationHub.cs:
public class NotificationHub : Hub
{
[Authorize]
public void NotifyUser(string userId, int message)
{
Clients.User(userId).DispatchMessage(message);
}
public override Task OnConnected()
{
return base.OnConnected();
}
public override Task OnDisconnected(bool stopCalled)
{
return base.OnDisconnected(stopCalled);
}
public override Task OnReconnected()
{
return base.OnReconnected();
}
}
IUserIdProvider.cs:
public class UserIdProvider : IUserIdProvider
{
MemberService _memberService;
public UserIdProvider()
{
}
public string GetUserId(IRequest request)
{
long UserId = 0;
if (request.User != null && request.User.Identity != null &&
request.User.Identity.Name != null)
{
var currenUser = Task.Run(() => _memberService.FindByUserName(request.User.Identity.Name)).Result;
UserId = currenUser.UserId;
}
return UserId.ToString();
}
}
Startup.cs
HttpConfiguration config = GlobalConfiguration.Configuration;
config.Routes.MapHttpRoute(
"Default2",
"api/{controller}/{action}/{id}",
new { id = RouteParameter.Optional });
config.Routes.MapHttpRoute(
"DefaultApi2",
"api/{controller}/{id}",
new { id = RouteParameter.Optional });
app.Map("/signalr", map =>
{
map.UseCors(CorsOptions.AllowAll);
var idProvider = new UserIdProvider();
GlobalHost.DependencyResolver.Register(typeof(IUserIdProvider), () => idProvider);
map.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()
{
Provider = new QueryStringOAuthBearerAuthenticationProvider()
});
var hubConfiguration = new HubConfiguration
{
};
map.RunSignalR(hubConfiguration);
});
app.MapSignalR();
QuerstringOAuthBearerAuthenticationProvider:
public class QueryStringOAuthBearerAuthenticationProvider
: OAuthBearerAuthenticationProvider
{
public override Task RequestToken(OAuthRequestTokenContext context)
{
if (context == null) throw new ArgumentNullException("context");
// try to find bearer token in a cookie
// (by default OAuthBearerAuthenticationHandler
// only checks Authorization header)
var tokenCookie = context.OwinContext.Request.Cookies["BearerToken"];
if (!string.IsNullOrEmpty(tokenCookie))
context.Token = tokenCookie;
return Task.FromResult<object>(null);
}
}
Do I need to map the user to the connections myself using the IUserIdProvider through the OnConnected, OnDisconnected, etc. or does this happen automatically behind the scenes? Is there someone wrong in my posted code that could be a problem as well? I am running signalr from the same environment as my web api rest services, don't know if this makes a difference and using the default bearer token setup web api is using.