簡體   English   中英

WebAPI + OWIN + SignalR + Autofac

[英]WebAPI + OWIN + SignalR + Autofac

幾個星期以來,我一直在努力解決這個問題。

我有一個應用程序,我已配置owin后端與web api和autofac DI與后台handfire工作。 我幾乎關注了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);
    }

我不得不使用不同的容器,因為我將db設置為InstancePerRequest范圍。

我的所有服務都在通知集線器類中解決,沒有問題。 唯一的問題是當我嘗試從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"));
    }
}

這可能與Autofac為您的通話創建新的生命周期顯示有關,但您是否期望繼續使用現有范圍? 也許檢查你的autinstac注冊singleinstance / instanceperlifetimescope只是說,但你有沒有注冊任何靜態類? 它們可以讓你的范圍保持很長時間。

我看到你正在使用多個容器構建器 - 這不是我們在這里做的事情,我們為每個應用程序都有一個“大規模”容器構建器。 我很好奇為什么你這樣做? 為了滿足我的好奇心,您是否可以嘗試使用單個容器構建器並在該單個構建器上注冊所有內容? (雖然看起來這是SignalR和autofac的模式)

文檔說 :“OWIN集成中的常見錯誤是使用GlobalHost。”

看起來你正是這樣做的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM