Lycoris.Castle.Extensions 6.0.0

dotnet add package Lycoris.Castle.Extensions --version 6.0.0
                    
NuGet\Install-Package Lycoris.Castle.Extensions -Version 6.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Lycoris.Castle.Extensions" Version="6.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Lycoris.Castle.Extensions" Version="6.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Lycoris.Castle.Extensions" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Lycoris.Castle.Extensions --version 6.0.0
                    
#r "nuget: Lycoris.Castle.Extensions, 6.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Lycoris.Castle.Extensions@6.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Lycoris.Castle.Extensions&version=6.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Lycoris.Castle.Extensions&version=6.0.0
                    
Install as a Cake Tool

Castle.Core.AsyncInterceptor针对Autofac的AOP拦截扩展

Ps:Castle.Core.AsyncInterceptor 的AOP拦截目前测试中仅支持使用接口进行实现的服务,其他的不支持,也就是要使用该扩展的前提条件就是必须要有接口与实现类的方式注册服务,如果你的应用非这种方式的话,请不要使用,因为你也用不了,会报错!

使用方法

由于是做了封装扩展,所以Castle.Core.AsyncInterceptor的原生使用方式,这里就不做描述,仅介绍扩展封装后的简化使用方式

创建一个特性,该特性主要是用来甄别方法是否需要AOP执行类的介入

[AttributeUsage(AttributeTargets.Method, Inherited = true)]
public class DemoAopAttribute : Attribute
{
    /// <summary>
    /// 类中的公有属性根据你自己的需求添加,此处的参数仅仅是实例,你也不加,后续AOP的方法中会传入你的特性
    /// </summary>
    public string ActionName { get; set; } = string.Empty;
}

创建AOP执行类,创建方式有两种

  • 1. 对于不熟悉原生使用方式的人员,建议创建一个AOP执行类并继承AsyncInterceptorHandler,在继承类的泛型参数中填入上面创建的特性

public class DemoAsyncInterceptor : AsyncInterceptorHandler<DemoAopAttribute>
{
}

继承后需要实现虚方法:

  • protected abstract void InterceptAfterHandlger(IInvocation invocation, T attribute):同步拦截器

  • protected virtual Task InterceptAfterHandlger(IInvocation invocation, T attribute):异步拦截器(Task)

  • protected abstract Task InterceptbAfterHandlgerAsync<TResult>(IInvocation invocation, T attribute, TResult result):异步拦截器(ValueTask)

以上三个均是必须实现的方法,这三个方法都是针对于执行方法之后的拦截,如果你需要执行方法之前也需要拦截,你只需要重写以下几个方法:

  • protected virtual void InterceptBeforeHandlger(IInvocation invocation, T attribute):同步拦截器

  • protected virtual Task InterceptbBeforeHandlgerAsync(IInvocation invocation, T attribute):异步拦截器(Task)

  • protected virtual Task InterceptbBeforeHandlgerAsync<TResult>(IInvocation invocation, T attribute):异步拦截器(ValueTask)

上述的方法根据你自己的业务需求的方法类型进行重写即可,不一定都要重写


  • 2. 对于熟悉原生使用方式的人员,你想有更多的自定义需求,可以继承:BaseAsyncInterceptorHandler,进行更多的自定义

public class DemoAsyncInterceptor : BaseAsyncInterceptorHandler<DemoAopAttribute>
{
}

继承BaseAsyncInterceptorHandler需要注意你需要手动去进行拦截方法的执行,该类没有帮你处理这部分,以防你需要其他的处理

继承BaseAsyncInterceptorHandler同样需要实现三个虚方法:

  • protected abstract void InterceptHandlger(IInvocation invocation, T attribute):同步拦截器

  • protected abstract Task InterceptHandlgerAsync(IInvocation invocation, T attribute):异步拦截器(Task)

  • protected abstract Task<TResult> InterceptHandlgerAsync<TResult>(IInvocation invocation, T attribute):异步拦截器(ValueTask)

当然你还不满足于此,你甚至想修改更多,也支持重写原生的接口方法,重写原生的方法后,如果你使用不到上面的三个虚方法直接抛异常实现它们即可:

/// <summary>
/// Implement this interface to intercept method invocations with DynamicProxy2.
/// </summary>
public interface IAsyncInterceptor
{
    /// <summary>
    /// Intercepts a synchronous method <paramref name="invocation"/>.
    /// </summary>
    /// <param name="invocation">The method invocation.</param>
    void InterceptSynchronous(IInvocation invocation);

