我已经苦苦挣扎了几周,这个问题让我很困惑。
我的应用程序配置了OWIN后端、Web API和Autofac DI背景下的Handfire Jobs。我已经查看了Stackoveflow上关于这个问题的所有问题,但是似乎没有什么作用。
我的应用程序关于OWIN/Hangfire/WebAPI都运行得很好。直到涉及到SignalR推送消息。
如果我从js客户端调用任何通知中心终点,推送消息就可以正常工作,并且我可以在任何其他连接的客户端上接收推送消息。但是当我想从我的api控制器或hangfire job发送消息时,它永远不会到达任何客户端。
Startup.cs
public void Configuration(IAppBuilder app)
{
//var signalRHelper = new SignalRHelper(GlobalHost.ConnectionManager.GetHubContext<NotificationHub>());
var constants = new Constants();
constants.Set(ConstantTypes.AllyHrNoReplyEmailAddress, Util.Constants.AllyHrNoReplyEmailAddress);
constants.Set(ConstantTypes.SendGridKey, Util.Constants.SendGridKey);
constants.Set(ConstantTypes.EncryptionKey, Util.Constants.EncryptionKey);
constants.Set(ConstantTypes.ApiUrl, Util.Constants.ApiUrl);
constants.Set(ConstantTypes.RootFolder, Util.Constants.RootFolder);
constants.Set(ConstantTypes.FrontEndUrl, Util.Constants.FrontEndUrl);
GlobalConfiguration.Configuration
.UseSqlServerStorage("AllyHrDb");
var config = System.Web.Http.GlobalConfiguration.Configuration;
var builder = new ContainerBuilder();
var jobBuilder = new ContainerBuilder();
var signalRBuilder = new ContainerBuilder();
var hubConfig = new HubConfiguration();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly()).PropertiesAutowired();
builder.Register(x => constants);
builder.RegisterModule(new ServiceModule());
jobBuilder.Register(x => constants);
jobBuilder.RegisterModule(new HangfireServiceModule());
signalRBuilder.RegisterModule(new SignalRServiceModule());
signalRBuilder.Register(x => constants);
signalRBuilder.RegisterType<AutofacDependencyResolver>().As<IDependencyResolver>().SingleInstance();
signalRBuilder.RegisterType<ConnectionManager>().As<IConnectionManager>().ExternallyOwned().SingleInstance();
signalRBuilder.RegisterType<NotificationHub>().ExternallyOwned().SingleInstance();
signalRBuilder.RegisterType<SignalRHelper>().PropertiesAutowired().ExternallyOwned().SingleInstance();
signalRBuilder.Register(context => context.Resolve<IDependencyResolver>().Resolve<IConnectionManager>().GetHubContext<NotificationHub, INotificationHub>()).ExternallyOwned().SingleInstance();
var hubContainer = signalRBuilder.Build();
builder.RegisterInstance(hubContainer.Resolve<IConnectionManager>());
builder.RegisterInstance(hubContainer.Resolve<IHubContext<INotificationHub>>());
builder.RegisterInstance(hubContainer.Resolve<NotificationHub>());
builder.RegisterInstance(hubContainer.Resolve<SignalRHelper>());
jobBuilder.RegisterInstance(hubContainer.Resolve<IHubContext<INotificationHub>>());
jobBuilder.RegisterInstance(hubContainer.Resolve<NotificationHub>());
jobBuilder.RegisterInstance(hubContainer.Resolve<SignalRHelper>());
var container = builder.Build();
var jobContainer = jobBuilder.Build();
var idProvider = new SignalRCustomUserIdProvider();
hubConfig.Resolver = new AutofacDependencyResolver(hubContainer);
hubConfig.Resolver.Register(typeof(IUserIdProvider), () => idProvider);
app.Map("/signalr", map =>
{
map.UseCors(CorsOptions.AllowAll);
map.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()
{
Provider = new QueryStringOAuthBearerProvider()
});
map.RunSignalR(hubConfig);
});
GlobalConfiguration.Configuration.UseAutofacActivator(jobContainer);
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(config);
app.UseHangfireServer();
app.UseHangfireDashboard();
ConfigureAuth(app);
app.UseWebApi(config);
}
因为我的数据库设置了InstancePerRequest作用域,所以我必须使用不同的容器。
所有我的服务都在通知中心类中进行解析,没有任何问题。唯一的问题是,当我尝试通过Hangfire服务或甚至从API控制器使用hub上下文发送消息时,它从未到达任何客户端。
NotificationHub.cs
public interface INotificationHub
{
/// <summary>
///
/// </summary>
void pushNotification(string message);
/// <summary>
///
/// </summary>
/// <param name="model"></param>
void getNotification(object model);
void getMessage(object model);
}
/// <summary>
/// Notification Hub
/// </summary>
[HubName("NotificationHub")]
[Authorize]
public class NotificationHub : Hub<INotificationHub>
{
/// <summary>
///
/// </summary>
public static IHubContext<INotificationHub> GlobalContext { get; private set; }
private readonly IChatMessagingService _chatMessagingService;
private readonly IUserService _userService;
private Guid LoggedInUserId
{
get
{
var claims = ((ClaimsIdentity)Context.User.Identity).Claims.ToArray();
var userIdClaim = claims.FirstOrDefault(x => x.Type.Equals("UserId"));
if (userIdClaim == null) return Guid.Empty;
return Guid.Parse(userIdClaim.Value);
}
}
/// <summary>
/// Consructor
/// </summary>
/// <param name="lifetimeScope"></param>
/// <param name="context"></param>
public NotificationHub(ILifetimeScope lifetimeScope, IHubContext<INotificationHub> context)
{
GlobalContext = context;
try
{
var childScope = lifetimeScope.BeginLifetimeScope();
_chatMessagingService = childScope.Resolve<IChatMessagingService>();
_userService = childScope.Resolve<IUserService>();
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
/// <summary>
/// Notifications
/// </summary>
public void Notifications()
{
Clients.All.pushNotification("AllyHr" + LoggedInUserId);
}
/// <summary>
/// Send Message
/// </summary>
/// <param name="model"></param>
public void SendMessage(SendChatMessageBindingModel model)
{
var chatMessage = _chatMessagingService.SendMessageToGroup(LoggedInUserId, model.GroupId, model.Message);
var recipientIds = _chatMessagingService.GetChatMembersByGroupId(LoggedInUserId, model.GroupId);
var stringUserIds = new List<string>();
var chatGroup = _chatMessagingService.GetChatGroupById(model.GroupId);
foreach (var recipientId in recipientIds)
{
stringUserIds.Add(recipientId.ToString());
}
Clients.Users(stringUserIds).getNotification(new
{
message = "A new Message is Recieved in Chat Group: " + chatGroup.Name,
groupId = chatGroup.Id
});
var chatMessageVm = chatMessage.Map<ChatMessage, ChatMessageViewModel>();
chatMessageVm.Sender = _userService.Get(chatMessageVm.SenderId).Map<User, UserViewModel>();
stringUserIds.Add(LoggedInUserId.ToString());
Clients.Users(stringUserIds).getMessage(chatMessageVm);
}
}
signalRhelper.cs用于从API或Hangfire服务中调用
public class SignalRHelper
{
public IConnectionManager ConnectionManager { get; set; }
public IHubContext<INotificationHub> HubContext { get; set; }
/// <summary>
/// Send Notifications to Users
/// </summary>
/// <param name="message"></param>
/// <param name="userIds"></param>
public void GetNotification(object message, IList<string> userIds)
{
HubContext.Clients.Users(userIds).getNotification(message);
}
/// <summary>
/// Get LoggedInUser Id for SignalR
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
public static Guid GetLoggedInUserId(IPrincipal user)
{
var claim = GetLoggedinUserClaim(user);
if (claim == null) return Guid.Empty;
return Guid.Parse(claim.Value);
}
private static Claim GetLoggedinUserClaim(IPrincipal user)
{
var claim = ((ClaimsIdentity)user.Identity).Claims.ToArray();
return claim.FirstOrDefault(x => x.Type.Equals("UserId"));
}
}
SignalRHelper
中的所有调用都没有被客户端接收到。虽然看起来不是这种情况,但我猜测您在SignalRHelper
类中收到了一个新的HubContext
实例。 - Stefan