希望能在某個 Method前面加上 [AddCache("cacheKey", new TimeSpan(0, 10, 0))],就能把 ReadMethod回傳的值放進快取 10分鐘,最好順便有 [RefreshCache("cacheKey")]能用在 UpdateMethod;當然,儘量不要動到原本 Method內容。
先說目前狀況:待解決。
最像的是這個:https://github.com/agbell/attribute-based-caching,用 PostSharp弄出像 event (OnEntry、OnSuccess)的東東可以在 method執行前、後加入自訂邏輯(我突然懷念 JavaScript可以隨便挾持方法亂加料),但是 PostSharp好像原本免費,現在要收錢…編譯過不了就跳過。
接著試著 google "C# AOP",看到幾種方式,但都…工程不小:
- 原本有用 DI的話,很多 DI framework有 Interceptor,可以在呼叫方法前後加入自訂邏輯
- 沒有 DI可以直接用 DynamicProxy
在不改 method內容的前提下增加自訂邏輯(拼拼湊湊的程式碼):
using Castle.Core;
using Castle.DynamicProxy;
using Castle.MicroKernel.Registration;
using Castle.Windsor;
using System;
using System.Reflection;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Proxies;
namespace testCastle
{
class Program
{
static void Main(string[] args)
{
Imethod method;
// Castle.Windsor;
CastleConfig.Initialized();
method = CastleConfig.Container.Resolve<Imethod>();
method.echo1("echo1");
method.echo2("echo2");
// Castle.Core
method = new ProxyGenerator().CreateClassProxy<method>(
new Interceptor1()
);
method.echo1("echo1");
method.echo2("echo2");
// System.Runtime.Remoting
method = new DynamicProxy<Imethod>(
new method()
).GetTransparentProxy() as Imethod;
method.echo1("echo1");
method.echo2("echo2");
}
}
public interface Imethod
{
string echo1(string input);
string echo2(string input);
}
[Interceptor(typeof(Interceptor1))]
public class method : Imethod
{
public virtual string echo1(string input)
{
Console.WriteLine("echo1 execute.");
return input;
}
public string echo2(string input)
{
Console.WriteLine("echo2 execute.");
return input;
}
}
static class CastleConfig
{
public static IWindsorContainer Container;
internal static void Initialized()
{
Container = new WindsorContainer();
// 註冊攔截器的型別與物件供 Interceptor attribute 使用
Container.Register(
Component.For<IInterceptor>().ImplementedBy<Interceptor1>().LifestyleTransient()
);
Container.Register(
Component.For<Imethod>()
.ImplementedBy<method>().LifestyleTransient());
}
}
class Interceptor1 : IInterceptor
{
public void Intercept(IInvocation invocation)
{
var typeName = invocation.TargetType.FullName;
var methodName = invocation.Method.Name;
Console.WriteLine("====Interceptor1 before", typeName, methodName);
//foreach (var arg in invocation.Arguments)
//{
// Console.WriteLine("argument:{0}", arg);
//}
invocation.Proceed();
Console.WriteLine("====Interceptor1 after", typeName, methodName);
//Console.WriteLine();
}
}
class DynamicProxy<T> : RealProxy
{
private readonly T _decorated;
public DynamicProxy(T decorated)
: base(typeof(T))
{
_decorated = decorated;
}
private void Log(string msg, object arg = null)
{
//Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(msg, arg);
//Console.ResetColor();
}
public override IMessage Invoke(IMessage msg)
{
var methodCall = msg as IMethodCallMessage;
var methodInfo = methodCall.MethodBase as MethodInfo;
Log("====RealProxy before", methodCall.MethodName);
try
{
var result = methodInfo.Invoke(_decorated, methodCall.InArgs);
Log("====RealProxy after",
methodCall.MethodName);
return new ReturnMessage(result, null, 0,
methodCall.LogicalCallContext, methodCall);
}
catch (Exception e)
{
Log(string.Format(
"In Dynamic Proxy- Exception {0} executing '{1}'", e),
methodCall.MethodName);
return new ReturnMessage(e, methodCall);
}
}
}
}
剛剛做到這裡覺得有點亂,寫下來整理一下…繼續找 orz