如何利用C#實(shí)現(xiàn)AOP-創(chuàng)新互聯(lián)

這篇文章主要介紹了如何利用C#實(shí)現(xiàn)AOP,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

為企業(yè)提供成都網(wǎng)站設(shè)計(jì)、成都做網(wǎng)站、網(wǎng)站優(yōu)化、全網(wǎng)營(yíng)銷(xiāo)推廣、競(jìng)價(jià)托管、品牌運(yùn)營(yíng)等營(yíng)銷(xiāo)獲客服務(wù)。創(chuàng)新互聯(lián)擁有網(wǎng)絡(luò)營(yíng)銷(xiāo)運(yùn)營(yíng)團(tuán)隊(duì),以豐富的互聯(lián)網(wǎng)營(yíng)銷(xiāo)經(jīng)驗(yàn)助力企業(yè)精準(zhǔn)獲客,真正落地解決中小企業(yè)營(yíng)銷(xiāo)獲客難題,做到“讓獲客更簡(jiǎn)單”。自創(chuàng)立至今,成功用技術(shù)實(shí)力解決了企業(yè)“網(wǎng)站建設(shè)、網(wǎng)絡(luò)品牌塑造、網(wǎng)絡(luò)營(yíng)銷(xiāo)”三大難題,同時(shí)降低了營(yíng)銷(xiāo)成本,提高了有效客戶(hù)轉(zhuǎn)化率,獲得了眾多企業(yè)客戶(hù)的高度認(rèn)可!

AOP為Aspect Oriented Programming的縮寫(xiě),意為:面向切面編程,通過(guò)預(yù)編譯方式和運(yùn)行期動(dòng)態(tài)代理實(shí)現(xiàn)程序功能的中統(tǒng)一處理業(yè)務(wù)邏輯的一種技術(shù),比較常見(jiàn)的場(chǎng)景是:日志記錄,錯(cuò)誤捕獲、性能監(jiān)控等

AOP的本質(zhì)是通過(guò)代理對(duì)象來(lái)間接執(zhí)行真實(shí)對(duì)象,在代理類(lèi)中往往會(huì)添加裝飾一些額外的業(yè)務(wù)代碼,比如如下代碼:

 class RealA
 {
 public virtual string Pro { get; set; }
 
 public virtual void ShowHello(string name)
 {
 Console.WriteLine($"Hello!{name},Welcome!");
 }
 }
 
 
//調(diào)用:
 
 var a = new RealA();
 a.Pro = "測(cè)試";
 a.ShowHello("夢(mèng)在旅途");

這段代碼很簡(jiǎn)單,只是NEW一個(gè)對(duì)象,然后設(shè)置屬性及調(diào)用方法,但如果我想在設(shè)置屬性前后及調(diào)用方法前后或報(bào)錯(cuò)都能收集日志信息,該如何做呢?可能大家會(huì)想到,在設(shè)置屬性及調(diào)用方法前后都加上記錄日志的代碼不就可以了,雖然這樣是可以,但如果很多地方都要用到這個(gè)類(lèi)的時(shí)候,那重復(fù)的代碼是否太多了一些吧,所以我們應(yīng)該使用代理模式或裝飾模式,將原有的真實(shí)類(lèi)RealA委托給代理類(lèi)ProxyRealA來(lái)執(zhí)行,代理類(lèi)中在設(shè)置屬性及調(diào)用方法時(shí),再添加記錄日志的代碼就可以了,這樣可以保證代碼的干凈整潔,也便于代碼的后期維護(hù)。(注意,在C#中若需被子類(lèi)重寫(xiě),父類(lèi)必需是虛方法或虛屬性virtual)

如下代碼:

class ProxyRealA : RealA
 {
 
 public override string Pro
 {
 get
 {
 return base.Pro;
 }
 set
 {
 ShowLog("設(shè)置Pro屬性前日志信息");
 base.Pro = value;
 ShowLog($"設(shè)置Pro屬性后日志信息:{value}");
 }
 }
 
 public override void ShowHello(string name)
 {
 try
 {
 ShowLog("ShowHello執(zhí)行前日志信息");
 base.ShowHello(name);
 ShowLog("ShowHello執(zhí)行后日志信息");
 }
 catch(Exception ex)
 {
 ShowLog($"ShowHello執(zhí)行出錯(cuò)日志信息:{ex.Message}");
 }
 }
 
 private void ShowLog(string log)
 {
 Console.WriteLine($"{DateTime.Now.ToString()}-{log}");
 }
 }
 
 
//調(diào)用:
 var aa = new ProxyRealA();
 aa.Pro = "測(cè)試2";
 aa.ShowHello("zuowenjun.cn");

這段代碼同樣很簡(jiǎn)單,就是ProxyRealA繼承自RealA類(lèi),即可看成是ProxyRealA代理RealA,由ProxyRealA提供各種屬性及方法調(diào)用。這樣在ProxyRealA類(lèi)內(nèi)部屬性及方法執(zhí)行前后都有統(tǒng)一記錄日志的代碼,不論在哪里用這個(gè)RealA類(lèi),都可以直接用ProxyRealA類(lèi)代替,因?yàn)槔锸咸鎿Q原則,父類(lèi)可以被子類(lèi)替換,而且后續(xù)若想更改日志記錄代碼方式,只需要在ProxyRealA中更改就行了,這樣所有用到的ProxyRealA類(lèi)的日志都會(huì)改變,是不是很爽。

