好的,首先我将描述我的目标,然后是我编写的代码,最后是问题。
目标
拥有一个管理多个合约的通用类,并且能够在进行操作的那一刻找出它是在线还是离线情况。有一种非常简单的方法:为每个 Online-Offline 对创建一个类,该类实现合约并检查每个方法是否在线,并做出正确的调用。这正是我想要避免的。
仅供参考,在幕后它将是一个连接到WCF 服务的在线场景和一个连接到客户端本地数据库的离线场景。
仅供参考 2:我试图避免拦截和 AOP 的东西,但我发现了一个死胡同。您可以看到这篇文章,我在其中实现了似乎是一个很好的解决方案,但是如果它在构造函数上已连接或未连接则稳定,但现实世界的场景需要在操作级别而不是构造函数级别进行此检查。
代码
它已准备好运行和测试:只需复制/粘贴到新的控制台应用程序上。
using System;
using System.Reflection;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.InterceptionExtension;
namespace ConsoleApplication1
{
public class Unity
{
public static IUnityContainer Container;
public static void Initialize()
{
Container = new UnityContainer();
Container.AddNewExtension<Interception>();
Container.RegisterType<ILogger, OnlineLogger>();
Container.Configure<Interception>().SetInterceptorFor<ILogger>(new InterfaceInterceptor());
}
}
class Program
{
static void Main(string[] args)
{
Unity.Initialize();
var r = new Router<ILogger, OnlineLogger, OfflineLogger>();
try
{
r.Logger.Write("Method executed.");
}
catch (CantLogException ex)
{
r.ManageCantLogException(ex);
}
Console.ReadKey();
}
}
public class Router<TContract, TOnline, TOffline>
where TOnline : TContract, new()
where TOffline : TContract, new()
{
public TContract Logger;
public Router()
{
Logger = Unity.Container.Resolve<TContract>();
}
public void ManageCantLogException(CantLogException ex)
{
// Is this an ugly trick? I mean, the type was already registered with online.
Unity.Container.RegisterType<TContract, TOffline>();
Logger = Unity.Container.Resolve<TContract>();
var method = ((MethodBase)ex.MethodBase);
method.Invoke(Logger, ex.ParameterCollection);
}
}
public interface ILogger
{
[Test]
void Write(string message);
}
public class OnlineLogger : ILogger
{
public static bool IsOnline()
{
// A routine that check connectivity
return false;
// Should I perform a "lock" here to make this tread safe?
}
public void Write(string message)
{
Console.WriteLine("Logger: " + message);
}
}
public class OfflineLogger : ILogger
{
public void Write(string message)
{
Console.WriteLine("Logger: " + message);
}
}
[System.Diagnostics.DebuggerStepThroughAttribute()]
public class TestAttribute : HandlerAttribute
{
public override ICallHandler CreateHandler(IUnityContainer container)
{
return new TestHandler();
}
}
public class TestHandler : ICallHandler
{
public int Order { get; set; }
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
Console.WriteLine("It's been intercepted.");
if (!OnlineLogger.IsOnline() && input.Target is OnlineLogger)
{
Console.WriteLine("It's been canceled.");
throw new CantLogException(input.MethodBase, input.Inputs);
}
return getNext()(input, getNext);
}
}
public class CantLogException : Exception
{
public MethodBase MethodBase { get; set; }
public object[] ParameterCollection { get; set; }
public CantLogException(string message)
: base(message)
{
}
public CantLogException(MethodBase methodBase, IParameterCollection parameterCollection)
{
this.MethodBase = methodBase;
var parameters = new object[parameterCollection.Count];
int i = 0;
foreach (var parameter in parameterCollection)
{
parameters[i] = parameter;
i++;
}
this.ParameterCollection = parameters;
}
}
}
问题
我提出的这个设计是线程安全的吗?
这是性能的耻辱吗?处理在线-离线情况的异常和那里的反思让我觉得我做错了。
我认为这是一个常见的要求,是不是有任何 api/fwk/whatever 可以进行在线-离线管理?感觉就像我在这里重新发明了轮船。
这是一个长期的问题:我真的不希望客户端(本例中的Program类)知道异常,是否有任何其他方法可以取消方法执行,而是通过拦截器上的异常?也欢迎任何其他方法。
我对付费的第三方东西不感兴趣,所以遗憾的是像PostSharp这样的东西不是我的选择。