SignalR, вызывающий клиентский метод из внешнего хаба с использованием GlobalHost.ConnectionManager.GetHubContext, не работает. Но звонки из хаба

Я пытаюсь вызвать клиентский метод из действия контроллера веб-API .net.

Я могу это сделать?

Единственный пост, который мне удалось найти, который близок к тому, что я хочу сделать, это этот:

SignalR + отправка сообщения на Хаб через метод действия

Там сообщение отправляется из действия контроллера asp.net MVC с использованием GlobalHost.ConnectionManager.GetHubContext.

Когда я пытаюсь сделать это внутри своего действия веб-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 ничего не происходит.

Почему? Неужели веб-API настолько отличается, что это не сработает? Кто-нибудь еще пробовал это и имел успех?

Когда я вызываю "methodInJavascript" из "нутри "моего хаба, он работает отлично. Просто не будет работать при вызове из действия контроллера веб-API .net.

ОБНОВЛЕНИЕ:

После исследования этой проблемы у меня нет решения. Могу только предположить, что в таких примерах чего-то не хватает Сообщения от сервера к клиенту не проходят через SignalR в ASP.NET MVC 4, и это проблемы с вызовом концентратора SignalR из контроллера WebAPI, например, может быть, есть дополнительный шаг настройки для включения вызова из HubContext или чего-то еще. Код, который я изначально разместил здесь, похож на тот, который появляется в этих примерах, и не был продемонстрирован каким-либо образом дефектный. Кто-нибудь может увидеть изъян в коде? Звонок из html работает. Я часто делаю это в своих приложениях и никогда не сталкиваюсь с проблемами. Я никогда не видел вызова из HubContext в работе контроллера API. Ошибок нет. Просто никаких результатов по клиенту.

РЕШЕНО (вроде):

Приведенный выше код действительно работает как при публикации. Однако не работает в среде разработки Visual Studio через localhost. На стороне клиента ошибок нет, но нет результата. Публикация кода на реальном сервере в Интернете действительно работает. Я никогда не думал, что будет разница, поэтому никогда не пробовал. Прикинул, что если он не работает локально, он не будет работать в опубликованном виде. Сейчас он работает вживую, но мне интересно, почему он не работает через localhost в среде разработки. Невозможно протестировать локально с помощью точек останова и т. Д.

Такое ощущение, что это виртуальный каталог сигнального устройства. Что-то другое при локальном запуске и опубликованном. Не знаю, что, но я вижу много сообщений вроде http://www.bitwisejourneys.com/signalr-hosting-in-iis-a-nasty-gotcha/. Читаю сейчас, чтобы узнать, есть ли способ заставить его работать как локально, так и опубликовать.


person Robert    schedule 13.12.2013    source источник
comment
Я действительно этого совсем не понимаю. Документацию вижу. Я вижу фрагменты кода во многих местах. Они все выглядят одинаково. Кто-нибудь на самом деле это сделал? Кто-нибудь действительно видел, как это работает?   -  person Robert    schedule 16.12.2013
comment
да, я сделал это, это тоже не работает для меня. Я веду себя так же, как OP   -  person godseyeview    schedule 10.06.2014
comment
Вы когда-нибудь разбирались в этом?   -  person jonho    schedule 11.10.2014
comment
@ Роберт, твоя заметка о ВД решила эту проблему для меня. Я заметил, что мои страницы, которые ссылаются на / signalr / hubs, получают localhost: 1234 / signalr / hubs, а сгенерированный контент инициализирует путь к / signalr вместо / MyWeb / signalr. НО, когда я ввожу localhost: 1234 / MyWeb / signalr / hubs - URL-адрес подключения сгенерированного контента - / MyWeb / signalr. Когда вы используете виртуальные диски в IISExpress, он создает два веб-сайта - один в / и один в / MyWeb, поэтому кажется, что сигнализатор работает, но, я думаю, вы получаете два разных концентратора. Убедитесь, что сгенерированный файл / signalr / hub включает VD в URL-адрес подключения.   -  person THX-1138    schedule 11.11.2014
comment
Я столкнулся с той же проблемой. После публикации работает нормально.   -  person Derek Long    schedule 26.07.2021


Ответы (2)


Пару дней назад я столкнулся с такой же проблемой. Это заняло у меня 2 дня, чтобы найти решение и разрешить его. После серьезного исследования основной причиной проблемы стал преобразователь зависимостей сигнального устройства, который я установил индивидуально.

В конце я нашел эту ссылку, в которой говорилось следующее:

Замена DependencyResolver

Вы можете изменить DependencyResolver для использования выбранного контейнера DI, установив GlobalHost.DependencyResolver.

ПРИМЕЧАНИЕ. НЕ переопределяйте глобальный преобразователь в PreApplicationStart, он не будет работать или будет работать только иногда. Сделайте это в PostApplicationStart (с помощью WebActivator) или в Global.asax.

Важное место здесь ПРИМЕЧАНИЕ. Конечно, после signalr 2.0 эта документация становится устаревшей. Поэтому я смешал кое-что из этого с новым API SignalR. В новом SignalR API больше не используется WebActivatorEx. 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);
        }
    }
}