上述執(zhí)行結(jié)果如下圖示:

如何利用C#實(shí)現(xiàn)AOP

以上通過(guò)定義代理類(lèi)的方式能夠?qū)崿F(xiàn)在方法中統(tǒng)一進(jìn)行各種執(zhí)行點(diǎn)的攔截代碼邏輯處理,攔截點(diǎn)(或者稱(chēng)為:橫切面,切面點(diǎn))一般主要為:執(zhí)行前,執(zhí)行后,發(fā)生錯(cuò)誤,雖然解決了之前直接調(diào)用真實(shí)類(lèi)RealA時(shí),需要重復(fù)增加各種邏輯代碼的問(wèn)題,但隨之而來(lái)的新問(wèn)題又來(lái)了,那就是當(dāng)一個(gè)系統(tǒng)中的類(lèi)非常多的時(shí)候,如果我們針對(duì)每個(gè)類(lèi)都定義一個(gè)代理類(lèi),那么系統(tǒng)的類(lèi)的個(gè)數(shù)會(huì)成倍增加,而且不同的代理類(lèi)中可能某些攔截業(yè)務(wù)邏輯代碼都是相同的,這種情況同樣是不能允許的,那有沒(méi)有什么好的辦法呢?答案是肯定的,以下是我結(jié)合網(wǎng)上資源及個(gè)人總結(jié)的如下幾種常見(jiàn)的實(shí)現(xiàn)AOP的方式,各位可以參考學(xué)習(xí)。

第一種:靜態(tài)織入,即:在編譯時(shí),就將各種涉及AOP攔截的代碼注入到符合一定規(guī)則的類(lèi)中,編譯后的代碼與我們直接在RealA調(diào)用屬性或方法前后增加代碼是相同的,只是這個(gè)工作交由編譯器來(lái)完成。

PostSharp:PostSharp的Aspect是使用Attribute實(shí)現(xiàn)的,我們只需事先通過(guò)繼承自O(shè)nMethodBoundaryAspect,然后重寫(xiě)幾個(gè)常見(jiàn)的方法即可,如:OnEntry,OnExit等,最后只需要在需要進(jìn)行AOP攔截的屬性或方法上加上AOP攔截特性類(lèi)即可。由于PostSharp是靜態(tài)織入的,所以相比其它的通過(guò)反射或EMIT反射來(lái)說(shuō)效率是最高的,但PostSharp是收費(fèi)版本的,而且網(wǎng)上的教程比較多,我就不在此重復(fù)說(shuō)明了。

第二種:EMIT反射,即:通過(guò)Emit反射動(dòng)態(tài)生成代理類(lèi),如下Castle.DynamicProxy的AOP實(shí)現(xiàn)方式,代碼也還是比較簡(jiǎn)單的,效率相對(duì)第一種要慢一點(diǎn),但對(duì)于普通的反射來(lái)說(shuō)又高一些,代碼實(shí)現(xiàn)如下:

