我的目标是在数据库中插入/更新以立即通知连接的用户。
我有Hub
。
[Authorize]
public class NotificationsHub : Hub
{
private readonly IWorker _worker;
public NotificationsHub() : this(new WorkerFacade(new ExtremeDataRepository())) { }
public NotificationsHub(IWorker worker)
{
_worker = worker;
}
public override Task OnConnected()
{
if (!HubUsersManager.ConnectedUsers.Any(p => p.Name.Equals(Context.User.Identity.Name)))
{
HubUsersManager.ConnectedUsers.Add(new HubUserHandler
{
Name = Context.User.Identity.Name,
ConnectionId = Context.ConnectionId
});
}
return base.OnConnected();
}
//public override Task OnDisconnected()
//{
// HubUserHandler hubUserHandler =
// HubUsersManager.ConnectedUsers.FirstOrDefault(p => p.Name == Context.User.Identity.Name);
// if (hubUserHandler != null)
// HubUsersManager.ConnectedUsers.Remove(hubUserHandler);
// return base.OnDisconnected();
//}
public async Task<ICollection<NotificationMessage>> GetAllPendingNotifications(string userId)
{
return await _worker.GetAllPendingNotifications(userId);
}
public void UpdateNotificationMessagesToAllClients(ICollection<NotificationMessage> notificationMessages)
{
Clients.All.updateNotificationMessages(notificationMessages);
}
}
正如您所看到的,我从已连接用户的手动映射中删除了OnDisconnected,以使用户名和ConnectionId稍后用于我的Entity Framework MemberShip用户广播消息,因为每次客户端离开时都会调用OnDisconnected集线器,而不是实际断开连接,例如关闭浏览器。
SignalR的初始化工作非常完美,我测试了它,GetAllPendingNotifications
在连接启动时被调用,我调用了SignalR Javascript代码的功能,参见下面的代码。
// A simple templating method for replacing placeholders enclosed in curly braces.
if (!String.prototype.supplant) {
String.prototype.supplant = function (o) {
return this.replace(/{([^{}]*)}/g,
function (a, b) {
var r = o[b];
return typeof r === 'string' || typeof r === 'number' ? r : a;
}
);
};
}
if (typeof String.prototype.endsWith !== 'function') {
String.prototype.endsWith = function(suffix) {
return this.indexOf(suffix, this.length - suffix.length) !== -1;
};
}
$(function () {
// Reference the auto-generated proxy for the hub.
var notificationsHub = $.connection.notificationsHub;
var userName, userId;
// Create a function that the hub can call back to display messages.
notificationsHub.client.updateNotificationMessages = updateNotificationsToPage;
function updateNotificationsToPage(notificationMessages) {
alert('Im in updating notifications');
if (notificationMessages.count > 0) {
$.each(function(index) {
alert($(this).Message);
});
}
};
function init() {
notificationsHub.server.getAllPendingNotifications(userId).done(updateNotificationsToPage);
}
function userDetailsRetrieved(data) {
userName = data.UserName;
userId = data.Id;
// Start the connection.
$.connection.hub.start().done(init);
}
function getUserDetails() {
var baseURL = document.baseURI,
url;
if (!baseURL.endsWith('Home/GetUserDetails')) {
if (baseURL.endsWith('/'))
url = baseURL + 'Home/GetUserDetails';
else if (baseURL.endsWith('/Home') ||
baseURL.endsWith('/Home/'))
url = baseURL + '/GetUserDetails';
else {
url = baseURL + '/Home/GetUserDetails';
}
} else
url = baseURL;
$.ajax({
url: url, success: userDetailsRetrieved, type: 'POST', error: function () {
console.log(arguments);
}, dataType: 'json' });
}
getUserDetails();
});
我知道映射可能不是必需的,我可以覆盖实现以将其映射到我的实际ApplicationUser
GUID ID以避免它,但是现在它似乎服务于目的,可能会改变它,如果我首先让它发挥作用。
如果客户端调用服务器方法,您还可以看到我用来获取某些数据的IWorker
引用。
此外,所有IWorker
正在使用Controllers
具体实现,并且具有属性Clients
,因此我可以立即将消息广播回连接的客户端。
private IHubConnectionContext _clients;
private IHubConnectionContext Clients
{
get {
return _clients ?? (_clients = GlobalHost.ConnectionManager.GetHubContext<NotificationsHub>().Clients);
}
}
哪个填充正确。
在应用程序的某些方面,IWorker
正在调用Clients
属性。
foreach (HubUserHandler hubUserHandler in HubUsersManager.ConnectedUsers)
{
ApplicationUser user = await GetApplicationUserWithName(hubUserHandler.Name);
List<string> userRoles = await GetUserRoles(user);
bool isInRole = userRoles.Any(p => p.Equals("ARole"));
List<NotificationMessage> testList = new List<NotificationMessage>
{
new NotificationMessage {Message = "TEST MESSAGE!"}
};
if (isInRole)
Clients.Client(hubUserHandler.ConnectionId).updateNotificationMessages(testList);
}
我的浏览器没有任何内容,应该弹出两个警报,一个说Im in updating notifications
,一个TEST MESSAGE
,就像您在上面的Javascript
代码中看到的那样。
[编辑]
更改了代码以将邮件发送到特定Group
,但没有任何内容再次出现在我的客户端浏览器中。
public override Task OnConnected()
{
if (_groupManager.Count == 0)
{
ICollection<string> rolesCollection = _worker.GetAllRoles();
foreach (string roleName in rolesCollection)
{
_groupManager.Add(roleName);
}
}
foreach (string groupRole in _groupManager.Groups)
{
if (Context.User.IsInRole(groupRole))
{
Groups.Add(Context.ConnectionId, groupRole);
}
}
return base.OnConnected();
}
我工人阶级的某个地方:
List<NotificationMessage> testList = new List<NotificationMessage>
{
new NotificationMessage {Message = "TEST MESSAGE!"}
};
Clients.Group("TestGroup").updateNotificationMessages(testList);
我想我错过了什么!!!
答案 0 :(得分:2)
我的2美分:你有没看过Clients.User()
方法?它已经为您执行了所有ConnectionId
映射,并且您正在使用Context.User
,因此它应该可以开箱即用。如果您需要更复杂的东西,可以在IUserIdProvider
的自定义实现中编写自己的映射逻辑。至少你会删除一个级别的复杂性(但不确定如果问题不是因为它会解决你的具体问题)。只是一个想法。