После долгих усилий и не найдя прямого пути, я нашел способ, как показано ниже, для кого-то другого в будущем, это может помочь.
Сценарий: 1. Веб-ферма: Хост, внешний пользователь, обращенный к веб-страницам. 2. Бэкенд-процесс: сочетание WebApi, SharePoint, службы Windows и т. д.
Пользователь с веб-страницы отправляет запрос и получает уникальный идентификатор в качестве возврата. Внутренне при получении запроса мы помещаем этот запрос в очередь на служебную шину, используя TopicClient для обработки.
Существует пул служб Windows, отслеживающих сообщение на служебной шине с помощью SubscriptionClient и обрабатывающих это сообщение. По завершению процесс может длиться от 5 секунд до 30 секунд, а в некоторых случаях и больше. Нам нужно сообщить клиенту, что его работа выполнена, если он ожидает на веб-странице или ждет уведомления о завершении.
В этой истории мы используем SignalR для отправки клиенту уведомления о завершении задания.
Теперь моя предыдущая проблема заключается в том, как я сообщаю из службы Windows веб-приложению, что задание выполнено, поэтому отправьте уведомление клиенту, который отправил запрос.
Один из способов заключается в том, что мы разместили другой концентратор внутри веб-приложения, служба Windows действует как клиент и вызывает концентратор, размещенный в веб-приложении, и в этом методе концентратора он вызывает метод внешнего концентратора для распространения сообщения конкретному клиенту, который отправил запрос, для которого мы с использованием группы одного пользователя.
И поскольку мы зарегистрировали служебную шину как объединительную плату, она будет распространяться на другие серверы, а затем соответствующий клиент получит уведомление. Так что это идеальное решение и должно работать в большинстве случаев.
В приведенном выше подходе у нас есть одно ограничение, связанное с тем, как служба Windows подключается к веб-клиенту, поскольку у нас нет аутентификации Windows, но у нас есть аутентификация на основе openid с ADFS. Теперь в таком случае веб-приложению требуется специальный код, в котором предоставляется отдельный идентификатор пользователя или пароль для службы Windows для связи или аутентификация Windows также разрешена для этого концентратора для служебной учетной записи службы Windows.
Я пытался и пытался, как убрать все эти надежды между межсерверным общением и опять же управлением дополнительной безопасностью.
Так я сделал ниже с простотой, хотя мне понадобилась целая ночь, чтобы найти нашу внутреннюю часть SignalR. Но это работает:
Подход заключается в отправке сообщения непосредственно на объединительную плату ServiceBus, и, поскольку все веб-серверы уже подключены к объединительной плате ServiceBus, они получат сообщение.
К сожалению, SignalR не предоставляет такого механизма для отправки сообщения непосредственно на объединительную плату. Я думаю, что это модель pub/sub, поэтому они не хотят, чтобы кто-то взломал их систему :). или нарушение их шаблона, но в моем случае это имеет смысл из-за разных ролей и безопасности, я упростил код, как показано ниже:
- Создайте экземпляр ServiceBusMessageBus в моем коде так же, как показано ниже: хотя я создал отдельный экземпляр и храню его до конца жизни службы Windows, поэтому я не создаю экземпляр каждый раз:
ServiceBusMessageBus serviceBusBackplane = new ServiceBusMessageBus (новый DefaultDependencyResolver(), new ServiceBusScaleoutConfiguration (connectionString, appName));
Создайте объект ClientHubInvocation: это сообщение, которое фактически создается в инфраструктуре SignalR при широковещательном сообщении на основе объединительной платы:
ClientHubInvocation hubData = new ClientHubInvocation
{
Args = new object[] { msg },
Hub = "JobStatusHub",
Method = "onJobStatus",
State = null,
};
Создайте объект Message, который принимает ServiceBusMessageBus.Publish. Да, так что это метод, который фактически вызывается в базовом классе ScaleoutMessageBus.Publish. Этот класс фактически отвечает за отправку сообщения в тему и другим подписчикам на других узлах сервера. Почему бы не использовать это напрямую. Теперь, чтобы создать объект сообщения, вам понадобится следующий код:
Сообщение backplaneMessage = новое сообщение (sourceId, "hg-JobStatusHub." + имя, новый ArraySegment (Encoding.UTF8.GetBytes (JsonConvert.SerializeObject (hubData)))));
В приведенном выше втором параметре есть что-то интересное. В случае, если вы хотите опубликовать для всех клиентов, тогда синтаксис «h-», в моем случае для конкретного пользователя группы, поэтому синтаксис «hg-.. Вы можете проверить код здесь: https://github.com/SignalR/SignalR/blob/bc9412bcab0f5ef097c7dc919e3ea1b37fc8718c/src/Microsoft.AspNet.SignalR.Core/Infrastructure/PrefixHelper.cs
- Опубликуйте свое сообщение непосредственно на объединительной плате, как показано ниже:
await serviceBusBackplane.Publish(backplaneMessage);
Я бы хотел, чтобы этот класс PrefixHelper был общедоступным.
Помните: это не рекомендуется и не изолирует от будущих обновлений для SignalR, так как они могут измениться внутри, поэтому любое обновление может сопровождаться небольшим затруднением для изменения этого кода. Но в целом это работает. Команда Hope SignalR предоставляет некоторый готовый механизм для отправки сообщения непосредственно на объединительную плату.
Спасибо
person
Shrenik Jhaveri
schedule
09.07.2014