using Castle.Core.Interceptor;
using Castle.DynamicProxy;
using NLog;
using NLog.Config;
using NLog.Win32.Targets;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace ConsoleApp
{
 class Program
 {
 static void Main(string[] args)
 {
 ProxyGenerator generator = new ProxyGenerator();
 var test = generator.CreateClassProxy<TestA>(new TestInterceptor());
 Console.WriteLine($"GetResult:{test.GetResult(Console.ReadLine())}");
 test.GetResult2("test");
 Console.ReadKey();
 }
 }
 
 public class TestInterceptor : StandardInterceptor
 {
 private static NLog.Logger logger;
 
 protected override void PreProceed(IInvocation invocation)
 {
 Console.WriteLine(invocation.Method.Name + "執(zhí)行前,入?yún)ⅲ?quot; + string.Join(",", invocation.Arguments));
 }
 
 protected override void PerformProceed(IInvocation invocation)
 {
 Console.WriteLine(invocation.Method.Name + "執(zhí)行中");
 try
 {
 base.PerformProceed(invocation);
 }
 catch (Exception ex)
 {
 HandleException(ex);
 }
 }
 
 protected override void PostProceed(IInvocation invocation)
 {
 Console.WriteLine(invocation.Method.Name + "執(zhí)行后,返回值:" + invocation.ReturnValue);
 }
 
 private void HandleException(Exception ex)
 {
 if (logger == null)
 {
 LoggingConfiguration config = new LoggingConfiguration();
 
 ColoredConsoleTarget consoleTarget = new ColoredConsoleTarget();
 consoleTarget.Layout = "${date:format=HH\\:MM\\:ss} ${logger} ${message}";
 config.AddTarget("console", consoleTarget);
 
 LoggingRule rule1 = new LoggingRule("*", LogLevel.Debug, consoleTarget);
 config.LoggingRules.Add(rule1);
 LogManager.Configuration = config;
 
 logger = LogManager.GetCurrentClassLogger(); //new NLog.LogFactory().GetCurrentClassLogger();
 }
 logger.ErrorException("error",ex);
 }
 }
 
 public class TestA
 {
 public virtual string GetResult(string msg)
 {
 string str = $"{DateTime.Now.ToString("yyyy-mm-dd HH:mm:ss")}---{msg}";
 return str;
 }
 
 public virtual string GetResult2(string msg)
 {
 throw new Exception("throw Exception!");
 }
 }
}

簡(jiǎn)要說(shuō)明一下代碼原理,先創(chuàng)建ProxyGenerator類(lèi)實(shí)例,從名字就看得出來(lái),是代理類(lèi)生成器,然后實(shí)例化一個(gè)基于繼承自StandardInterceptor的TestInterceptor,這個(gè)TestInterceptor是一個(gè)自定義的攔截器,最后通過(guò)generator.CreateClassProxy<TestA>(new TestInterceptor())動(dòng)態(tài)創(chuàng)建了一個(gè)繼承自TestA的動(dòng)態(tài)代理類(lèi),這個(gè)代理類(lèi)只有在運(yùn)行時(shí)才會(huì)生成的,后面就可以如代碼所示,直接用動(dòng)態(tài)代理類(lèi)對(duì)象實(shí)例Test操作TestA的所有屬性與方法,當(dāng)然這里需要注意,若需要被動(dòng)態(tài)代理類(lèi)所代理并攔截,則父類(lèi)的屬性或方法必需是virtual,這點(diǎn)與我上面說(shuō)的直接寫(xiě)一個(gè)代理類(lèi)相同。

上述代碼運(yùn)行效果如下:

如何利用C#實(shí)現(xiàn)AOP

第三種:普通反射+利用Remoting的遠(yuǎn)程訪(fǎng)問(wèn)對(duì)象時(shí)的直實(shí)代理類(lèi)來(lái)實(shí)現(xiàn),代碼如下,這個(gè)可能相比以上兩種稍微復(fù)雜一點(diǎn):

以上代碼實(shí)現(xiàn)步驟說(shuō)明:

1.這里定義的一個(gè)真實(shí)類(lèi)AopClass必需繼承自ContextBoundObject類(lèi),而ContextBoundObject類(lèi)又直接繼承自MarshalByRefObject類(lèi),表明該類(lèi)是上下文綁定對(duì)象,允許在支持遠(yuǎn)程處理的應(yīng)用程序中跨應(yīng)用程序域邊界訪(fǎng)問(wèn)對(duì)象,說(shuō)白了就是可以獲取這個(gè)真實(shí)類(lèi)的所有信息,以便可以被生成動(dòng)態(tài)代理。

2.定義繼承自ProxyAttribute的代理特性標(biāo)識(shí)類(lèi)AopAttribute,以表明哪些類(lèi)可以被代理,同時(shí)注意重寫(xiě)CreateInstance方法,在CreateInstance方法里實(shí)現(xiàn)通過(guò)委托與生成透明代理類(lèi)的過(guò)程,realProxy.GetTransparentProxy() 非常重要,目的就是根據(jù)定義的AopProxy代理類(lèi)獲取生成透明代理類(lèi)對(duì)象實(shí)例。

3.實(shí)現(xiàn)通用的AopProxy代理類(lèi),代理類(lèi)必需繼承自RealProxy類(lèi),在這個(gè)代理類(lèi)里面重寫(xiě)Invoke方法,該方法是統(tǒng)一執(zhí)行被代理的真實(shí)類(lèi)的所有方法、屬性、字段的出入口,我們只需要在該方法中根據(jù)傳入的IMessage進(jìn)行判斷并實(shí)現(xiàn)相應(yīng)的攔截代碼即可。

4.最后在需要進(jìn)行Aop攔截的類(lèi)上標(biāo)注AopAttribute即可(注意:被標(biāo)識(shí)的類(lèi)必需是如第1條說(shuō)明的繼承自ContextBoundObject類(lèi)),在實(shí)際調(diào)用的過(guò)程中是感知不到任何的變化。且AopAttribute可以被子類(lèi)繼承,也就意味著所有子類(lèi)都可以被代理并攔截。

如上代碼運(yùn)行效果如下:

如何利用C#實(shí)現(xiàn)AOP

這里順便分享微軟官方如果利用RealProxy類(lèi)實(shí)現(xiàn)AOP的,詳見(jiàn)地址:https://msdn.microsoft.com/zh-cn/library/dn574804.aspx

第四種:反射+ 通過(guò)定義統(tǒng)一的出入口,并運(yùn)用一些特性實(shí)現(xiàn)AOP的效果,比如:常見(jiàn)的MVC、WEB API中的過(guò)濾器特性 ,我這里根據(jù)MVC的思路,實(shí)現(xiàn)了類(lèi)似的MVC過(guò)濾器的AOP效果,只是中間用到了反射,可能性能不佳,但效果還是成功實(shí)現(xiàn)了各種攔截,正如MVC一樣,既支持過(guò)濾器特性,也支持Controller中的Action執(zhí)行前,執(zhí)行后,錯(cuò)誤等方法實(shí)現(xiàn)攔截

實(shí)現(xiàn)思路如下:

A.過(guò)濾器及Controller特定方法攔截實(shí)現(xiàn)原理:

1.獲取程序集中所有繼承自Controller的類(lèi)型;

2.根據(jù)Controller的名稱(chēng)找到第1步中的對(duì)應(yīng)的Controller的類(lèi)型:FindControllerType

3.根據(jù)找到的Controller類(lèi)型及Action的名稱(chēng)找到對(duì)應(yīng)的方法:FindAction

4.創(chuàng)建Controller類(lèi)型的實(shí)例;

5.根據(jù)Action方法找到定義在方法上的所有過(guò)濾器特性(包含:執(zhí)行前、執(zhí)行后、錯(cuò)誤)

6.執(zhí)行Controller中的OnActionExecuting方法,隨后執(zhí)行執(zhí)行前的過(guò)濾器特性列表,如:ActionExecutingFilter

7.執(zhí)行Action方法,獲得結(jié)果;

8.執(zhí)行Controller中的OnActionExecuted方法,隨后執(zhí)行執(zhí)行后的過(guò)濾器特性列表,如:ActionExecutedFilter

9.通過(guò)try catch在catch中執(zhí)行Controller中的OnActionError方法,隨后執(zhí)行錯(cuò)誤過(guò)濾器特性列表,如:ActionErrorFilter

10.最后返回結(jié)果;

B.實(shí)現(xiàn)執(zhí)行路由配置效果原理:

1.增加可設(shè)置路由模板列表方法:AddExecRouteTemplate,在方法中驗(yàn)證controller、action,并獲取模板中的占位符數(shù)組,最后保存到類(lèi)全局對(duì)象中routeTemplates;

2.增加根據(jù)執(zhí)行路由執(zhí)行對(duì)應(yīng)的Controller中的Action方法的效果:Run,在該方法中主要遍歷所有路由模板,然后與實(shí)行執(zhí)行的請(qǐng)求路由信息通過(guò)正則匹配,若匹配OK,并能正確找到Controller及Action,則說(shuō)明正確,并最終統(tǒng)一調(diào)用:Process方法,執(zhí)行A中的所有步驟最終返回結(jié)果。

需要說(shuō)明該模擬MVC方案并沒(méi)有實(shí)現(xiàn)Action方法參數(shù)的的綁定功能,因?yàn)镸odelBinding本身就是比較復(fù)雜的機(jī)制,所以這里只是為了搞清楚AOP的實(shí)現(xiàn)原理,故不作這方面的研究,大家如果有空可以實(shí)現(xiàn),最終實(shí)現(xiàn)MVC不僅是ASP.NET MVC,還可以是Console MVC,甚至是Winform MVC等。

