這篇文章主要介紹了如何利用C#實(shí)現(xiàn)AOP,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
成都創(chuàng)新互聯(lián)專(zhuān)注為客戶(hù)提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于網(wǎng)站制作、成都網(wǎng)站設(shè)計(jì)、博樂(lè)網(wǎng)絡(luò)推廣、重慶小程序開(kāi)發(fā)、博樂(lè)網(wǎng)絡(luò)營(yíng)銷(xiāo)、博樂(lè)企業(yè)策劃、博樂(lè)品牌公關(guān)、搜索引擎seo、人物專(zhuān)訪、企業(yè)宣傳片、企業(yè)代運(yùn)營(yíng)等,從售前售中售后,我們都將竭誠(chéng)為您服務(wù),您的肯定,是我們最大的嘉獎(jiǎng);成都創(chuàng)新互聯(lián)為所有大學(xué)生創(chuàng)業(yè)者提供博樂(lè)建站搭建服務(wù),24小時(shí)服務(wù)熱線:18980820575,官方網(wǎng)址:www.cdcxhl.com
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é)果如下圖示:
以上通過(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(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)ⅲ? + 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
動(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)行效果如下:
第三種:普通反射+利用Remoting的遠(yuǎn)程訪問(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)用程序域邊界訪問(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)行效果如下:
這里順便分享微軟官方如果利用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 DictionarymatchedControllerTypes = new Dictionary (); private static readonly Dictionary matchedControllerActions = new Dictionary (); private Dictionary routeTemplates = new Dictionary (); 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 ().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, @"{(? \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 (true); List execBeforeFilters = new List (); List execAfterFilters = new List (); List exceptionFilters = new List (); 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訪問(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#是一個(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),關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,更多相關(guān)知識(shí)等著你來(lái)學(xué)習(xí)!