名前空間System.Runtime.Remoting.Proxies
およびSystem.Runtime.Remoting.Messaging
for C#のAOP。アプリケーションを.Net Framework 4.6からdnxcore/dotnetコアに移植しようとしています。
Intellisenseによると、これらの2つの名前空間は私のフレームワークバージョン(netcoreapp1.0/dnxcore50)では使用できません。これら2つの名前空間が表示されるかどうかはわかりますか?または、RealProxy
クラスでAOPを取得する方法はありますか?
サードパーティライブラリを使用したくない-.Netが提供するものだけを使用したい。
RealProxyが.NET Core/Standardに含まれないようです 。この問題では、Microsoft開発者が DispatchProxy を代替として提案しています。
また、既存のAOPフレームワークの一部は、.NET Coreをすでにまたは将来サポートする可能性があります(質問のコメントに記載されています)。
別の方法はDispatchProxy
です。これは、ここに素晴らしい例があります。 http://www.c-sharpcorner.com/article/aspect-oriented-programming-in-c-sharp-using- dispatchproxy / 。
コードを簡略化すると、次のようになります。
public class LoggingDecorator<T> : DispatchProxy
{
private T _decorated;
protected override object Invoke(MethodInfo targetMethod, object[] args)
{
try
{
LogBefore(targetMethod, args);
var result = targetMethod.Invoke(_decorated, args);
LogAfter(targetMethod, args, result);
return result;
}
catch (Exception ex) when (ex is TargetInvocationException)
{
LogException(ex.InnerException ?? ex, targetMethod);
throw ex.InnerException ?? ex;
}
}
public static T Create(T decorated)
{
object proxy = Create<T, LoggingDecorator<T>>();
((LoggingDecorator<T>)proxy).SetParameters(decorated);
return (T)proxy;
}
private void SetParameters(T decorated)
{
if (decorated == null)
{
throw new ArgumentNullException(nameof(decorated));
}
_decorated = decorated;
}
private void LogException(Exception exception, MethodInfo methodInfo = null)
{
Console.WriteLine($"Class {_decorated.GetType().FullName}, Method {methodInfo.Name} threw exception:\n{exception}");
}
private void LogAfter(MethodInfo methodInfo, object[] args, object result)
{
Console.WriteLine($"Class {_decorated.GetType().FullName}, Method {methodInfo.Name} executed, Output: {result}");
}
private void LogBefore(MethodInfo methodInfo, object[] args)
{
Console.WriteLine($"Class {_decorated.GetType().FullName}, Method {methodInfo.Name} is executing");
}
}
したがって、対応するインターフェースを備えたサンプルクラスCalculator
がある場合(ここには表示されていません):
public class Calculator : ICalculator
{
public int Add(int a, int b)
{
return a + b;
}
}
このように使用できます
static void Main(string[] args)
{
var decoratedCalculator = LoggingDecorator<ICalculator>.Create(new Calculator());
decoratedCalculator.Add(3, 5);
Console.ReadKey();
}
_System.Reflection.DispatchProxy
_または独自の単純なデコレータ実装を使用できます。実装例については、Wikipediaの Decorator pattern ページを確認してください。
現在.NET Coreでは、DispatchProxy
でコンストラクターインジェクションを使用することはできません。使用するプロキシタイプへの明示的なキャストでDispatchProxy.Create()
ファクトリメソッドとプロパティインジェクションを使用する必要があります。詳細については、.NET Core GitHubリポジトリの DispachProxyTest.cs を確認してください。
これは、DispatchProxy
を継承する単純なジェネリックデコレータの例です。
_class GenericDecorator : DispatchProxy
{
public object Wrapped { get; set; }
public Action<MethodInfo, object[]> Start { get; set; }
public Action<MethodInfo, object[], object> End { get; set; }
protected override object Invoke(MethodInfo targetMethod, object[] args)
{
Start?.Invoke(targetMethod, args);
object result = targetMethod.Invoke(Wrapped, args);
End?.Invoke(targetMethod, args, result);
return result;
}
}
_
そしてそれは使用法です:
_class Program
{
static void Main(string[] args)
{
IEcho toWrap = new EchoImpl();
IEcho decorator = DispatchProxy.Create<IEcho, GenericDecorator>();
((GenericDecorator)decorator).Wrapped = toWrap;
((GenericDecorator)decorator).Start = (tm, a) => Console.WriteLine($"{tm.Name}({string.Join(',', a)}) is started");
((GenericDecorator)decorator).End = (tm, a, r) => Console.WriteLine($"{tm.Name}({string.Join(',', a)}) is ended with result {r}");
string result = decorator.Echo("Hello");
}
class EchoImpl : IEcho
{
public string Echo(string message) => message;
}
interface IEcho
{
string Echo(string message);
}
}
_
AutofacとDynamicProxyを組み合わせて使用することもできます。この記事には、素晴らしい紹介とそれを達成する方法のサンプルがあります。