调用Activator.GetObject后检查对象是否存在

时间:2013-05-10 23:15:03

标签: c# .net .net-remoting

我正在开发一个带被动复制的项目,其中服务器之间交换消息。每台服务器的位置都是众所周知的。

因此,当服务器启动时,它可能会检查其他可能尚未启动的服务器。当我调用Activator.GetObject时,它是通过调用对象上的方法找出其他服务器已关闭的唯一方法,并且期望IOException(例如下面的示例)吗?

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

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

我这样做并且它大部分时间都有效(尽管速度很慢),但有时会在进程中阻塞一个名为NegotiateStream.ProcessRead的方法,我无法理解为什么......

2 个答案:

答案 0 :(得分:2)

当服务器关闭时,我的超时总是很慢(使用TcpChannel,它不允许您在.NET Remoting中正确设置超时)。下面是我如何使用我的Ping功能的解决方法(它可能对您的需求有点复杂,因此我将解释对您而言重要的部分):

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

希望评论解释我在这里所做的事情,但我会给你一个整体功能的细分。如果您不感兴趣,请跳到我解释ping线程的地方。

DebuggerHidden Attribute

我设置了DebuggerHidder属性,因为在调试时,可以在ping线程中不断地抛出异常,并且它们是预期的。如果调试此函数变得必要,很容易对此进行评论。

为什么我使用反射和泛型类型

'svr'参数应该是具有Ping功能的类型。在我的例子中,我在服务器上实现了一些不同的远程接口,具有通用的Ping功能。通过这种方式,我可以调用Ping(svr)而无需强制转换或指定类型(除非远程对象在本地实例化为“对象”)。基本上,这只是为了语法上的便利。

Ping线程

你可以使用你想要的任何逻辑来确定可接受的超时,在我的情况下,5秒是好的。我创建一个值为5秒的TimeSpan'超时',一个异常pingexception,并创建一个尝试调用'svr.Ping()'的新线程,并将'pingexception'设置为调用'svr时抛出的任何异常。平()”

一旦我调用'ping.Start()',我立即使用boolean方法ping.Join(TimeSpan)等待线程成功返回,或者如果线程没有在指定的量内返回,则继续时间。但是,如果线程完成执行但抛出异常,我们仍然不希望Ping返回true,因为与远程对象通信时出现问题。这就是为什么我使用'pingexception'来确保在调用svr.Ping()时没有发生异常的原因。如果'pingexception'在结尾处为null,那么我知道我可以安全地返回true。

哦,回答你最初提出的问题(....有时它会阻塞一个名为NegotiateStream.ProcessRead的方法,在这个过程中,我无法理解为什么......),我从来没有能够想到解决.NET Remoting的超时问题,所以这个方法就是我为.NET Remoting需求而烘焙和清理的。

答案 1 :(得分:0)

我使用了泛型的改进版本:

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