Signalr вызывает конкретного клиента из-за пределов хаба

Мне известно о проекте Криса Фулстоу log4net.signalr. Это отличная идея, если вы хотите непроизводственный журнал, так как он регистрирует все сообщения из всех запросов. Я хотел бы иметь что-то, что различает сообщения журнала по запросу, который их создает, и отправляет обратно в соответствующий браузер.

Вот что я сделал в приложении:

 public class SignalRHubAppender:AppenderSkeleton
    {
        protected override void Append(log4net.Core.LoggingEvent loggingEvent)
        {
            if (HttpContext.Current != null)
            {
                var cookie = HttpContext.Current.Request.Cookies["log-id"];
                if (null != cookie)
                {
                    var formattedEvent = RenderLoggingEvent(loggingEvent);
                    var context = GlobalHost.ConnectionManager.GetHubContext<Log4NetHub>();
                    context.Clients[cookie.Value].onLog(new { Message = formattedEvent, Event = loggingEvent });
                }
            }
        }
    }

Я пытаюсь прикрепить идентификатор сеанса к файлу cookie, но это не работает на том же компьютере, поскольку файл cookie перезаписывается. вот код, который я использую на клиенте, чтобы прикрепить событие:

//start hubs
    $.connection.hub.start()
    .done(function () {
        console.log("hub subsystem running...");
        console.log("hub connection id=" + $.connection.hub.id);
        $.cookie("log-id", $.connection.hub.id);
        log4netHub.listen();
    });

В результате сообщения журнала отображаются только на последней подключенной странице. Я хотел бы знать, есть ли какие-то стратегии для получения текущего идентификатора соединения из браузера, который инициирует текущий запрос, если таковой имеется. Также мне интересно узнать, есть ли лучший дизайн для ведения журнала для каждого браузера.

ИЗМЕНИТЬ

Я мог бы создать файл cookie на основе условного имени (например, log-id-someguid), но мне интересно, есть ли что-то более умное.

BOUNTY Я решил начать вознаграждение за этот вопрос, и я бы дополнительно спросил об архитектуре, чтобы увидеть, имеет ли смысл моя стратегия или нет. Я сомневаюсь, что я использую концентратор в одном «направлении» от сервера к клиенту, и я использую его для регистрации действий, исходящих не от вызовов к концентратору, а от других запросов (потенциально запросы, поднятые на других концентраторах), является что правильный подход, имея в качестве цели браузер видимый аппендер log4net?


person Felice Pollano    schedule 13.09.2012    source источник
comment
Мне никогда не приходилось решать такую ​​проблему, единственный способ, который приходит мне в голову, - это переписать URL-адрес, чтобы каждый экземпляр браузера/вкладки однозначно идентифицировался с помощью URL-адреса или комбинации URL-адреса и файлов cookie.   -  person Wasp    schedule 14.09.2012
comment
@Wasp проблема, приложение является SPA :) Я редактирую вопрос, чтобы предложить дополнительную идею, чтобы посмотреть, имеет ли это смысл.   -  person Felice Pollano    schedule 14.09.2012
comment
Я догадался :) Но все же я думаю, что вы могли бы придумать какое-то умное правило маршрутизации, чтобы иметь своего рода уникальный идентификатор, сгенерированный в URL-адресе и каким-то образом обработанный. Глупая идея, пользователь переходит на foo.com, а вы при первом подключении перенаправляете его на foo.com/n2998fhn239 и сохраните его в своем SPA.   -  person Wasp    schedule 14.09.2012
comment
@Wasp Хорошая идея, я немного боюсь, что архитектура wole неверна. Но другой образец на ту же тему не различает клиентские сеансы.   -  person Felice Pollano    schedule 14.09.2012
comment
Я думаю, что это единственное решение, которое работает с любым (не юрским) браузером. Объединив некоторые сгенерированные файлы cookie и URL-адрес, вы сможете предотвратить захват, и в этот момент SignalR сделает все остальное. Я не могу найти угловые случаи, но, возможно, это только я :)   -  person Wasp    schedule 14.09.2012
comment
Как насчет того, чтобы просто сгенерировать GUID в javascript и установить его в качестве значения файла cookie вместо идентификатора подключения SignalR? Это решило бы проблему, когда только последняя страница получает сообщения (что, очевидно, связано с тем, что SignalR запускает новое соединение на каждой странице и перезаписывает файл cookie). Вместо GUID вы также можете просто использовать идентификатор сеанса ASP.NET. Edit забыл упомянуть, что вам нужно добавить подключение к группе SignalR, идентифицированной значением файла cookie, чтобы это работало.   -  person Alexander Köplinger    schedule 17.09.2012
comment
@akoeplinger, даже если я использую GUID в качестве значения файла cookie, не будет ли файл cookie перезаписан, если я открою другой браузер по тому же URL-адресу?   -  person Felice Pollano    schedule 17.09.2012
comment
Да, но вы можете проверить, установлен ли уже cookie, и ничего не делать в этом случае, или я что-то упускаю в вашем сценарии?   -  person Alexander Köplinger    schedule 18.09.2012
comment
@akoeplinger, если я запущу два экземпляра браузера, оба должны войти в журнал ...   -  person Felice Pollano    schedule 18.09.2012
comment
Вы можете установить дату истечения срока действия файла cookie на дату в далеком будущем, например. 2038. Если вы откроете несколько экземпляров одного и того же браузерного приложения, они будут использовать один и тот же файл cookie, и оба должны получать сообщения (при условии, что вы добавили соединение в группу, идентифицированную значением файла cookie на сервере).   -  person Alexander Köplinger    schedule 18.09.2012
comment
Я предполагаю, что Felice НЕ хочет, чтобы все экземпляры с одним и тем же файлом cookie получали это сообщение, каждый из них должен получать только сообщения, которые каким-то образом связаны с этим конкретным экземпляром. Верно?   -  person Wasp    schedule 18.09.2012