Я не хочу отправлять сюда весь код, чтобы показать настоящую проблему.

Так что у меня пока все работает нормально. Также работает внедрение зависимостей. Но плохо то, что везде, где я искал, Дэвид Фаулер говорил: «Это по замыслу». Я начал думать, действительно ли этот дизайн необходим или ошибочен.

Надеюсь, это поможет кому-то другому, кто исследует ту же проблему.

person Yusuf Uzun    schedule 14.12.2013
comment
Я ценю твой ответ. Однако я этого не понимаю. Зачем мне заменять DependencyResolver. Документация по вызову клиентских методов извне хаба (asp.net/signalr/overview/signalr-20/hubs-api/) ничего об этом не говорит. Ни в одном из приведенных выше примеров об этом также не упоминается. Мой код выше мне кажется правильным. Вы видите что-то неправильное с этим? - person Robert; 16.12.2013
comment
Хорошо, мой ответ заключался в предположении, что вы использовали инъекцию зависимостей. Прежде чем ответить здесь, я проверил ваши примеры ссылок, и в вашей второй ссылке OP говорил о разрешении зависимостей. Пожалуйста, поправьте меня, если вы не используете преобразователь зависимостей. А еще здесь есть еще одна вещь. Ссылка, которую вы дали мне в комментарии выше, также использует преобразователь зависимостей. Также StockTickerHub является экземпляром singleton. Так что он всегда возвращает вам одно и то же. Но в нашем случае преобразователь зависимостей дает разные экземпляры. Если хотите, я могу дополнить свой ответ еще кодом. - person Yusuf Uzun; 16.12.2013
comment
@Robert, пожалуйста, проверьте эту ссылку, есть пример решения без DLL зависимостей nuget - person Yusuf Uzun; 17.12.2013
comment
Я сейчас смотрю на эту ссылку. Я также переформулировал свой вопрос выше, чтобы внести ясность. - person Robert; 17.12.2013
comment
Хммм ... Ваш образец решения похож на мой. По сути, мы поступаем так же. Контроллер такой же. Клиентская сторона js такая же. Я просто не получаю сообщения на стороне клиента. Должно быть что-то фундаментальное, чего я не понимаю в хабах. У меня сложилось впечатление, что был только один экземпляр. Поэтому, если я попрошу контекст концентратора, он будет относиться к одному экземпляру концентратора, на котором работает мое приложение. Неужели экземпляров больше одного? Создает ли прокси-сервер новый экземпляр моего хаба, оставляя мой клиентский javascript разговаривать с каким-то другим, предыдущим экземпляром? - person Robert; 17.12.2013
comment
AFAIK hubcontext всегда должен содержать одни и те же данные везде. Когда я писал ответ, я предполагал, что вы используете инъекцию зависимостей. Все предыдущие комментарии были в этом контексте. Предлагаю вам сравнить пример решения с вашим. Другой способ - создать черновик решения и написать то же самое. Я считаю, что таким образом вы сможете лучше понять, что не так. - person Yusuf Uzun; 17.12.2013
comment
После исследования этой проблемы у меня нет решения. Могу только предположить, что в таких примерах чего-то не хватает stackoverflow.com/questions/13648605/ и это stackoverflow.com/questions/16695975/ (возможно, отсутствует дополнительная конфигурация шаги что ли?). Код, который я изначально разместил здесь, похож на тот, что в этих примерах не был продемонстрирован каким-либо образом без изъянов. Кто-нибудь может увидеть изъян в коде? Звонок из html работает. От контроллера API нет - person Robert; 09.07.2014
comment
Эта проблема пинала меня хвостом что-то свирепое! Перемещение DependencyResolver в событие Application_Start тоже решило мою проблему. Спасибо!!! - person Swisher Sweet; 21.02.2015
comment
Я потратил часы на отладку этой проблемы, это дурацкое решение решило мои проблемы. Спасибо. - person keithl8041; 02.11.2016
comment
Спасибо за ваш пост! Это обязательно нужно отметить как ответ! Да, если вы используете SignalR и у вас есть собственный контейнер DI (например, Unity), И вы используете GlobalHost, вы должны установить GlobalHost.DependencyResolver = new MyResolver... в Application_Start, а НЕ в HubConfiguration в app.MapSignalR В противном случае контекст, возвращаемый GlobalHost.ConnectionManager.GetHubContext, не будет обрабатывать какие-либо сообщения или может вызывать «Использование экземпляра Hub, созданного не HubPipeline, не поддерживается». когда вы пытаетесь выполнить Client.All или любую другую функцию отправки. - person Serge Ageyev; 21.05.2019

У меня была такая же проблема, и она связана с IoC (с чем угодно, например, Ninject или Castle). Если вы установите глобальный преобразователь зависимостей для своего диспетчера IoC, он также заменит разрешение внутреннего конвейера SignalR. Это приводит к тому, что ваш клиентский хаб SingleTon не работает должным образом.

Я решил это, имея только IoC-серверные концентраторы. Для приведенного ниже кода требуется 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));
person Egbert Nierop    schedule 16.06.2017