在调用Activator.GetObject后检查对象是否存在
本文关键字:对象 是否 存在 检查 调用 Activator GetObject | 更新日期: 2023-09-27 18:13:09
我正在开发一个被动复制项目,其中服务器之间交换消息。每个服务器的位置都被其他服务器知道。
当一个服务器启动时,它可能会检查其他服务器,这些服务器可能还没有启动。当我调用Activator.GetObject
时,通过调用对象上的方法来发现其他服务器已关闭,并期望IOException
(如下面的示例)是唯一的方法吗?
try
{
MyType replica = (MyType)Activator.GetObject(
typeof(IMyType),
"tcp://localhost:" + location + "/Server");
replica.ping();
}
catch (IOEXception){} // server is down
我这样做,它的工作大多数时候(即使是缓慢的),但有时它阻塞了一个方法称为NegotiateStream.ProcessRead
过程中,我不明白为什么…
当服务器关闭时,超时对我来说总是很慢(使用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线程的地方。
<<p> DebuggerHidden属性/strong>我设置了DebuggerHidder属性,因为在调试时,异常可以在ping线程中不断抛出,并且它们是预期的。如果需要调试该函数,可以很容易地将其注释掉。
为什么我使用反射和泛型类型
'svr'参数应该是一个带有Ping功能的类型。在我的例子中,我在服务器上实现了几个不同的远程接口,并使用一个通用的Ping功能。这样,我就可以调用Ping(svr),而不必强制转换或指定类型(除非远程对象在本地实例化为"对象")。基本上,这只是为了语法上的方便。
Ping线程
你可以使用任何逻辑你想要确定一个可接受的超时,在我的情况下,5秒是好的。我创建了一个TimeSpan 'timeout',值为5秒,一个Exception pingexception,并创建了一个新线程,试图调用'svr.Ping()',并将'pingexception'设置为调用'svr.Ping()'时抛出的任何异常。
一旦我调用'ping.Start()',我立即使用布尔方法ping.Join(TimeSpan)等待线程成功返回,或者如果线程没有在指定的时间内返回,则继续前进。但是,如果线程完成执行但抛出异常,我们仍然不希望Ping返回true,因为与远程对象通信存在问题。这就是为什么我使用'pingexception'来确保在调用svr.Ping()时不会发生异常。如果'pingexception'最后为null,那么我知道我可以安全返回true。
哦,回答你最初问的问题(....有时它会阻塞一个名为NegotiateStream的方法。ProcessRead的过程中,我不能理解为什么…),我从来没有能够找出超时问题与。net Remoting,所以这个方法是我烤和清理我们的。net Remoting需要。
我使用了一个改进的泛型版本:
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);
}