Ответы (1)


Идея о том, как правильно настроить таргетинг на нужный экземпляр/вкладку браузера, даже если несколько вкладок открыты в одном и том же SPA, состоит в том, чтобы различать их с помощью URL-адреса. Один из возможных способов реализовать это — перенаправить их при первом доступе с http://foo.com на http://foo.com/hhd83hd8hd8dh3, каждый раз генерируется случайным образом. Эту перезапись URL-адреса можно было бы выполнить и другими способами, но это всего лишь способ проиллюстрировать проблему. Таким образом, приложение сможет проверить исходный URL-адрес, а из URL-адреса с помощью некоторого сопоставления, которое вы сохраняете на стороне сервера, вы можете определить правильный SignalR ConnectionId. Детали реализации могут различаться, но основная идея такова. Отслеживая дополнительную информацию, доступную в HttpContext с момента первого подключения, вы также можете использовать дополнительные стратегии для предотвращения взлома.

Что касается вашей архитектуры, я могу сказать вам, что именно так я ее использовал в ElmahR. У меня есть сообщения, исходящие из-за пределов концентратора уведомлений (ошибки, отправленные из других веб-приложений), и я делаю широковещательную рассылку всем клиентам, подключенным к этому концентратору (и подписывающимся на определенные группы): все работает нормально.

Я не являюсь авторитетным источником, но я также предполагаю, что такая архитектура приемлема даже с несколькими концентраторами, потому что концентраторы в конце концов являются просто абстракцией над (одним) постоянным соединением, которое позволяет группировать обмен сообщениями по контексты. За кулисами (я упрощаю) у вас есть просто постоянное соединение с сообщениями, идущими туда и обратно, поэтому какую бы структуру концентратора вы ни определили поверх него (которая существует только для того, чтобы помочь вам организовать вещи), вы все равно настаиваете на этом соединении, так что вы не можете причинить никакого вреда.

SignalR хорошо справляется с двумя задачами: массовой трансляцией (клиенты) и общением один на один (вызывающий абонент). Пока вы не пытаетесь делать странные вещи, такие как сохранение серверных ссылок на конкретных вызывающих абонентов, все должно быть в порядке, независимо от количества концентраторов и взаимодействий между ними.

Это мои выводы, сделанные на местах. Может быть, вы можете твитнуть @dfowler об этом вопросе и посмотреть, есть ли у него (гораздо) более авторитетные рекомендации.

person Wasp    schedule 18.09.2012
comment
Я рад слышать, что общая архитектура имеет смысл, но все еще ищу что-то лучшее, чем файлы cookie, чтобы направлять сообщения в правильный источник. - person Felice Pollano; 18.09.2012