一、AOP面向切面编程思想概述:
在C#中,AOP(Aspect Oriented Programming,面向切面编程)是一种编程模式,它允许程序员在运行时将代码注入到应用程序中,以实现横切关注点的统一管理,例如日志记录、异常处理、性能统计等。
二、实现方式
C#中实现AOP的方式通常是基于反射和委托的,主要有以下两种常见方式:
1. 使用Attribute实现AOP
C#内置特性Attribute,可以在方法或类上自定义特性,并在特性中执行一些预先定义好的动作。这种方式需要通过反射技术来查找并执行特性中的代码。
2. 使用动态代理实现AOP
动态代理是指在运行时生成代理对象以代替实际对象执行方法。使用动态代理可以通过委托实现预定义的动作,例如记录日志、处理异常等。
C#中还有一些第三方AOP框架,例如PostSharp、Castle Windsor等,它们提供了更强大的AOP支持,可以支持更复杂的剖面(Aspect)和更多的动作(Action)类型。
使用AOP可以让代码更加简洁、易于维护和扩展,同时也提高了程序的性能和可读性,是一种非常值得掌握的编程思想。
三、使用Unity动态代理实现AOP
今天我们这里就简单的讲述一下,使用Unity动态代理实现AOP。
1、引入管理Nuget包(Unity.Abstractions、Unity.Configuration、Unity.Container、Unity.Interception、Unity.Interception.Configuration)
2、简单业务叙述
我有一个商品接口查询商品的接口,在用户查询商品接口之前、我需要判断用户是否登录,只有登录了才能查看商品,同时校验代码是否有报错异常.。....大家还可以根据自己的思想添加不同业务逻辑,可扩展。
3、代码配置演示
/// <summary>
/// 查询商品接口
/// </summary>
public interface IProduct
{
void GetProduct(Users users);
}
/// <summary>
/// 接口实现
/// </summary>
public class Product : IProduct
{
/// <summary>
/// 查询商品
/// </summary>
/// <param name="users"></param>
/// <exception cref="NotImplementedException"></exception>
public void GetProduct(Users users)
{
Console.WriteLine("我是用户登录之后查询到的商品: A");
}
}
/// <summary>
/// 用户类
/// </summary>
public class Users
{
public string Id { get; set; }
public string Name { get; set; }
public string Password { get; set; }
}
/// <summary>
/// Unity实现AOP
/// 固定写法,复制粘贴即可
/// </summary>
public class UtityConfigAOP
{
/// <summary>
/// Unity实现AOP
/// 固定写法,复制粘贴即可
/// 参数根据自己的业务逻辑可变更
/// </summary>
/// <param name="users">用户</param>
public static void Find(Users users)
{
//配置IUnityContainer信息
IUnityContainer container = new UnityContainer();
ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
//读取Unity.Config文件地址
//AOP_Unity_Config\\Unity.Config配置文件的地址,代码生成后 bin目录下的地址
fileMap.ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + "AOP_Unity_Config\\Unity.Config");
/**
*打开给定映射文件的exe.config文件。
*用于动态修改应用程序的配置文件,
*或者在运行时加载另一个配置文件。
*它接受一个ConfigurationFileMap参数,
*该参数描述了可访问的配置文件以及它们的位置。
*该方法返回一个Configuration对象,该对象表示指定配置文件的完整内容。
*/
Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
/**
* UnityConfigurationSection 是Unity IOC容器提供的配置节。
* 它负责加载和解析应用程序的配置文件中的Unity IOC配置节,并创建容器实例,以便在应用程序中进行依赖注入操作。
* 配置节是应用程序配置文件(例如app.config或web.config)中的一个特殊部分,它允许您指定应用程序的配置信息。
* UnityConfigurationSection是在应用程序配置文件中指定Unity容器的信息的部分。
* 它定义了如何注册和构造类,并描述了容器应如何配置各种对象的行为。
* UnityConfigurationSection使得在应用程序中实现依赖注入更加容易,
* 因为它提供了一种简单的方式来配置Unity容器,而不必在代码中编写依赖注入的配置。
*
* 简单的来说:这一行就是去config文件种找unity名称的配置信息,进行读取
*/
UnityConfigurationSection configurationSection = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName);
//AopContainer 自己定义的配置文件节段名称
configurationSection.Configure(container, "AopContainer");
//对IProduct接口进行AOP配置
//大家也可以根据自己的业务逻辑进行变更,因为此处我是对查询商品接口进行验证,所以Resolve<IProduct>
IProduct product = container.Resolve<IProduct>();
product.GetProduct(users);
}
}
<!--这是我的Unity.Config配置文件-->
<configuration>
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Unity.Configuration"/>
</configSections>
<unity>
<sectionExtension type ="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Unity.Interception.Configuration"/>
<containers><!--容器-->
<container name="AopContainer">
<extension type ="Interception" />
<register type ="YDTFileTest.AOP.IProduct,YDTFileTest"
mapTo="YDTFileTest.AOP.Product,YDTFileTest">
<interceptor type ="InterfaceInterceptor"/>
<!--参数校验-->
<interceptionBehavior type ="YDTFileTest.AOP.ParameterCheckBehavior, YDTFileTest"/>
<!--代码异常校验-->
<interceptionBehavior type="YDTFileTest.AOP.ExceptionLoggingBehavior, YDTFileTest"/>
</register>
</container>
</containers>
</unity>
</configuration>
/// <summary>
/// 参数校验类,必须继承IInterceptionBehavior
/// </summary>
public class ParameterCheckBehavior : IInterceptionBehavior
{
/// <summary>
/// 固定写法不用管,继承IInterceptionBehavior 自动生成的
/// </summary>
/// <returns></returns>
public bool WillExecute { get { return true; } }
/// <summary>
/// 固定写法不用管,继承IInterceptionBehavior 自动生成的
/// </summary>
/// <returns></returns>
public IEnumerable<Type> GetRequiredInterfaces()
{
return Type.EmptyTypes;
}
/// <summary>
/// 只需要在这个方法中书写逻辑, 继承IInterceptionBehavior 自动生成的
/// </summary>
/// <param name="input"></param>
/// <param name="getNext"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
Console.WriteLine("开始参数校验");
Users user = input.Inputs[0] as Users;
if (user.Name != "小王" || user.Password != "123")
{
Console.WriteLine("用户名密码不正确");
//创建一个异常信息并抛出
return input.CreateExceptionMethodReturn(new Exception("用户名密码不正确"));
}
else
{
Console.WriteLine("参数检测无误");
//执行config中下下一个AOP配置校验
return getNext().Invoke(input, getNext);
}
}
/// <summary>
/// 代码异常校验具体实现,必须继承IInterceptionBehavior
/// </summary>
public class ExceptionLoggingBehavior : IInterceptionBehavior
{
/// <summary>
/// 固定写法不用管,继承IInterceptionBehavior 自动生成的
/// </summary>
/// <returns></returns>
public bool WillExecute { get { return true; } }
/// <summary>
/// 固定写法不用管,继承IInterceptionBehavior 自动生成的
/// </summary>
/// <returns></returns>
public IEnumerable<Type> GetRequiredInterfaces()
{
return Type.EmptyTypes;
}
/// <summary>
/// 只需要在这个方法中书写逻辑, 继承IInterceptionBehavior 自动生成的
/// </summary>
/// <param name="input"></param>
/// <param name="getNext"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
Console.WriteLine("开始异常校验");
IMethodReturn methodReturn = getNext()(input, getNext);
if (methodReturn.Exception == null)
{
Console.WriteLine("无异常");
}
else
{
Console.WriteLine($"异常:{methodReturn.Exception.Message}");
}
return methodReturn;
}
4、代码调用演示
//直接调用配置的Find方法进行验证,通过则自动记录日志等,并调用查看商品接口
public static void Load()
{
Users user = new Users()
{
Id = "1",
Name = "小王",
Password = "123",
};
UtityConfigAOP.Find(user);
}
如上图,可以看到我们已经成功的实现了AOP动态代理拦截器的生成了,如果后续还需要添加什么验证,只需要在配置文件添加<interceptionBehavior type="文件所在项目路径, 项目名称"/>,并跟上面登录、异常验证一样只需继承IInterceptionBehavior并实现,在Invoke方法中写自己需要的逻辑即可,非常的方便,并且不会影响到之前的代码逻辑!
今天的分享就到这里了,大家还有更好的实现AOP的方式,欢迎到评论区讨论!!!