WebAPI + OWIN + SignalR + Autofac

时间:2018-09-04 08:38:28

标签: c# signalr autofac signalr-hub hangfire

我已经在这个问题上苦苦挣扎了好几个星期了。

我有一个应用程序,其中我使用Web api和autofac DI配置了后台后端工作,从而在owin后端进行了配置。我几乎已经在Stackoveflow上查看了与此相关的每个问题,但似乎没有任何效果。 我有关OWIN / Hangfire / WebAPI的应用似乎都可以正常运行。直到涉及SignalR推送消息为止。

如果我从js客户端推送消息中调用了任何通知中心端点,则可以,并且我可以在任何其他连接的客户端上接收推送消息。但是,当我要从我的api控制器或hangfire作业发送消息时,它永远不会到达任何客户端。

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范围。

我的所有服务都在通知中心类中解决,那里没有问题。唯一的问题是,当我尝试使用Hangout上下文从hangfire服务甚至从api控制器发送消息时,它永远不会到达任何客户端。

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"));
    }
}

1 个答案:

答案 0 :(得分:0)

这与Autofac为您的呼叫创建新的Lifetimescope有关,但是您希望继续使用现有范围吗?也许检查您的autofac注册以获取单实例/ instanceperlifetimescope 只是说,但是您是否注册了任何静态类?它们会使您的示波器存活太久。

我看到您正在使用多个containerbuilder-这不是我们要做的,每个应用程序都有一个“大型” containerbuilder。我很好奇你为什么要这么做?为了满足我的好奇心,您可以尝试使用一个容器构建器并在该构建器上注册所有内容吗? (尽管看起来这是SignalR和autofac的模式)

The documentation says:“ OWIN集成中的一个常见错误是使用GlobalHost。”

您似乎正是在这样做。