使用GlobalHost.ConnectionManager.GetHubContext从外部集线器调用SignalR的客户端方法不起作用。但是从集线器内部呼叫确实如此

时间:2013-12-13 07:24:05

标签: c# asp.net-web-api controller action signalr-hub

我正在尝试从.net Web API控制器操作中调用客户端方法。

我可以这样做吗?

我能找到的唯一一个接近我要做的就是这个:

SignalR + posting a message to a Hub via an action method

在那里使用GlobalHost.ConnectionManager.GetHubContext从asp.net MVC控制器动作中发送消息。

当我在我的Web API操作中尝试时,不会抛出任何错误,但是从不在客户端调用方法“methodInJavascript”。

    Public ActionResult MyControllerMethod()
    {
        var context = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
        context.Clients.All.methodInJavascript("hello world");
        // or
        context.Clients.Group("groupname").methodInJavascript("hello world");
    }

当我在该动作中设置断点时,我看到正在到达并执行代码。但是在javascript客户端没有任何事情发生。

为什么呢? Web API是如此不同,以至于这不起作用?还有其他人尝试过并取得了成功吗?

当我从我的中心“内部”调用“methodInJavascript”时,它完美无缺。从.net Web API控制器操作中调用时无法正常工作。

更新

在研究这个问题后,我没有解决方案。我只能假设像Server to client messages not going through with SignalR in ASP.NET MVC 4calling SignalR hub from WebAPI controller issues之类的例子中缺少某些东西,例如可能有一个额外的配置步骤来启用从HubContext或其他东西调用。我最初在这里发布的代码就像那些示例中出现的代码没有被证明有任何缺陷。任何人都可以看到代码中的缺陷吗?从html调用工作。我在我的应用程序中广泛使用它,从未遇到过问题。我从未在API控制器工作中看到来自HubContext的调用。没有错误。对客户端没有任何结果。

已解决(种类):

上面的代码确实可以正常工作发布时。但是,通过localhost在Visual Studio开发环境中不起作用。客户端没有错误但没有结果。将代码原样发布到Web上的真实服务器确实有效。我从没想过会有什么不同所以我从未尝试过。如果它在本地不起作用,则无法发布。它现在正在运行,但我想知道为什么它在开发环境中不能通过localhost工作。无法使用断点等进行本地测试。

我感觉这是信号器虚拟目录。在本地运行和发布时有些不同。不知道什么,但我看到很多帖子,如http://www.bitwisejourneys.com/signalr-hosting-in-iis-a-nasty-gotcha/。现在阅读,看看是否有办法让它在本地和发布。

2 个答案:

答案 0 :(得分:26)

我几天前遇到同样的问题。花了我2天的时间才找到解决方案并解决它。经过一番认真的调查后,问题的根本原因是我自定义的信号依赖解析器。

最后我找到了this link,这就是这样说的:

  

替换DependencyResolver

     

您可以更改DependencyResolver以使用您的DI容器   通过设置GlobalHost.DependencyResolver进行选择。

     

注意:请勿覆盖PreApplicationStart中的全局解析器   不起作用,或者它有时只能起作用。做它   PostApplicationStart(使用WebActivator)或Global.asax。

这里的重要地方是NOTE。当然,在signalr 2.0之后,这个文档变得已弃用。所以我在这里混合了一些新的SignalR API。在不再使用WebActivatorEx的新SignalR API中。 OwinStartup首选而不是WebActivator。

[assembly: OwinStartupAttribute(typeof(YourNamespace.Startup))]
namespace YourNamespace
{
    public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            //IoC container registration process
            UnityConfig.RegisterComponents();

            UnityConfig.Container.RegisterType<AHub, AHub>();

            HubConfiguration config = new HubConfiguration();
            config.EnableJavaScriptProxies = true;


            //You should remove your dependency resolver code from here to Global.asax Application_Start method. Before setting the MVC properties.
            //config.Resolver = new SignalrDefaultDependencyResolver(UnityConfig.Container); // your dependency resolver
            //


            app.MapSignalR(config);
        }
    }
}

在你的global.asax

namespace YourNamespace
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            //Here your SignalR dependency resolver
            GlobalHost.DependencyResolver = new SignalrDefaultDependencyResolver(UnityConfig.Container);


            //other settings goes on
            AreaRegistration.RegisterAllAreas();
            GlobalConfiguration.Configure(WebApiConfig.Register);

            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }
    }
}

我不想在这里发送所有代码,以显示真正的问题。

所以对我来说,现在一切正常。依赖注入也有效。但不好的地方到处都是我搜索过David Fowler说的“它的设计”。我开始认为这个设计确实是必要的或错误的。

希望能帮助其他人为同样的问题进行研究。

答案 1 :(得分:2)

我遇到了同样的问题,它与IoC有关(无论是ninject还是城堡)。 如果将全局依赖关系解析器设置为IoC管理器,它还将替换SignalR内部管道解析。这使您的SingleTon客户端集线器无法正常工作。

我只是将服务器中心设为IoC-ed而解决了这个问题 下面的代码需要SignalHubActivator(您可以在互联网上找到它)

现在,GlobalHost.ConnectionManager.GetHubContext将返回单个实例,并且将再次正确调用客户端方法!

 //configuration.Resolver = signalrDependency ; dont, this will cause GlobalHost.ConnectionManager to be intercepted by Castle


 configuration.Resolver.Register(typeof(IHubActivator),
                                      () => new SignalHubActivator(container));