zoukankan      html  css  js  c++  java
  • Asp.Net Core轻量级Aop解决方案:AspectCore

    什么是AspectCore Project ?

    AspectCore Project 是适用于Asp.Net Core 平台的轻量级 Aop(Aspect-oriented programming) 解决方案,它更好的遵循Asp.Net Core的模块化开发理念,使用AspectCore可以更容易构建低耦合、易扩展的Web应用程序。AspectCore使用Emit实现高效的动态代理从而不依赖任何第三方Aop库。

    开使使用AspectCore

    • 启动 Visual Studio。从 File 菜单, 选择 New > Project。选择 ASP.NET Core Web Application 项目模版,创建新的 ASP.NET Core Web Application 项目。

    • 从 Nuget 安装 AspectCore.Extensions.DependencyInjection package:

      PM>   Install-Package AspectCore.Extensions.DependencyInjection
      
    • 在一般情况下可以使用抽象的AbstractInterceptorAttribute 自定义特性类,它实现IInterceptor接口。AspectCore默认实现了基于Attribute的拦截器配置。我们的自定义拦截器看起来像下面这样:

      public class CustomInterceptorAttribute : AbstractInterceptorAttribute 
      {
          public async override Task Invoke(AspectContext context, AspectDelegate next)
          {
              try
              {
                  Console.WriteLine("Before service call");
                  await next(context);
              }
              catch (Exception)
              {
                  Console.WriteLine("Service threw an exception!");
                  throw;
              }
              finally
              {
                  Console.WriteLine("After service call");
              }
           }
       }
      
    • 定义ICustomService接口和它的实现类CustomService:

      public interface ICustomService
      {
          [CustomInterceptor]
          void Call();
      }
      
      public class CustomService : ICustomService
      {
          public void Call()
          {
              Console.WriteLine("service calling...");
          }
      }
      
    • HomeController中注入ICustomService:

      public class HomeController : Controller
      {
          private readonly ICustomService _service;
          public HomeController(ICustomService service)
          {
              _service = service;
          }
      
          public IActionResult Index()
          {
              _service.Call();
              return View();
          }
      }
      
    • 注册ICustomService,接着,在ConfigureServices中配置创建代理类型的容器:

      public IServiceProvider ConfigureServices(IServiceCollection services)
      {
          services.AddTransient<ICustomService, CustomService>();
          services.AddMvc();
          services.AddDynamicProxy();
          return services.BuildAspectCoreServiceProvider();
      }
      
    • 拦截器配置。

      全局拦截器。使用AddDynamicProxy(Action<IAspectConfiguration>)的重载方法,其中IAspectConfiguration提供Interceptors注册全局拦截器:

       services.AddDynamicProxy(config =>
       {
            config.Interceptors.AddTyped<CustomInterceptorAttribute>();
       });
      

      带构造器参数的全局拦截器,在CustomInterceptorAttribute中添加带参数的构造器:

      public class CustomInterceptorAttribute : AbstractInterceptorAttribute 
      {
          private readonly string _name;
          public CustomInterceptorAttribute(string name)
          {
              _name = name;
          }
          public async override Task Invoke(AspectContext context, AspectDelegate next)
          {
              try
              {
                  Console.WriteLine("Before service call");
                  await next(context);
              }
              catch (Exception)
              {
                  Console.WriteLine("Service threw an exception!");
                  throw;
              }
              finally
              {
                  Console.WriteLine("After service call");
              }
          }
      }
      

      修改全局拦截器注册:

      services.AddDynamicProxy(config =>
      {
           config.Interceptors.AddTyped<CustomInterceptorAttribute>(args: new object[] { "custom" });
      });
      

      作为服务的全局拦截器。在ConfigureServices中添加:

      services.AddTransient<CustomInterceptorAttribute>(provider => new CustomInterceptorAttribute("service"));
      

      修改全局拦截器注册:

      services.AddDynamicProxy(config =>
      {
          config.Interceptors.AddServiced<CustomInterceptorAttribute>();
      });
      

      作用于特定ServiceMethod的全局拦截器,下面的代码演示了作用于带有Service后缀的类的全局拦截器:

      services.AddDynamicProxy(config =>
      {
          config.Interceptors.AddTyped<CustomInterceptorAttribute>(method => method.DeclaringType.Name.EndsWith("Service"));
      });
      

      使用通配符的特定全局拦截器:

      services.AddDynamicProxy(config =>
      {
          config.Interceptors.AddTyped<CustomInterceptorAttribute>(Predicates.ForService("*Service"));
      });
      
    • 在AspectCore中提供NonAspectAttribute来使得ServiceMethod不被代理:

      [NonAspect]
      public interface ICustomService
      {
          void Call();
      }
      

      同时支持全局忽略配置,亦支持通配符:

       services.AddDynamicProxy(config =>
        {
            //App1命名空间下的Service不会被代理
            config.NonAspectPredicates.AddNamespace("App1");
      
            //最后一级为App1的命名空间下的Service不会被代理
            config.NonAspectPredicates.AddNamespace("*.App1");
      
            //ICustomService接口不会被代理
            config.NonAspectPredicates.AddService("ICustomService");
      
            //后缀为Service的接口和类不会被代理
            config.NonAspectPredicates.AddService("*Service");
      
            //命名为Query的方法不会被代理
            config.NonAspectPredicates.AddMethod("Query");
      
            //后缀为Query的方法不会被代理
            config.NonAspectPredicates.AddMethod("*Query");
        });
      
      
    • 拦截器中的依赖注入。在拦截器中支持属性注入,构造器注入和服务定位器模式。
      属性注入,在拦截器中拥有public get and set权限的属性标记[AspectCore.Injector.FromContainerAttribute]特性,即可自动注入该属性,如:

      public class CustomInterceptorAttribute : AbstractInterceptorAttribute 
      {
          [FromContainer]
          public ILogger<CustomInterceptorAttribute> Logger { get; set; }
      
      
          public override Task Invoke(AspectContext context, AspectDelegate next)
          {
              Logger.LogInformation("call interceptor");
              return next(context);
          }
      }
      

      构造器注入需要使拦截器作为Service,除全局拦截器外,仍可使用ServiceInterceptor使拦截器从DI中激活:

      public interface ICustomService
      {
          [ServiceInterceptor(typeof(CustomInterceptorAttribute))]
          void Call();
      }
      

      服务定位器模式。拦截器上下文AspectContext可以获取当前Scoped的ServiceProvider

      public class CustomInterceptorAttribute : AbstractInterceptorAttribute 
      {
          public override Task Invoke(AspectContext context, AspectDelegate next)
          {
              var logger = context.ServiceProvider.GetService<ILogger<CustomInterceptorAttribute>>();
              logger.LogInformation("call interceptor");
              return next(context);
          }
      }
      

    有问题反馈

    如果您有任何问题,请提交 Issue 给我们。
    AspectCore Project 项目地址: https://github.com/dotnetcore/AspectCore-Framework
    AspectCore Group QQ群: 306531723

  • 相关阅读:
    第三方驱动备份与还原
    Greenplum 解决 gpstop -u 指令报错
    yum安装(卸载)本地rpm包的方法(卸载本地安装的greenplum 5.19.rpm)
    Java JUC(java.util.concurrent工具包)
    netty 详解(八)基于 Netty 模拟实现 RPC
    netty 详解(七)netty 自定义协议解决 TCP 粘包和拆包
    netty 详解(六)netty 自定义编码解码器
    netty 详解(五)netty 使用 protobuf 序列化
    netty 详解(四)netty 开发 WebSocket 长连接程序
    netty 详解(三)netty 心跳检测机制案例
  • 原文地址:https://www.cnblogs.com/liuhaoyang/p/aspectcore-introduction-1.html
Copyright © 2011-2022 走看看