さて、最初に私の目標を説明し、次に私がコーディングしたものを説明し、最後に質問をします。
ゴール
複数のコントラクトを管理し、操作が行われている瞬間に、それがオンラインかオフラインかを判断できる汎用クラスを持つこと。それを行うには本当に簡単な方法があります。コントラクトを実装し、オンラインかどうかにかかわらずすべてのメソッドをチェックし、適切な呼び出しを行う、オンラインとオフラインの各ペアのクラスです。そしてそれはまさに私が避けたいことです。
参考までに、舞台裏では、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 /何かはありませんか?ここでウィールを作り直しているような気がします。
これは長い質問です。クライアント(この例ではプログラムクラス)に例外について知られたくないのですが、メソッドの実行をキャンセルする方法は他にありませんが、インターセプターの例外を使用しますか?他のアプローチも歓迎します。
私は有料のサードパーティのものには興味がないので、悲しいことに、PostSharpのようなものは私にとってオプションではありません。