2013-05-10 17 views
5

Ich entwickle ein Projekt mit passiver Replikation, wo Server untereinander Nachrichten austauschen. Die Speicherorte jedes Servers sind jedem anderen Server bekannt.Überprüfen, ob ein Objekt nach dem Aufruf von Activator.GetObject existiert

So kann es passieren, dass beim Start eines Servers die anderen Server, die noch nicht auf dem Server sind, überprüft werden. Wenn ich Activator.GetObject aufrufen, ist es die einzige Möglichkeit, herauszufinden, dass andere Server heruntergefahren sind, indem Sie eine Methode für das Objekt aufrufen und eine IOException (wie das Beispiel unten) erwarten?

try 
{ 
    MyType replica = (MyType)Activator.GetObject(
    typeof(IMyType), 
    "tcp://localhost:" + location + "/Server"); 

    replica.ping(); 
} 
catch (IOEXception){} // server is down 

Ich tue dies, und es funktioniert die meiste Zeit (obwohl langsam ist), aber manchmal ist es Blöcke auf einer Methode namens NegotiateStream.ProcessRead während des Prozesses, und ich kann nicht verstehen, warum ...

+0

Meinen Sie IMyType Replik = IMyType) Activator.GetObject (typeof (IMyType), "tcp: // localhost:" + Lage + "/Server");? – AngelCastillo

+0

In diesem Fall gibt es kein Problem. MyType implementiert die IMyType-Schnittstelle. Und wie gesagt, das funktioniert meistens, also glaube ich nicht, dass das das Problem sein könnte! –

Antwort

1

Wenn ein Server heruntergefahren ist, war das Zeitlimit für mich immer langsam (mit einem TcpChannel, mit dem Sie das Timeout in .NET Remoting nicht richtig einstellen können). Im Folgenden finden Sie eine Abhilfe für wie ich meine Ping-Funktion verwenden (es ist wahrscheinlich ein wenig komplex für Ihre Bedürfnisse, also werde ich die Teile erklären, die für Sie wichtig):

[System.Diagnostics.DebuggerHidden] // ignore the annoying breaks when get exceptions here. 
    internal static bool Ping<T>(T svr) 
    { 
    // Check type T for a defined Ping function 
    if (svr == null) return false; 
    System.Reflection.MethodInfo PingFunc = typeof(T).GetMethod("Ping"); 
    if (PingFunc == null) return false; 

    // Create a new thread to call ping, and create a timeout of 5 secons 
    TimeSpan timeout = TimeSpan.FromSeconds(5); 
    Exception pingexception = null; 
    System.Threading.Thread ping = new System.Threading.Thread(
     delegate() 
     { 
      try 
      { 
       // just call the ping function 
       // use svr.Ping() in most cases 
       // PingFunc.Invoke is used in my case because I use 
       // reflection to determine if the Ping function is 
       // defined in type T 
       PingFunc.Invoke(svr, null); 
      } 
      catch (Exception ex) 
      { 
       pingexception = ex; 
      } 
     } 
    ); 

    ping.Start(); // start the ping thread. 
    if (ping.Join(timeout)) // wait for thread to return for the time specified by timeout 
    { 
     // if the ping thread returned and no exception was thrown, we know the connection is available 
     if (pingexception == null) 
      return true; 
    } 

    // if the ping thread times out... return false 
    return false; 
    } 

Hoffentlich werden die Kommentare zu erklären, was ich hier tun, aber ich gebe dir eine Zusammenfassung der ganzen Funktion. Wenn Sie nicht interessiert sind, springen Sie einfach zu der Stelle, an der ich den Ping-Thread erkläre.

DebuggerHidden Attribut

stelle ich das DebuggerHidder Attribut, weil, wenn das Debuggen, können Ausnahmen hier ständig im Ping-Thread geworfen werden, und sie erwartet werden. Es ist einfach genug, dies zu kommentieren, sollte die Fehlersuche notwendig werden.

Warum verwende ich Reflexion und einen generischen Typen