以下是實(shí)現(xiàn)的全部代碼,代碼中我已進(jìn)行了一些基本的優(yōu)化,可以直接使用:

public abstract class Controller
{
 public virtual void OnActionExecuting(MethodInfo action)
 {
 
 }
 
 public virtual void OnActionExecuted(MethodInfo action)
 {
 
 }
 
 public virtual void OnActionError(MethodInfo action, Exception ex)
 {
 
 }
 
}
 
public abstract class FilterAttribute : Attribute
{
 public abstract string FilterType { get; }
 public abstract void Execute(Controller ctrller, object extData);
}
 
public class ActionExecutingFilter : FilterAttribute
{
 public override string FilterType => "BEFORE";
 
 public override void Execute(Controller ctrller, object extData)
 {
 Console.WriteLine($"我是在{ctrller.GetType().Name}.ActionExecutingFilter中攔截發(fā)出的消息!-{DateTime.Now.ToString()}");
 }
}
 
public class ActionExecutedFilter : FilterAttribute
{
 public override string FilterType => "AFTER";
 
 public override void Execute(Controller ctrller, object extData)
 {
 Console.WriteLine($"我是在{ctrller.GetType().Name}.ActionExecutedFilter中攔截發(fā)出的消息!-{DateTime.Now.ToString()}");
 }
}
 
