具有 DispatchProxy 类的面向方面范例示例

发布:2024-10-25 15:10 阅读:24 点赞:0

在本文中,我们将探讨如何使用动态代理类实现跨切关注点(CCC)。在.NET环境中,有多种AOP实现方式。我们主要关注通过代理对象调度任何类。

一. AOP 和跨切关注点概述

AOP(面向方面编程)是一种提供更好模块化的范式,通过分离关注点(SoC)来提高代码的松耦合性。这意味着我们可以在不修改现有代码的情况下添加可重用的代码。

在本示例中,我们将使用DispatchProxy类,该类在System.Reflection命名空间中作为.NET Standard库的一部分创建。

二. 跨切关注点示例

DispatchProxy类基于接口工作。它提供了动态包装任何类型的能力,允许在方法调用时添加额外的代码实现。

虽然我们理解了DispatchProxy是什么,但需要注意的是,早期的替代方案RealProxy类也提供了类似功能,但功能更强大。RealProxy支持跨进程远程调用,而DispatchProxy则不支持。

2.1 示例服务接口

假设我们有两个不同的应用服务:EmailMessageSenderServerInfoRetriever。这些名称直观地反映了它们的功能。

public interface IEmailMessageSender
{
    public bool TrySendMessage(string to, string subject, string message);
}

public class EmailMessageSender : IEmailMessageSender
{
    // 模拟发送邮件
    public bool TrySendMessage(string to, string subject, string message)
    {
        Console.WriteLine($"消息已发送到 {to}");
        return true// 返回假信息
    }
}
public record ServerInfo(string State, DateTime ActivationDate, string Version);

public interface IServerInfoRetriever
{
    public ServerInfo GetInfo(IPAddress address);
}

public class ServerInfoRetriever : IServerInfoRetriever
{
    // 模拟获取服务器信息
    public ServerInfo GetInfo(IPAddress address)
    {
        Console.WriteLine($"{address.ToString()} 服务器信息已检索!");
        return new ServerInfo("处理中", DateTime.Now, "1.0.0"); // 返回假信息
    }
}

三. 实现 DispatchProxy

要实现我们的DispatchProxy,我们应从其派生并在其中实现逻辑。

public class LoggingDecoratorProxy<T> : DispatchProxy
{
    private readonly Logger _logger; // 日志记录器
    public T Target { getinternal set; } // 目标对象

    public LoggingDecoratorProxy() : base()
    {
        _logger = new LoggerConfiguration()
            .WriteTo.Console().CreateLogger(); // 使用Serilog创建日志记录器
    }

    protected override object? Invoke(MethodInfo? targetMethod, object?[]? args)
    {
        try
        {
            // 记录方法调用信息
            _logger.Information("{TypeName}.{MethodName}({Arguments})", targetMethod.DeclaringType.Name, targetMethod.Name, args);
            var result = targetMethod.Invoke(Target, args); // 调用目标对象的方法
            // 记录方法返回值
            _logger.Information("{TypeName}.{MethodName} returned -> {ReturnValue}", targetMethod.DeclaringType.Name, targetMethod.Name, result);
            return result; // 返回结果
        }
        catch (TargetInvocationException exc)
        {
            // 记录异常信息
            _logger.Warning(exc.InnerException, "{TypeName}.{MethodName} threw exception: {Exception}", targetMethod.DeclaringType.Name, targetMethod.Name, exc.InnerException);
            throw exc.InnerException; // 抛出原始异常
        }
    }
}

3.1 创建工厂方法

我们还需要一个工厂方法来创建带有日志记录的跨切关注点的代理对象。

public static class LoggingDecoratorProxyFactory
{
    public static TInterface Create<TInterface, TConcrete>(TConcrete instance) where TConcrete : classTInterface where TInterface : class
    {
        if (!typeof(TInterface).IsInterface)
            throw new Exception($"{typeof(TInterface).Name} 必须是一个接口!");

        // 创建代理对象
        LoggingDecoratorProxy<TInterface> proxy = LoggingDecoratorProxy<TInterface>.Create<TInterface, LoggingDecoratorProxy<TInterface>>() 
                    as LoggingDecoratorProxy<TInterface>;
        proxy.Target = instance; // 设置目标对象
        return proxy as TInterface; // 返回代理对象
    }
}

四. 应用示例

现在,我们可以运行我们的应用并获取结果。

// 创建邮件发送服务的代理对象
IEmailMessageSender emailSender = LoggingDecoratorProxyFactory.Create<IEmailMessageSender, EmailMessageSender>(new EmailMessageSender());
emailSender.TrySendMessage("resulhsn@gmail.com""测试""嗨,Rasul");

Console.WriteLine("------------------------------------------------------------------------------------------");

// 创建服务器信息检索服务的代理对象
IServerInfoRetriever retriever = LoggingDecoratorProxyFactory.Create<IServerInfoRetriever, ServerInfoRetriever>(new ServerInfoRetriever());
retriever.GetInfo(IPAddress.Parse("127.0.0.1"));

4.1 控制台输出

在我们的示例中,创建了一个跨切关注点(日志记录调用),并通过DispatchProxy动态装饰了任何对象。这表明,DispatchProxy允许我们在运行时以所需的类型实现AOP。

五. 结论

  1. DispatchProxy类是.NET生态系统中一个强大的工具,用于创建动态代理,允许开发者在运行时拦截和修改方法调用。
  2. 这种能力使得可以灵活、清晰地实现跨切关注点,如日志记录、缓存和性能监控,而不会污染核心业务逻辑。
  3. 通过利用DispatchProxy,开发者可以保持模块化和解耦的代码库,增强可维护性和可扩展性。