Die ‚svr‘ Parameter ein Typ zu sein, mit einer Ping-Funktion erwartet wird. In meinem Fall habe ich ein paar remotable Interfaces auf dem Server mit einer gemeinsamen Ping-Funktion implementiert. Auf diese Weise kann ich einfach Ping (svr) aufrufen, ohne einen Typ eingeben oder bestimmen zu müssen (es sei denn, das entfernte Objekt wird lokal als 'Objekt' instanziiert). Im Grunde ist dies nur für syntaktische Bequemlichkeit.

Das Ping Thema

können Sie verwenden, was Logik Sie ein akzeptables Timeout bestimmen wollen, in meinem Fall, 5 Sekunden ist gut. Ich erstelle ein TimeSpan 'timeout' mit einem Wert von 5 Sekunden, eine Exception pingexception, und erstelle einen neuen Thread, der 'svr.Ping()' aufruft und setzt 'pigexception' auf die Ausnahme, die beim Aufruf von 'svr ausgelöst wird. Klingeln()'.

Sobald ich 'ping.Start()' aufrufen, verwende ich sofort die boolesche Methode ping.Join (TimeSpan), um auf die erfolgreiche Rückgabe des Threads zu warten, oder gehe weiter, wenn der Thread nicht innerhalb der angegebenen Menge zurückkehrt von Zeit. Wenn der Thread jedoch ausgeführt wurde, aber eine Ausnahme ausgelöst wurde, möchten wir dennoch nicht, dass Ping den Wert true zurückgibt, da ein Problem bei der Kommunikation mit dem Remote-Objekt aufgetreten ist. Aus diesem Grund verwende ich 'pingexception', um sicherzustellen, dass beim Aufruf von svr.Ping() keine Ausnahmen aufgetreten sind. Wenn 'pingexception' am Ende null ist, dann weiß ich, dass ich sicher bin, dass es wahr ist.

Oh und um die Frage zu beantworten, die Sie ursprünglich gefragt (.... manchmal blockiert es auf eine Methode namens NegotiateStream.ProcessRead während des Prozesses, und ich kann nicht verstehen, warum ...), Ich war noch nie in der Lage finde die Timeout Probleme mit.NET Remoting, also ist diese Methode, was ich für unsere .NET Remoting-Bedürfnisse gebacken und aufgeräumt habe.

+0

Ich hatte den Check-Stack-Überlauf schon länger nicht mehr, und mein Projekt ist schon fertig, also werde ich deine Lösung nicht versuchen ... Aber es war die vollständigste und gut erklärte Antwort, also werde ich es als akzeptiert markieren! –

0

Ich habe eine verbesserte Version davon mit Generika verwendet:

internal static TResult GetRemoteProperty<T, TResult>(string Url, System.Linq.Expressions.Expression<Func<T, TResult>> expr) 
    { 
     T remoteObject = GetRemoteObject<T>(Url); 
     System.Exception remoteException = null; 
     TimeSpan timeout = TimeSpan.FromSeconds(5); 
     System.Threading.Tasks.Task<TResult> t = new System.Threading.Tasks.Task<TResult>(() => 
     { 
      try 
      { 
       if (expr.Body is System.Linq.Expressions.MemberExpression) 
       { 
        System.Reflection.MemberInfo memberInfo = ((System.Linq.Expressions.MemberExpression)expr.Body).Member; 
        System.Reflection.PropertyInfo propInfo = memberInfo as System.Reflection.PropertyInfo; 
        if (propInfo != null) 
         return (TResult)propInfo.GetValue(remoteObject, null); 
       } 
      } 
      catch (Exception ex) 
      { 
       remoteException = ex; 
      } 
      return default(TResult); 
     }); 
     t.Start(); 
     if (t.Wait(timeout)) 
      return t.Result; 
     throw new NotSupportedException(); 
    } 

    internal static T GetRemoteObject<T>(string Url) 
    { 
     return (T)Activator.GetObject(typeof(T), Url); 
    }