public class ActionErrorFilter : FilterAttribute
{
 public override string FilterType => "EXCEPTION";
 
 public override void Execute(Controller ctrller, object extData)
 {
 Console.WriteLine($"我是在{ctrller.GetType().Name}.ActionErrorFilter中攔截發(fā)出的消息!-{DateTime.Now.ToString()}-Error Msg:{(extData as Exception).Message}");
 }
}
 
public class AppContext
{
 private static readonly Type ControllerType = typeof(Controller);
 private static readonly Dictionary<string, Type> matchedControllerTypes = new Dictionary<string, Type>();
 private static readonly Dictionary<string, MethodInfo> matchedControllerActions = new Dictionary<string, MethodInfo>();
 private Dictionary<string,string[]> routeTemplates = new Dictionary<string, string[]>();
 
 
 public void AddExecRouteTemplate(string execRouteTemplate)
 {
 if (!Regex.IsMatch(execRouteTemplate, "{controller}", RegexOptions.IgnoreCase))
 {
  throw new ArgumentException("執(zhí)行路由模板不正確,缺少{controller}");
 }
 
 if (!Regex.IsMatch(execRouteTemplate, "{action}", RegexOptions.IgnoreCase))
 {
  throw new ArgumentException("執(zhí)行路由模板不正確,缺少{action}");
 }
 
 string[] keys = Regex.Matches(execRouteTemplate, @"(?<={)\w+(?=})", RegexOptions.IgnoreCase).Cast<Match>().Select(c => c.Value.ToLower()).ToArray();
 
 routeTemplates.Add(execRouteTemplate,keys);
 }
 
