0

SignalR은 값을 반환하는 클라이언트 메소드를 가질 수 없습니다. 그래서 이것을 가능하게하는 도우미 클래스를 만들려고 노력하고 있습니다.은 SignalR로 클라이언트 측 메소드를 동 기적으로 호출합니다.

  1. 서버 측 :

    그래서 이것은 내가 뭘하려고 오전입니다 고유의 요청 ID를 클라이언트 메소드를 호출하고 제공 Client(clientId).GetValue(requestId)

  2. 서버 측 : RequestID가를 저장하고 ManualResetEvent
  3. 클라이언트를 사용하여 응답을 기다립니다 쪽 : 내부 void GetValue(Guid requestId) 콜 서버 방식 hubProxy.Invoke("GetValueFinished", requestId, 10)
  4. 서버 쪽 : 요청 대기 방법 찾기 아이디 => 설정 반환 값 => 신호 설정
  5. 서버 쪽 : 더 이상 기다리지 않는 방법 ManualResetEvent 및 검색된 값을 반환합니다.

불행히도 작업 할 수 있습니다. 나는이 방법 서버 측이 필요합니다이 MethodHandler 클래스를 사용

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(); 
     } 
    } 
} 

: 여기 내 코드입니다

// Method registration 
_hubProxy.On("GetValue", new Action<Guid>(GetValue)); 

public void GetValue(Guid requestId) 
{ 
    int result = 10; 
    _hubConnection.Invoke("GetValueResult", requestId, result); 
} 

문제 :

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); 
} 

클라이언트 측 구현이 같다 서버 측 GetValue("clientid")을 호출하면
입니다. 클라이언트 메소드는 호출되지 않습니다. returnWaiter.Signal.WaitOne();을 주석 처리하면 클라이언트 측 GetValue이 호출되고 서버 측 GetValueResult이 호출됩니다. 그러나 이번에도 방법은 이미 돌아왔다.

저는 ManualResetEvent과 관련이 있다고 생각하지만 while(!returnWaiter.HasValue) Thread.Sleep(100);을 사용해도이 문제는 해결되지 않습니다.

이 아이디어를 해결하는 방법에 대한 아이디어가 있으십니까?

미리 감사드립니다.

답변

0

문제 해결 :

문제 만 Hub.OnConnectedHub.OnDisconnected에서 발생. 왜 정확한 설명을 가지고 있지는 않지만, 클라이언트에 대한 메서드 호출을 처리하기 전에 이러한 메서드를 완료 할 수 있어야합니다. 당신의 문제를 설명하기 위해

public override Task OnConnected() 
{ 
    // NOT WORKING 
    Debug.Print(MethodHandler.GetValue<int>(key => Clients(Context.ConnectionId).Client.GetValue(key))); 

    // WORKING 
    new Thread(() => Debug.Print(MethodHandler.GetValue<int>(key => Clients(Context.ConnectionId).Client.GetValue(key)))).Start(); 

    return base.OnConnected(); 
} 
2

우선 동기를 발생시키는 방법에 대한 도움을 요청하는 대신, 지금하고있는 일에 대해 알려 주면 가장 적절한 방법이라고 제안 할 수 있다고 생각합니다. .

당신은 당신의 MethodHandler::Retrieve 방법을 보여주지 않지만, 나는 그것이 어떻게 생겼는지를 짐작할 수 있습니다. 그리고 그것은 진짜 문제조차되지 않습니다. 가능한 가장 좋은 방법으로 말해야하는데 이것은 입니다. 정말 나쁜 아이디어입니다. 단순히 확장되지 않습니다. 블로킹을 제공하기 위해 머신 특정 리소스 (예 : ManualResetEvent 뒤에있는 커널 객체)를 사용하기 때문에 단일 SignalR 서버 인스턴스에서만 작동합니다. 요구 사항을 충족하기 위해 하나의 서버 이상으로 확장 할 필요는 없지만 단일 서버에서도 여전히 리소스 낭비입니다.

실제로 클라이언트는 requestId을 상관 식별자로 호출하여 올바른 경로에 있습니다. 왜 그 상관 관계를 사용하여 논리적 인 당신이 서버 측의 중간에 어떤 프로세스를 재개 할 수 없습니까?이렇게하면 메시지가 클라이언트에 전달되고 처리 된 후 샘플에있는 후속 메시지 인 GetValueResult이 서버 인스턴스로 다시 전송 될 때까지 기다리지 않고 리소스를 보존 할 수 있습니다.

+0

감사 :

그래서 나는 코드를 변경했습니다. 여러 대의 서버로 확장 할 필요는 없지만 성능은 아주 좋아야합니다. – hwcverwe

+0

'MethodHandler :: Retrieve'를'MethodHandler :: GetValue'로 변경했습니다 ;-) – hwcverwe