• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

C# 使用 Castle 实现 AOP及如何用 Autofac 集成 Castle

c# 搞代码 4年前 (2022-01-09) 36次浏览 已收录 0个评论

Castle 是 2003 年诞生于 Apache Avalon 项目,目的是为了创建一个IOC 框架。发展到现在已经有四个组件:

  • ORM组件:ActiveRecord
  • IOC组件:Windsor
  • 动态代理组件:DynamicProxy
  • Web MVC组件:MonoRail

本文主要介绍 动态代理组件 Castle.DynamicProxy

基本用法

Castle.DynamicProxy 是通过 Emit 反射动态生成代理类来实现的,效率相对静态植入要慢一点,但比普通的反射又高一些。动态代理只对公共接口方法、类中的虚方法生效,因为只有接口中的方法、类中的虚方法才可以在子类中重写。

基于接口的拦截器

public interface IProductRepository
{
 void Add(string name);
}

public class ProductRepository : IProductRepository
{
 public void Add(string name) => Console.WriteLine($"新增产品:{name}");
}

public class LoggerInterceptor : IInterceptor
{
 public void Intercept(IInvocation invocation)
 {
  var methodName = invocation.Method.Name;

  Console.WriteLine($"{methodName} 执行前");

  //调用业务方法
  invocation.Proceed();

  Console.WriteLine($"{methodName} 执行完毕");
 }
}

class Program
{
 static void Main(string[] args)
 {
  ProxyGenerator generator = new ProxyGenerator();

  IInterceptor loggerIntercept = new LoggerInterceptor();

  IProductRepository productRepo = new ProductRepository();

  IProductRepository proxy = generator.CreateInterfaceProxyWithTarget(productRepo, loggerIntercept);

  proxy.Add("大米");

  Console.Read();
 }
}

基于类的拦截器

public class ProductRepository
{
 public virtual void Add(string name) => Console.WriteLine($"新增产品:{name}");
}

static void Main(string[] args)
{
 ProxyGenerator generator = new ProxyGenerator();

 IInterceptor loggerIntercept = new LoggerInterceptor();

 ProductRepository proxy = generator.CreateClassProxyWithTarget(new ProductRepository(), loggerIntercept);
 // 使用 CreateClassProxy 泛型方法可以省去实例化代码
 //ProductRepository proxy = generator.CreateClassProxy<ProductReposito<i>本文来源gaodai$ma#com搞$代*码*网</i>ry>(loggerIntercept);

 proxy.Add("大米");
}

在上例中,如果 ProductRepository.Add 不是虚方法,也不会报错,但是拦截器不会被调用。

异步函数拦截

Castle.DynamicProxy 对异步函数的拦截跟同步没啥差别,只是,如果要在方法执行完成后插入内容,需要 await

public class ProductRepository
{
 public virtual Task Add(string name)
 {
  return Task.Run(() =>
      {
       Thread.Sleep(1000);
       Console.WriteLine($"异步新增产品:{name}");
      });
 }
}

public class LoggerInterceptor : IInterceptor
{
 public async void Intercept(IInvocation invocation)
 {
  var methodName = invocation.Method.Name;

  Console.WriteLine($"{methodName} 执行前");

  invocation.Proceed();

  // 不 await 的话将会先输出“执行完毕”,再输出“异步新增产品”
  var task = (Task)invocation.ReturnValue;
  await task;

  Console.WriteLine($"{methodName} 执行完毕");
 }
}

上面这个写法是简单粗暴的,如果碰到返回值是 Task<TResult>,或者不是异步函数,就会出错。所以这里是要对返回值进行一个判断的。

可以使用 Castle.Core.AsyncInterceptor 包,它包装了 Castle,使异步调用更简单。

Castle.Core.AsyncInterceptor 的 GitHub 地址:https://github.com/JSkimming/Castle.Core.AsyncInterceptor

public class ProductRepository : IProductRepository
{
 public Task Add(string name)
 {
  return Task.Run(() =>
      {
       Thread.Sleep(1000);
       Console.WriteLine($"异步新增产品:{name}");
      });
 }

 public Task<string> Get()
 {
  return Task.Run(() =>
      {
       Thread.Sleep(1000);
       Console.WriteLine($"获取产品");

       return "大米";
      });
 }
}

public class LoggerInterceptor : IAsyncInterceptor
{
 public void InterceptAsynchronous(IInvocation invocation)
 {
  invocation.ReturnValue = InternalInterceptAsynchronous(invocation);
 }

 async Task InternalInterceptAsynchronous(IInvocation invocation)
 {
  var methodName = invocation.Method.Name;

  Console.WriteLine($"{methodName} 异步执行前");

  invocation.Proceed();
  await (Task)invocation.ReturnValue;

  Console.WriteLine($"{methodName} 异步执行完毕");
 }

 public void InterceptAsynchronous<TResult>(IInvocation invocation)
 {
  invocation.ReturnValue = InternalInterceptAsynchronous<TResult>(invocation);

  Console.WriteLine(((Task<TResult>)invocation.ReturnValue).Id);
 }

 private async Task<TResult> InternalInterceptAsynchronous<TResult>(IInvocation invocation)
 {
  var methodName = invocation.Method.Name;

  Console.WriteLine($"{methodName} 异步执行前");

  invocation.Proceed();
  var task = (Task<TResult>)invocation.ReturnValue;
  TResult result = await task;

  Console.WriteLine(task.Id);

  Console.WriteLine($"{methodName} 异步执行完毕");

  return result;
 }

 public void InterceptSynchronous(IInvocation invocation)
 {
  var methodName = invocation.Method.Name;

  Console.WriteLine($"{methodName} 同步执行前");

  invocation.Proceed();

  Console.WriteLine($"{methodName} 同步执行完毕");
 }
}

class Program
{
 static void Main(string[] args)
 {
  ProxyGenerator generator = new ProxyGenerator();

  IAsyncInterceptor loggerIntercept = new LoggerInterceptor();

  IProductRepository productRepo = new ProductRepository();

  IProductRepository proxy = generator.CreateInterfaceProxyWithTarget(productRepo, loggerIntercept);

  proxy.Get();
 }
}

搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:C# 使用 Castle 实现 AOP及如何用 Autofac 集成 Castle

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址