 public object Run(string execRoute)
 {
 //{controller}/{action}/{id}
 string ctrller = null;
 string actionName = null;
 ArrayList args = null;
 Type controllerType = null;
 bool findResult = false;
 
 foreach (var r in routeTemplates)
 {
  string[] keys = r.Value;
  string execRoutePattern = Regex.Replace(r.Key, @"{(?<key>\w+)}", (m) => string.Format(@"(?<{0}>.[^/\\]+)", m.Groups["key"].Value.ToLower()), RegexOptions.IgnoreCase);
 
  args = new ArrayList();
  if (Regex.IsMatch(execRoute, execRoutePattern))
  {
  var match = Regex.Match(execRoute, execRoutePattern);
  for (int i = 0; i < keys.Length; i++)
  {
   if ("controller".Equals(keys[i], StringComparison.OrdinalIgnoreCase))
   {
   ctrller = match.Groups["controller"].Value;
   }
   else if ("action".Equals(keys[i], StringComparison.OrdinalIgnoreCase))
   {
   actionName = match.Groups["action"].Value;
   }
   else
   {
   args.Add(match.Groups[keys[i]].Value);
   }
  }
 
  if ((controllerType = FindControllerType(ctrller)) != null && FindAction(controllerType, actionName, args.ToArray()) != null)
  {
   findResult = true;
   break;
  }
  }
 }
 
 if (findResult)
 {
  return Process(ctrller, actionName, args.ToArray());
 }
 else
 {
  throw new Exception($"在已配置的路由模板列表中未找到與該執(zhí)行路由相匹配的路由信息:{execRoute}");
 }
 }
 
 public object Process(string ctrller, string actionName, params object[] args)
 {
 Type matchedControllerType = FindControllerType(ctrller);
 
 if (matchedControllerType == null)
 {
  throw new ArgumentException($"未找到類(lèi)型為{ctrller}的Controller類(lèi)型");
 }
 
 object execResult = null;
 if (matchedControllerType != null)
 {
  var matchedController = (Controller)Activator.CreateInstance(matchedControllerType);
  MethodInfo action = FindAction(matchedControllerType, actionName, args);
  if (action == null)
  {
  throw new ArgumentException($"在{matchedControllerType.FullName}中未找到與方法名:{actionName}及參數(shù)個(gè)數(shù):{args.Count()}相匹配的方法");
  }
 
 
  var filters = action.GetCustomAttributes<FilterAttribute>(true);
  List<FilterAttribute> execBeforeFilters = new List<FilterAttribute>();
  List<FilterAttribute> execAfterFilters = new List<FilterAttribute>();
  List<FilterAttribute> exceptionFilters = new List<FilterAttribute>();
 
  if (filters != null && filters.Count() > 0)
  {
  execBeforeFilters = filters.Where(f => f.FilterType == "BEFORE").ToList();
  execAfterFilters = filters.Where(f => f.FilterType == "AFTER").ToList();
  exceptionFilters = filters.Where(f => f.FilterType == "EXCEPTION").ToList();
  }
 
  try
  {
  matchedController.OnActionExecuting(action);
 
  if (execBeforeFilters != null && execBeforeFilters.Count > 0)
  {
   execBeforeFilters.ForEach(f => f.Execute(matchedController, null));
  }
 
  var mParams = action.GetParameters();
  object[] newArgs = new object[args.Length];
  for (int i = 0; i < mParams.Length; i++)
  {
   newArgs[i] = Convert.ChangeType(args[i], mParams[i].ParameterType);
  }
 
  execResult = action.Invoke(matchedController, newArgs);
 
  matchedController.OnActionExecuted(action);
 
  if (execBeforeFilters != null && execBeforeFilters.Count > 0)
  {
   execAfterFilters.ForEach(f => f.Execute(matchedController, null));
  }
 
  }
  catch (Exception ex)
  {
  matchedController.OnActionError(action, ex);
 
  if (exceptionFilters != null && exceptionFilters.Count > 0)
  {
   exceptionFilters.ForEach(f => f.Execute(matchedController, ex));
  }
  }
 
 
 }
 
