Préface : Cet article est destiné à parler d'AOP. En fait, le blogueur n'a été exposé à ce concept que depuis quelques mois. Après l'avoir compris, j'ai réalisé que bon nombre des principes de code que j'avais écrits auparavant. étaient basés sur AOP, comme le filtrage MVC, la capture des exceptions peut être traitée via FilterAttribute et IExceptionFilter. Le principe interne du mécanisme de traitement de ces deux objets devrait être AOP, mais un tel concept n'existait pas auparavant.
1. Concept AOP
Anciennes règles, regardons d'abord l'explication officielle : AOP ( Programmation orientée aspect (programmation orientée aspect), c'est une technologie qui peut ajouter dynamiquement et uniformément des fonctions au programme sans modifier le code source via la pré-compilation et les agents dynamiques d'exécution. Il s'agit d'une nouvelle méthodologie qui complète la programmation POO traditionnelle. La POO se concentre sur la division des fonctions requises en classes différentes, relativement indépendantes et bien encapsulées, et leur permet d'avoir leurs propres comportements, en s'appuyant sur l'héritage et le polymorphisme pour définir leurs relations ; AOP espère pouvoir transformer les fonctions générales requises en séparant les classes liées ; permet à plusieurs classes de partager un comportement. Une fois qu'un changement se produit, il n'est pas nécessaire de modifier plusieurs classes, mais seulement le comportement. L'AOP utilise des aspects pour modulariser les préoccupations transversales, et la POO utilise des classes pour modulariser l'état et le comportement. Dans le monde de la POO, les programmes sont organisés en classes et en interfaces, et il est très approprié de les utiliser pour implémenter la logique métier de base du programme. Cependant, il est très difficile de mettre en œuvre des préoccupations transversales (exigences fonctionnelles qui s'étendent sur plusieurs modules de l'application), telles que la journalisation, la vérification des autorisations, l'interception des exceptions, etc.
Compréhension du blogueur : AOP extrait les fonctions communes. Si les exigences des fonctions communes changent à l'avenir, il vous suffit de modifier le code des modules communs. n'a pas besoin d'être modifié. Ce que l'on appelle l'orientation aspect signifie que nous nous concentrons uniquement sur les fonctions générales et non sur la logique métier. La mise en œuvre se fait généralement par interception. Par exemple, n'importe lequel de nos projets Web dispose essentiellement d'une fonction de vérification des autorisations. Avant d'accéder à chaque page, il vérifiera si l'utilisateur actuellement connecté a l'autorisation de visualiser l'interface. Il nous est impossible d'écrire ce paragraphe dans la méthode d'initialisation de. chaque page. Code de vérification, c'est à ce moment-là que notre AOP est utile. Le mécanisme de l'AOP consiste à prédéfinir un ensemble de caractéristiques afin qu'il ait la fonction d'intercepter les méthodes, vous permettant de faire les affaires que vous souhaitez faire auparavant et. après avoir exécuté la méthode, et lorsque nous l'utilisons, il nous suffit d'ajouter une certaine fonctionnalité à la méthode ou à la définition de classe correspondante.
2. Avantages de l'utilisation de l'AOP
Le blogueur pense que ses avantages se reflètent principalement dans :
1. En extrayant la logique, une grande quantité de code répété peut être omise, ce qui est bénéfique pour le fonctionnement et la maintenance du code.
2. Lors de la conception de logiciels, l'extraction de fonctions (aspects) communes est propice à la modularisation de la conception logicielle et réduit la complexité de l'architecture logicielle. En d’autres termes, les fonctions générales constituent un module distinct et les codes de conception de ces fonctions générales ne sont pas visibles dans l’activité principale du projet.
3. Application simple de l'AOP
Afin d'expliquer le principe de fonctionnement de l'AOP, le blogueur prévoit de commencer par un exemple simple pour comprendre comment fonctionne l'AOP grâce à l'interception statique.
1. Interception statique
public class Order { public int Id { set; get; } public string Name { set; get; } public int Count { set; get; } public double Price { set; get; } public string Desc { set; get; } } public interface IOrderProcessor { void Submit(Order order); } public class OrderProcessor : IOrderProcessor { public void Submit(Order order) { Console.WriteLine("提交订单"); } } public class OrderProcessorDecorator : IOrderProcessor { public IOrderProcessor OrderProcessor { get; set; } public OrderProcessorDecorator(IOrderProcessor orderprocessor) { OrderProcessor = orderprocessor; } public void Submit(Order order) { PreProceed(order); OrderProcessor.Submit(order); PostProceed(order); } public void PreProceed(Order order) { Console.WriteLine("提交订单前,进行订单数据校验...."); if (order.Price 0) { Console.WriteLine("订单总价有误,请重新核对订单。"); } } public void PostProceed(Order order) { Console.WriteLine("提交带单后,进行订单日志记录......"); Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "提交订单,订单名称:" + order.Name + ",订单价格:" + order.Price); } }
Code d'appel :
static void Main(string[] args) { Order order = new Order() { Id = 1, Name = "lee", Count = 10, Price = 100.00, Desc = "订单测试" }; IOrderProcessor orderprocessor = new OrderProcessorDecorator(new OrderProcessor()); orderprocessor.Submit(order); Console.ReadLine(); }
Obtenir le résultat :
上面我们模拟订单提交的例子,在提交一个订单前,我们需要做很多的准备工作,比如数据有效性校验等;订单提交完成之后,我们还需要做日志记录等。上面的代码很简单,没有任何复杂的逻辑,从上面的代码可以看出,我们通过静态植入的方式手动在执行方法前和执行方法后让它做一些我们需要的功能。AOP的实现原理应该也是如此,只不过它帮助我们做了方法拦截,帮我们省去了大量重复代码,我们要做的仅仅是写好拦截前和拦截后需要处理的逻辑。
2、动态代理
了解了静态拦截的例子,你是否对AOP有一个初步的认识了呢。下面我们就来到底AOP该如何使用。按照园子里面很多牛人的说法,AOP的实现方式大致可以分为两类:动态代理和IL 编织两种方式。博主也不打算照本宣科,分别拿Demo来说话吧。下面就以两种方式各选一个代表框架来说明。
动态代理方式,博主就以微软企业库(MS Enterprise Library)里面的PIAB(Policy Injection Application Block)框架来作说明。
首先需要下载以下几个dll,然后添加它们的引用。
然后定义对应的Handler
public class User { public string Name { set; get; } public string PassWord { set; get; } } #region 1、定义特性方便使用 public class LogHandlerAttribute : HandlerAttribute { public string LogInfo { set; get; } public int Order { get; set; } public override ICallHandler CreateHandler(IUnityContainer container) { return new LogHandler() { Order = this.Order, LogInfo = this.LogInfo }; } } #endregion #region 2、注册对需要的Handler拦截请求 public class LogHandler : ICallHandler { public int Order { get; set; } public string LogInfo { set; get; } //这个方法就是拦截的方法,可以规定在执行方法之前和之后的拦截 public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext) { Console.WriteLine("LogInfo内容" + LogInfo); //0.解析参数 var arrInputs = input.Inputs; if (arrInputs.Count > 0) { var oUserTest1 = arrInputs[0] as User; } //1.执行方法之前的拦截 Console.WriteLine("方法执行前拦截到了"); //2.执行方法 var messagereturn = getNext()(input, getNext); //3.执行方法之后的拦截 Console.WriteLine("方法执行后拦截到了"); return messagereturn; } } #endregion #region 3、用户定义接口和实现 public interface IUserOperation { void Test(User oUser); void Test2(User oUser, User oUser2); } //这里必须要继承这个类MarshalByRefObject,否则报错 public class UserOperation : MarshalByRefObject, IUserOperation { private static UserOperation oUserOpertion = null; public UserOperation() { //oUserOpertion = PolicyInjection.Create(); } //定义单例模式将PolicyInjection.Create()产生的这个对象传出去,这样就避免了在调用处写这些东西 public static UserOperation GetInstance() { if (oUserOpertion == null) oUserOpertion = PolicyInjection.Create(); return oUserOpertion; } //调用属性也会拦截 public string Name { set; get; } //[LogHandler],在方法上面加这个特性,只对此方法拦截 [LogHandler(LogInfo = "Test的日志为aaaaa")] public void Test(User oUser) { Console.WriteLine("Test方法执行了"); } [LogHandler(LogInfo = "Test2的日志为bbbbb")] public void Test2(User oUser, User oUser2) { Console.WriteLine("Test2方法执行了"); } } #endregion
最后我们来看调用的代码:
static void Main(string[] args) { try { var oUserTest1 = new User() { Name = "test2222", PassWord = "yxj" }; var oUserTest2 = new User() { Name = "test3333", PassWord = "yxj" }; var oUser = UserOperation.GetInstance(); oUser.Test(oUserTest1); oUser.Test2(oUserTest1,oUserTest2); } catch (Exception ex) { //throw; } }
得到结果如下:
我们来看执行Test()方法和Test2()方法时候的顺序。
由于Test()和Test2()方法上面加了LogHander特性,这个特性里面定义了AOP的Handler,在执行Test和Test2方法之前和之后都会进入Invoke()方法里面。其实这就是AOP的意义所在,将切面的通用功能在统一的地方处理,在主要逻辑里面直接用过特性使用即可。
3、IL编织
静态织入的方式博主打算使用PostSharp来说明,一来这个使用起来简单,二来项目中用过这种方式。
Postsharp从2.0版本就开始收费了。为了说明AOP的功能,博主下载了一个免费版本的安装包,使用PostSharp与其它框架不太一样的是一定要下载安装包安装,只引用类库是不行的,因为上文说过,AOP框架需要为编译器或运行时添加扩展。使用步骤如下:
(1)下载Postsharp安装包,安装。
(2)在需要使用AOP的项目中添加PostSharp.dll 这个dll的引用。
(3)定义拦截的方法:
[Serializable] public class TestAop : PostSharp.Aspects.OnMethodBoundaryAspect { //发生异常时进入此方法 public override void OnException(MethodExecutionArgs args) { base.OnException(args); } //执行方法前执行此方法 public override void OnEntry(MethodExecutionArgs args) { base.OnEntry(args); } //执行方法后执行此方法 public override void OnExit(MethodExecutionArgs args) { base.OnExit(args); } }
注意这里的TestAop这个类必须要是可序列化的,所以要加上[Serializable]特性
(4)在需要拦截功能的地方使用。
在类上面加特性拦截,此类下面的所有的方法都会具有拦截功能。
[TestAop]public class Impc_TM_PLANT : Ifc_TM_PLANT { /// /// 获取或设置服务接口。 /// private Ic_TM_PLANTService service { get; set; } public IList Find() { DTO_TM_PLANT otest = null; otest.NAME_C = "test"; //异常,会进入OnException方法 return service.FindAll(); } }
方法上面加特性拦截,只会拦截此方法。
[TestAop] public IList Find() { DTO_TM_PLANT otest = null; otest.NAME_C = "test"; return service.FindAll(); }
有没有感觉很简单,很强大,其实这一简单应用,解决我们常见的日志、异常、权限验证等功能简直太小菜一碟了。当然Postsharp可能还有许多更加高级的功能,有兴趣可以深究下。
4、MVC里面的Filter
public class AOPFilterAttribute : ActionFilterAttribute, IExceptionFilter { public void OnException(ExceptionContext filterContext) { throw new System.NotImplementedException(); } public override void OnActionExecuting(ActionExecutingContext filterContext) { base.OnActionExecuting(filterContext); } public override void OnActionExecuted(ActionExecutedContext filterContext) { base.OnActionExecuted(filterContext); } }
在controller里面使用该特性:
[AOPFilter] public JsonResult GetEditModel(string strType) { var lstRes = new List>(); var lstResPage = new List(); //.........todo return Json(new { lstDataAttr = lstRes, PageAttr = lstResPage, lstJsConnections = lstJsPlumbLines }, JsonRequestBehavior.AllowGet); }
调试可知,在执行GetEditModel(string strType)方法之前,会先执行OnActionExecuting()方法,GetEditModel(string strType)之后,又会执行OnActionExecuted()方法。这在我们MVC里面权限验证、错误页导向、日志记录等常用功能都可以方便解决。
Ce qui précède est la série avancée C# - AOP ? AOP! Pour plus de contenu connexe, veuillez prêter attention au site Web PHP chinois (www.php.cn) !