    /// <summary>
    /// Intercepts an asynchronous method <paramref name="invocation"/> with return type of <see cref="Task"/>.
    /// </summary>
    /// <param name="invocation">The method invocation.</param>
    void InterceptAsynchronous(IInvocation invocation);

    /// <summary>
    /// Intercepts an asynchronous method <paramref name="invocation"/> with return type of <see cref="Task{T}"/>.
    /// </summary>
    /// <typeparam name="TResult">The type of the <see cref="Task{T}"/> <see cref="Task{T}.Result"/>.</typeparam>
    /// <param name="invocation">The method invocation.</param>
    void InterceptAsynchronous<TResult>(IInvocation invocation);
}

基类中的属性和方法

以上两种实现方式中均包含以下属性及方法

  • T? GetAttribute(IInvocation invocation):用来获取当前方法上基类的指定特性,如上面写的AOP实现你继承的基类的泛型指定的特性是DemoAopAttribute,那么这个方法返回值就是DemoAopAttribute,支持重写

  • MethodInfo GetMethodInfo(IInvocation invocation):获取当前AOP拦截的方法信息,支持重写


以下属性仅继承了AsyncInterceptorHandler的AOP拦截类拥有

  • ExceptionHanlded:bool属性,用来指示AOP中捕获的异常是否已经处理完成,设置为已完成的则基类不会再向上级抛出异常

    true:已处理不由基类向上级抛出异常 false:未处理由基类向上级抛出异常,默认为false

  • void InternalExceptionHanlder(Exception ex):AOP方法异常捕捉

如果你没有重写以下三个方法的前提下:

  • void InterceptHandlger(IInvocation invocation, T attribute)
  • Task InterceptHandlgerAsync(IInvocation invocation, T attribute)
  • Task<TResult> InterceptHandlgerAsync<TResult>(IInvocation invocation, T attribute)

可以通过重写void InternalExceptionHanlder(Exception ex)进行捕捉AOP执行类中的异常,并对此进行处理,并与属性ExceptionHanlded进行配合来实现是否让AOP向上级抛出异常

注意:ExceptionHanldedvoid InternalExceptionHanlder(Exception ex)处理的异常仅仅是你实现的AOP拦截方法的异常,不包含被拦截方法产生的异常

例:

protected override void InternalExceptionHanlder(Exception ex)
{
    // do something
    // 请注意此处拦截的异常仅是AOP执行类内产生的异常,被拦截的方法产生的异常,AOP拦截类不会处理会直接抛出给上级
    // 异常已处理,不需要AOP向上级抛出异常
    this.ExceptionHanlded = true;
}

注册扩展

注册扩展一样有两种方式,以上述举例的DemoAsyncInterceptor为例

Autofac原生注册方式

  • 1. 注册方式
// 系统DI容器自带的方法
builder.Services.TryAddScoped<InterceptorHandler<DemoAsyncInterceptor>>();
builder.Services.TryAddScoped<DemoAsyncInterceptor>();

// Autofac模块注册的方法
builder.RegisterType<InterceptorHandler<DemoAsyncInterceptor>>().InstancePerLifetimeScope();
builder.RegisterType<DemoAsyncInterceptor>().InstancePerLifetimeScope();
  • 2. 使用扩展提供的系统DI容器扩展注册方式
builder.Services.AddCastleInterceptor<DemoAsyncInterceptor, DemoAopAttribute>();

使用Lycoris.Autofac.Extensions 扩展包进行注册

由于做当前扩展的基类的时候考虑到,有些人已经再项目中使用了原生Autofac,没有使用我做的Lycoris.Autofac.Extensions扩展包,所以基类并没做自动注册的操作,考虑后期出个扩展,此版本暂时还需要额外处理

需要手动创建一个类,并继承InterceptorHandler<TAsyncInterceptor>,其中泛型TAsyncInterceptor 即上面实现的AOP拦截

public class DemoInterceptor : InterceptorHandler<DemoAsyncInterceptor>
{
    // 不需要做任何操作
}

然后根据Lycoris.Autofac.Extensions 扩展包的使用方式,在拦截器上增加特性

[AutofacRegister(ServiceLifeTime.Scoped, IsInterceptor = true)]
public class DemoInterceptor : InterceptorHandler<DemoAsyncInterceptor>
[AutofacRegister(ServiceLifeTime.Scoped, IsInterceptor = true)]
public class DemoAsyncInterceptor : AsyncInterceptorHandler<DemoAopAttribute>

使用方式

