聊一聊如何整合Microsoft.Extensions.DependencyInjection和Castle.Core(三)

发布时间 2024-01-13 20:20:29作者: 漫思

聊一聊如何整合Microsoft.Extensions.DependencyInjection和Castle.Core(三)

 

前言

今天的第三篇,感觉没啥人看呀,难道没有兄弟跟我有同样的整合需求吗???手动image
image
image
本文会简短一些,介绍下 CastleCore 作为代理库的一些缺点甚至是硬伤

异步支持

先上代码

/// <summary>
/// 异常捕获、日志记录和耗时监控 拦截器 2024-1-12 21:28:22
/// </summary>
public class CatchLoggingInterceptor : IInterceptor
{
    public  void Intercept(IInvocation invocation)
    {
        //TODO:类注释所写的逻辑
        Console.WriteLine("Interceptor  starting...");
        invocation.Proceed();
        Console.WriteLine("Interceptor  ended...");
    }     
}

如上是一个最简单的 CastleCore 拦截器示例,为了该拦截器能在使用的时候可以直接标注在方法上使用,为我们做如下改动:

/// <summary>
/// 异常捕获、日志记录和耗时监控 拦截器 2024-1-12 21:28:22
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public class CatchLoggingInterceptor : Attribute, IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        //TODO:类注释所写的逻辑
        Console.WriteLine("Interceptor  starting...");
        invocation.Proceed();
        Console.WriteLine("Interceptor  ended...");
    }
}

public class SampleService : ISampleService
{
    [CatchLoggingInterceptor]
    public virtual Task<string> ShowAsync()
    {
        Console.WriteLine(nameof(ShowAsync));
        return Task.FromResult(nameof(ShowAsync));
    }
}

public interface ISampleService
{
    [CatchLoggingInterceptor]
    Task<string> ShowAsync();
}

使用代码如下

 public static async Task Main(string[] args)
{
    var services = new ServiceCollection();
    services.AddLogging();//此处添加日志服务 伪代码 以便获取ILogger<SampleService>
    services.TryAddSingleton(sp => new ProxyGenerator());
    services.TryAddTransient<SampleService>();
    services.TryAddTransient<ISampleService, SampleService>();
    var sp = services.BuildServiceProvider();

    var generator = sp.GetRequiredService<ProxyGenerator>();
    var instance = sp.GetRequiredService<SampleService>();
    var proxy = generator.CreateClassProxyWithTarget(typeof(SampleService), instance, new CatchLoggingInterceptor()) as SampleService;
    var name = await proxy.ShowAsync();
}

输入如图所示:image

name也可以正常取到值,没问题
看下拦截器的定义 ,我们全部是同步方法,要知道dotnetcore下是推荐所有方法都是异步的, 我们对拦截器做如下改造:

public void Intercept(IInvocation invocation)
{
    invocation.ReturnValue = IntercetpAsync(invocation);
}

private async Task IntercetpAsync(IInvocation invocation)
{
    //TODO:类注释所写的逻辑
    await Console.Out.WriteLineAsync("Interceptor  starting...");
    Console.WriteLine("Interceptor  starting...");
    invocation.Proceed();
    await Console.Out.WriteLineAsync("Interceptor  ended...");
}

如上,拦截器里面使用Console.Out执行了异步方法的拦截,再执行
image
image

此时引出 Castle代理的致命的问题:拦截方法默认无法异步
针对此问题,官方也已显式标明,并提供了具体的解决办法

https://github.com/castleproject/Core/blob/master/docs/dynamicproxy-async-interception.md

这里我推荐 https://www.nuget.org/packages/stakx.DynamicProxy.AsyncInterceptor 的处理办法

其他缺点

  • 拦截器内如何可以使用ioc的生态获取已经有的各项功能服务
  • 某些场景下拦截器是需要传入常量 比方说,操作日志拦截,方法1 可能需要 Name="方法1",而方法二额需要 Name="方法2"

综上

上面三个缺点都是CastleCore 的硬伤,我们都要克服,后文会陆续解决这些问题,请各位看官拭目以待。写文很累,各位能不能dian点个star呢?您的鼓励会让我信心倍增,更新更快。

本文示例代码已上传至 https://gitee.com/gainorloss_259/microsoft-castle.git