 return execResult;
 
 }
 
 private Type FindControllerType(string ctrller)
 {
 Type matchedControllerType = null;
 if (!matchedControllerTypes.ContainsKey(ctrller))
 {
  var assy = Assembly.GetAssembly(typeof(Controller));
 
  foreach (var m in assy.GetModules(false))
  {
  foreach (var t in m.GetTypes())
  {
   if (ControllerType.IsAssignableFrom(t) && !t.IsAbstract)
   {
   if (t.Name.Equals(ctrller, StringComparison.OrdinalIgnoreCase) || t.Name.Equals($"{ctrller}Controller", StringComparison.OrdinalIgnoreCase))
   {
    matchedControllerType = t;
    matchedControllerTypes[ctrller] = matchedControllerType;
    break;
   }
   }
  }
  }
 }
 else
 {
  matchedControllerType = matchedControllerTypes[ctrller];
 }
 
 return matchedControllerType;
 }
 
 private MethodInfo FindAction(Type matchedControllerType, string actionName, object[] args)
 {
 string ctrlerWithActionKey = $"{matchedControllerType.FullName}.{actionName}";
 MethodInfo action = null;
 if (!matchedControllerActions.ContainsKey(ctrlerWithActionKey))
 {
  if (args == null) args = new object[0];
  foreach (var m in matchedControllerType.GetMethods(BindingFlags.Instance | BindingFlags.Public))
  {
  if (m.Name.Equals(actionName, StringComparison.OrdinalIgnoreCase) && m.GetParameters().Length == args.Length)
  {
   action = m;
   matchedControllerActions[ctrlerWithActionKey] = action;
   break;
  }
  }
 }
 else
 {
  action = matchedControllerActions[ctrlerWithActionKey];
 }
 
 return action;
 }
}

使用前,先定義一個(gè)繼承自Controller的類(lèi),如:TestController,并重寫(xiě)相應(yīng)的方法,或在指定的方法上加上所需的過(guò)濾器特性,如下代碼所示:

public class TestController : Controller
{
 public override void OnActionExecuting(MethodInfo action)
 {
 Console.WriteLine($"{action.Name}執(zhí)行前,OnActionExecuting---{DateTime.Now.ToString()}");
 }
 
 public override void OnActionExecuted(MethodInfo action)
 {
 Console.WriteLine($"{action.Name}執(zhí)行后,OnActionExecuted--{DateTime.Now.ToString()}");
 }
 
 public override void OnActionError(MethodInfo action, Exception ex)
 {
 Console.WriteLine($"{action.Name}執(zhí)行,OnActionError--{DateTime.Now.ToString()}:{ex.Message}");
 }
 
 [ActionExecutingFilter]
 [ActionExecutedFilter]
 public string HelloWorld(string name)
 {
 return ($"Hello World!->{name}");
 }
 
 [ActionExecutingFilter]
 [ActionExecutedFilter]
 [ActionErrorFilter]
 public string TestError(string name)
 {
 throw new Exception("這是測(cè)試拋出的錯(cuò)誤信息!");
 }
 
 [ActionExecutingFilter]
 [ActionExecutedFilter]
 public int Add(int a, int b)
 {
 return a + b;
 }
}

最后前端實(shí)際調(diào)用就非常簡(jiǎn)單了,代碼如下:

