ACP*_*ACP 12 c# castle-dynamicproxy class interceptor
我被要求在我的asp.net Web应用程序中实现城堡动态代理,我正在阅读几篇文章,我从Castle Project和Code Project获得了关于asp.net web应用程序中的城堡动态代理....
这两篇文章都与创建拦截器有关,但是我无法理解为什么拦截器会与类一起使用....为什么我要拦截行为正常的类?
Aar*_*ght 53
假设你的班级需要为某项操作做3件事:
让我们进一步假设您的类对您配置安全性,日志记录或缓存的具体方式一无所知.你需要依赖这些东西的抽象.
有几种方法可以解决它.一种方法是设置一堆接口并使用构造函数注入:
public class OrderService : IOrderService
{
private readonly IAuthorizationService auth;
private readonly ILogger logger;
private readonly ICache cache;
public OrderService(IAuthorizationService auth, ILogger logger,
ICache cache)
{
if (auth == null)
throw new ArgumentNullException("auth");
if (logger == null)
throw new ArgumentNullException("logger");
if (cache == null)
throw new ArgumentNullException("cache");
this.auth = auth;
this.logger = logger;
this.cache = cache;
}
public Order GetOrder(int orderID)
{
auth.AssertPermission("GetOrder");
logger.LogInfo("GetOrder:{0}", orderID);
string cacheKey = string.Format("GetOrder-{0}", orderID);
if (cache.Contains(cacheKey))
return (Order)cache[cacheKey];
Order order = LookupOrderInDatabase(orderID);
cache[cacheKey] = order;
return order;
}
}
Run Code Online (Sandbox Code Playgroud)
这不是可怕的代码,但想想我们引入的问题:
OrderService没有所有三个依赖项,该类无法运行.如果我们想要这样做,我们需要开始在每个地方使用空检查来编写代码.
我们正在编写大量额外代码来执行相对简单的操作(查找订单).
所有这些样板代码都必须在每个方法中重复,这使得实现非常大,丑陋,容易出错.
这是一个更容易维护的类:
public class OrderService : IOrderService
{
[Authorize]
[Log]
[Cache("GetOrder-{0}")]
public virtual Order GetOrder(int orderID)
{
return LookupOrderInDatabase(orderID);
}
}
Run Code Online (Sandbox Code Playgroud)
在面向方面编程中,这些属性称为连接点,其完整集合称为点切割.
我们不是一遍又一遍地实际编写依赖代码,而是留下"提示",即应该为此方法执行一些额外的操作.
当然,这些属性必须得到变成代码的某个时候,但你可以推迟,所有的方式到你的主应用程序代码,通过创建一个代理的OrderService(注意GetOrder方法已经取得了virtual,因为它需要重写的服务),并拦截该GetOrder方法.
编写拦截器可能就像这样简单:
public class LoggingInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
if (Attribute.IsDefined(invocation.Method, typeof(LogAttribute))
{
Console.Writeline("Method called: "+ invocation.Method.Name);
}
invocation.Proceed();
}
}
Run Code Online (Sandbox Code Playgroud)
创建代理将是:
var generator = new ProxyGenerator();
var orderService = (IOrderService)generator.CreateClassProxy(typeof(OrderService),
new LoggingInterceptor());
Run Code Online (Sandbox Code Playgroud)
这不仅是重复性较低的代码,而且它完全消除了实际的依赖性,因为看看我们做了什么 - 我们甚至还没有授权或缓存系统,但系统仍在运行.我们稍后可以通过注册另一个拦截器并检查AuthorizeAttribute或来插入授权和缓存逻辑CacheAttribute.
希望这能解释"为什么".
边栏:正如KrzysztofKoźmic评论的那样,使用这样的动态拦截器并不是DP的"最佳实践".在生产代码中,您不希望拦截器运行不必要的方法,因此请使用IInterceptorSelector.