首先找到使用AOP拦截的方法上,转到对应的接口方法上

例:我需要给TestMethod方法使用上述创建的AOP拦截

public class Test : ITest
{
    public async Task TestMethod()
    {

    }
}

找到对应的接口ITest,添加上述的特性DemoAop

public interface ITest : ITest
{
    [DemoAop]
    Task TestMethod();
}

注入AOP拦截至服务中

此处仅以Autofac举例,系统自带容器及其他第三方的容器扩展,请自行研究。

使用Autofac原生的使用方式

原生Autofac使用方式,不熟悉用法的请自己移步Autofac官网

    public class ApplicationBuilderModule : Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            builder.RegisterType(typeof(Test))
                   .As(typeof(ITest))
                   // 开启AOP拦截(需要引用包:Autofac.Extras.DynamicProxy)
                   .EnableInterfaceInterceptors()
                   // 指定拦截器
                   .InterceptedBy(typeof(InterceptorHandler<DemoAsyncInterceptor>))
                   // 生命周期
                   .InstancePerLifetimeScope();
        }
    }

使用 Lycoris.Autofac.Extensions 扩展包的注册方式,直接注册上面继承了基类的拦截器

旧版本:

public class ApplicationModule : AutofacRegisterModule
{
    public override void InterceptorRegister()
    {
        AddInterceptor<DemoInterceptor>(0);
    }
}

新版本:

 public class ApplicationModule : LycorisRegisterModule
 {
     public override void Register(LycorisModuleBuilder builder)
     {
         builder.InterceptedBy<DemoInterceptor>();
     }
 }

注意:此处需要使用AOP拦截的服务注册时候特性中的EnableInterfaceInterceptors需要设置为true

扩展还包含了简单的操作日志AOP拦截,开箱即用

使用方式

创建一个处理操作日志的类并继承OperationLogAsyncInterceptor,然后实现InterceptorOperateLoAsync方法

public class TestLog : OperationLogAsyncInterceptor
{
    public override Task InterceptorOperateLoAsync(InterceptorOperateLog log)
    {
        // log 中包含当前方法的具体位置及方法的入参,以及方法是否抛出异常等
        // 虽然此处会捕捉到异常的具体信息,但是异常仍然会照常抛出,不会影响程序原本的运行
        // do something 

        return Task.CompletedTask;
    }
}

InterceptorOperateLog入参包含以下参数:

public class InterceptorOperateLog
{
    /// <summary>
    /// 当前执行方法的类名
    /// </summary>
    public string ClassName { get; set; } 

    /// <summary>
    /// 当前执行方法的方法名
    /// </summary>
    public string MethodName { get; set; } 

    /// <summary>
    /// 当前方法上特性注明的操作名称
    /// </summary>
    public string ActionName { get; set; } 

    /// <summary>
    /// 方法入参数组 
    /// 例:Method(int a) Arguments:[a]
    /// 例:Method(Dto input) Arguments:[Dto]
    /// 例:Method(Dto input, int a) Arguments:[Dto, a]
    /// 以此类推
    /// </summary>
    public object[]? Arguments { get; set; } 

    /// <summary>
    /// 方法是否执行异常(此处的异常仅指方法是否抛出异常)
    /// </summary>
    public bool Success { get; set; } = true;

    /// <summary>
    /// 异常捕捉
    /// </summary>
    public Exception? Exception { get; set; } 
}

操作日志服务注册

  • 1. DI容器自带的注册扩展
builder.Services.AddOperateInterceptor<TestLog>();
  • 2. Autofac注册
// 基础拦截器
builder.RegisterType<OperationLogInterceptor<TestLog>>().InstancePerLifetimeScope();
// 异步拦截器
builder.RegisterType<TestLog>().InstancePerLifetimeScope();

使用方式

在需要使用操作日志的服务类上指定AOP拦截器

public class ApplicationModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        builder.RegisterType(typeof(TestServices))
               .As(typeof(ITestServices))
               // 允许AOP拦截
               .EnableInterfaceInterceptors()
               // 指定操作日志拦截器
               .InterceptedBy(typeof(OperationLogInterceptor<TestLog>))
               .InstancePerLifetimeScope();

        base.Load(builder);
    }
}

在需要记录操作日志的方法上,注明特性,并注明操作名称即可

public interface ITestServices
{
     /// <summary>
     /// 测试日志AOP
     /// </summary>
    [OperationLog(ActionName = "测试日志AOP")]
    void Test();

    int TestResult();

    int TestException();
}
Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
6.0.0 387 11/28/2022