class MVCProgram
{
 static void Main(string[] args)
 {
 try
 {
  var appContext = new AppContext();
  object rs = appContext.Process("Test", "HelloWorld", "夢(mèng)在旅途");
  Console.WriteLine($"Process執(zhí)行的結(jié)果1:{rs}");
 
  Console.WriteLine("=".PadRight(50, '='));
 
  appContext.AddExecRouteTemplate("{controller}/{action}/{name}");
  appContext.AddExecRouteTemplate("{action}/{controller}/{name}");
 
  object result1 = appContext.Run("HelloWorld/Test/夢(mèng)在旅途-zuowenjun.cn");
  Console.WriteLine($"執(zhí)行的結(jié)果1:{result1}");
 
  Console.WriteLine("=".PadRight(50, '='));
 
  object result2 = appContext.Run("Test/HelloWorld/夢(mèng)在旅途-zuowenjun.cn");
  Console.WriteLine($"執(zhí)行的結(jié)果2:{result2}");
 
  Console.WriteLine("=".PadRight(50, '='));
 
  appContext.AddExecRouteTemplate("{action}/{controller}/{a}/");
  object result3 = appContext.Run("Add/Test/500/20");
  Console.WriteLine($"執(zhí)行的結(jié)果3:{result3}");
 
  object result4 = appContext.Run("Test/TestError/夢(mèng)在旅途-zuowenjun.cn");
  Console.WriteLine($"執(zhí)行的結(jié)果4:{result4}");
 }
 catch (Exception ex)
 {
  Console.ForegroundColor = ConsoleColor.Red;
  Console.WriteLine($"發(fā)生錯(cuò)誤:{ex.Message}");
  Console.ResetColor();
 }
 
 Console.ReadKey();
 }
}

可以看到,與ASP.NET MVC有點(diǎn)類(lèi)似,只是ASP.NET MVC是通過(guò)URL訪(fǎng)問(wèn),而這里是通過(guò)AppContext.Run 執(zhí)行路由URL 或Process方法,直接指定Controller、Action、參數(shù)來(lái)執(zhí)行。

通過(guò)以上調(diào)用代碼可以看出路由配置還是比較靈活的,當(dāng)然參數(shù)配置除外。如果大家有更好的想法也可以在下方評(píng)論交流,謝謝!

MVC代碼執(zhí)行效果如下:

如何利用C#實(shí)現(xiàn)AOP

C#是什么

C#是一個(gè)簡(jiǎn)單、通用、面向?qū)ο蟮木幊陶Z(yǔ)言,它由微軟Microsoft開(kāi)發(fā),繼承了C和C++強(qiáng)大功能,并且去掉了一些它們的復(fù)雜特性,C#綜合了VB簡(jiǎn)單的可視化操作和C++的高運(yùn)行效率,以其強(qiáng)大的操作能力、優(yōu)雅的語(yǔ)法風(fēng)格、創(chuàng)新的語(yǔ)言特性和便捷的面向組件編程從而成為.NET開(kāi)發(fā)的選語(yǔ)言,但它不適用于編寫(xiě)時(shí)間急迫或性能非常高的代碼,因?yàn)镃#缺乏性能極高的應(yīng)用程序所需要的關(guān)鍵功能。

感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“如何利用C#實(shí)現(xiàn)AOP”這篇文章對(duì)大家有幫助,同時(shí)也希望大家多多支持創(chuàng)新互聯(lián)成都網(wǎng)站建設(shè)公司,關(guān)注創(chuàng)新互聯(lián)成都網(wǎng)站建設(shè)公司行業(yè)資訊頻道,更多相關(guān)知識(shí)等著你來(lái)學(xué)習(xí)!

另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線(xiàn),公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、網(wǎng)站建設(shè)公司香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性?xún)r(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專(zhuān)為企業(yè)上云打造定制,能夠滿(mǎn)足用戶(hù)豐富、多元化的應(yīng)用場(chǎng)景需求。

當(dāng)前標(biāo)題:如何利用C#實(shí)現(xiàn)AOP-創(chuàng)新互聯(lián)
本文URL:http://bm7419.com/article8/iijip.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站設(shè)計(jì)公司微信公眾號(hào)、商城網(wǎng)站、網(wǎng)站改版營(yíng)銷(xiāo)型網(wǎng)站建設(shè)、網(wǎng)站收錄

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都網(wǎng)站建設(shè)