SignalR не может иметь клиентские методы, которые возвращают значение. Поэтому я пытаюсь создать вспомогательный класс, чтобы сделать это возможным.синхронно вызывать метод клиентской стороны с SignalR
Так это то, что я пытаюсь сделать: со стороны
- сервера: Вызов метода клиента и предоставлять уникальный идентификатор запроса
Client(clientId).GetValue(requestId)
- стороне сервера: Сохранить RequestID и ждать ответа с помощью
ManualResetEvent
- Client сторона: Внутри
void GetValue(Guid requestId)
метод сервера вызововhubProxy.Invoke("GetValueFinished", requestId, 10)
- Сторона сервера: найти метод ожидания по запросуId => установить возвращаемое значение => установить сигнал
- Сторона сервера: метод не дожидается до
ManualResetEvent
и возвращает полученное значение.
Я могу получить его работу к сожалению. Вот мой код:
public static class MethodHandler
{
private static ConcurrentDictionary<Guid, ReturnWaiter> runningMethodWaiters = new ConcurrentDictionary<Guid,ReturnWaiter>();
public static TResult GetValue<TResult>(Action<Guid> requestValue)
{
Guid key = Guid.NewGuid();
ReturnWaiter returnWaiter = new ReturnWaiter(key);
runningMethodWaiters.TryAdd(key, returnWaiter);
requestValue.Invoke(key);
returnWaiter.Signal.WaitOne();
return (TResult)returnWaiter.Value;
}
public static void GetValueResult(Guid key, object value)
{
ReturnWaiter waiter;
if (runningMethodWaiters.TryRemove(key, out waiter))
{
waiter.Value = value;
}
}
}
internal class ReturnWaiter
{
private ManualResetEvent _signal = new ManualResetEvent(false);
public ManualResetEvent Signal { get { return _signal; } }
public Guid Key {get; private set;}
public ReturnWaiter(Guid key)
{
Key = key;
}
private object _value;
public object Value
{
get { return _value; }
set
{
_value = value;
Signal.Set();
}
}
}
Используя этот MethodHandler
класс мне нужно иметь на стороне сервера два метода:
public int GetValue(string clientId)
{
return MethodHandler.GetValue<int>(key => Clients(clientId).Client.GetValue(key));
}
public void GetValueResult(Guid key, object value)
{
MethodHandler.GetValueResult(key, value);
}
реализации на стороне клиента, как это:
// Method registration
_hubProxy.On("GetValue", new Action<Guid>(GetValue));
public void GetValue(Guid requestId)
{
int result = 10;
_hubConnection.Invoke("GetValueResult", requestId, result);
}
ПРОБЛЕМА:
если вызываю сервер сторона GetValue("clientid")
. Клиентский метод не будет вызываться. Если я прокомментирую returnWaiter.Signal.WaitOne();
, вызывается клиентская сторона GetValue
и вызывается серверная сторона GetValueResult
. Но, конечно, на этот раз метод уже вернулся.
Я думал, что имеет отношение к ManualResetEvent
, но даже с использованием while(!returnWaiter.HasValue) Thread.Sleep(100);
эта проблема не будет устранена.
Любые идеи по устранению этой проблемы?
Заранее благодарен!
Благодаря объяснить вашу озабоченность. Мне не нужно масштабировать до нескольких серверов, но все же производительность должна быть очень хорошей. – hwcverwe
Я изменил метод MethodHandler :: Retrieve' на 'MethodHandler :: GetValue' ;-) – hwcverwe