前言前端
AOP爲Aspect Oriented Programming的縮寫,意爲:面向切面編程,經過預編譯方式和運行期動態代理實現程序功能的中統一處理業務邏輯的一種技術,比較常見的場景是:日誌記錄,錯誤捕獲、性能監控等web
AOP的本質是經過代理對象來間接執行真實對象,在代理類中每每會添加裝飾一些額外的業務代碼,好比以下代碼:編程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
class
RealA
{
public
virtual
string
Pro {
get
;
set
; }
public
virtual
void
ShowHello(
string
name)
{
Console.WriteLine($
"Hello!{name},Welcome!"
);
}
}
//調用:
var a =
new
RealA();
a.Pro =
"測試"
;
a.ShowHello(
"夢在旅途"
);
|
這段代碼很簡單,只是NEW一個對象,而後設置屬性及調用方法,但若是我想在設置屬性先後及調用方法先後或報錯都能收集日誌信息,該如何作呢?可能你們會想到,在設置屬性及調用方法先後都加上記錄日誌的代碼不就能夠了,雖然這樣是能夠,但若是不少地方都要用到這個類的時候,那重複的代碼是否太多了一些吧,因此咱們應該使用代理模式或裝飾模式,將原有的真實類RealA委託給代理類ProxyRealA來執行,代理類中在設置屬性及調用方法時,再添加記錄日誌的代碼就能夠了,這樣能夠保證代碼的乾淨整潔,也便於代碼的後期維護。(注意,在C#中若需被子類重寫,父類必需是虛方法或虛屬性virtual)數組
以下代碼:app
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
class
ProxyRealA : RealA
{
public
override
string
Pro
{
get
{
return
base
.Pro;
}
set
{
ShowLog(
"設置Pro屬性前日誌信息"
);
base
.Pro = value;
ShowLog($
"設置Pro屬性後日志信息:{value}"
);
}
}
public
override
void
ShowHello(
string
name)
{
try
{
ShowLog(
"ShowHello執行前日誌信息"
);
base
.ShowHello(name);
ShowLog(
"ShowHello執行後日志信息"
);
}
catch
(Exception ex)
{
ShowLog($
"ShowHello執行出錯日誌信息:{ex.Message}"
);
}
}
private
void
ShowLog(
string
log)
{
Console.WriteLine($
"{DateTime.Now.ToString()}-{log}"
);
}
}
//調用:
var aa =
new
ProxyRealA();
aa.Pro =
"測試2"
;
aa.ShowHello(
"zuowenjun.cn"
);
|
這段代碼一樣很簡單,就是ProxyRealA繼承自RealA類,便可當作是ProxyRealA代理RealA,由ProxyRealA提供各類屬性及方法調用。這樣在ProxyRealA類內部屬性及方法執行先後都有統一記錄日誌的代碼,不論在哪裏用這個RealA類,均可以直接用ProxyRealA類代替,由於里氏替換原則,父類能夠被子類替換,並且後續若想更改日誌記錄代碼方式,只須要在ProxyRealA中更改就好了,這樣全部用到的ProxyRealA類的日誌都會改變,是否是很爽。ide
上述執行結果以下圖示:性能
以上經過定義代理類的方式可以實如今方法中統一進行各類執行點的攔截代碼邏輯處理,攔截點(或者稱爲:橫切面,切面點)通常主要爲:執行前,執行後,發生錯誤,雖然解決了以前直接調用真實類RealA時,須要重複增長各類邏輯代碼的問題,但隨之而來的新問題又來了,那就是當一個系統中的類很是多的時候,若是咱們針對每一個類都定義一個代理類,那麼系統的類的個數會成倍增長,並且不一樣的代理類中可能某些攔截業務邏輯代碼都是相同的,這種狀況一樣是不能容許的,那有沒有什麼好的辦法呢?答案是確定的,如下是我結合網上資源及我的總結的以下幾種常見的實現AOP的方式,各位能夠參考學習。學習
第一種:靜態織入,即:在編譯時,就將各類涉及AOP攔截的代碼注入到符合必定規則的類中,編譯後的代碼與咱們直接在RealA調用屬性或方法先後增長代碼是相同的,只是這個工做交由編譯器來完成。測試
PostSharp:PostSharp的Aspect是使用Attribute實現的,咱們只需事先經過繼承自OnMethodBoundaryAspect,而後重寫幾個常見的方法便可,如:OnEntry,OnExit等,最後只須要在須要進行AOP攔截的屬性或方法上加上AOP攔截特性類便可。因爲PostSharp是靜態織入的,因此相比其它的經過反射或EMIT反射來講效率是最高的,但PostSharp是收費版本的,並且網上的教程比較多,我就不在此重複說明了。優化
第二種:EMIT反射,即:經過Emit反射動態生成代理類,以下Castle.DynamicProxy
的AOP實現方式,代碼也仍是比較簡單的,效率相對第一種要慢一點,但對於普通的反射來講又高一些,代碼實現以下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
|
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 +
"執行前,入參:"
+
string
.Join(
","
, invocation.Arguments));
}
protected
override
void
PerformProceed(IInvocation invocation)
{
Console.WriteLine(invocation.Method.Name +
"執行中"
);
try
{
base
.PerformProceed(invocation);
}
catch
(Exception ex)
{
HandleException(ex);
}
}
protected
override
void
PostProceed(IInvocation invocation)
{
Console.WriteLine(invocation.Method.Name +
"執行後,返回值:"
+ 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!"
);
}
}
}
|
簡要說明一下代碼原理,先建立ProxyGenerator類實例,從名字就看得出來,是代理類生成器,而後實例化一個基於繼承自StandardInterceptor的TestInterceptor,這個TestInterceptor是一個自定義的攔截器,最後經過generator.CreateClassProxy<TestA>(new TestInterceptor())
動態建立了一個繼承自TestA的動態代理類,這個代理類只有在運行時纔會生成的,後面就能夠如代碼所示,直接用動態代理類對象實例Test操做TestA的全部屬性與方法,固然這裏須要注意,若須要被動態代理類所代理並攔截,則父類的屬性或方法必需是virtual,這點與我上面說的直接寫一個代理類相同。
上述代碼運行效果以下:
第三種:普通反射+利用Remoting的遠程訪問對象時的直實代理類來實現,代碼以下,這個可能相比以上兩種稍微複雜一點:
以上代碼實現步驟說明:
1.這裏定義的一個真實類AopClass必需繼承自ContextBoundObject類,而ContextBoundObject類又直接繼承自MarshalByRefObject類,代表該類是上下文綁定對象,容許在支持遠程處理的應用程序中跨應用程序域邊界訪問對象,說白了就是能夠獲取這個真實類的全部信息,以即可以被生成動態代理。
2.定義繼承自ProxyAttribute的代理特性標識類AopAttribute,以代表哪些類能夠被代理,同時注意重寫CreateInstance方法,在CreateInstance方法裏實現經過委託與生成透明代理類的過程,realProxy.GetTransparentProxy()
很是重要,目的就是根據定義的AopProxy代理類獲取生成透明代理類對象實例。
3.實現通用的AopProxy代理類,代理類必需繼承自RealProxy類,在這個代理類裏面重寫Invoke方法,該方法是統一執行被代理的真實類的全部方法、屬性、字段的出入口,咱們只須要在該方法中根據傳入的IMessage進行判斷並實現相應的攔截代碼便可。
4.最後在須要進行Aop攔截的類上標註AopAttribute便可(注意:被標識的類必需是如第1條說明的繼承自ContextBoundObject類),在實際調用的過程當中是感知不到任何的變化。且AopAttribute能夠被子類繼承,也就意味着全部子類均可以被代理並攔截。
如上代碼運行效果以下:
這裏順便分享微軟官方若是利用RealProxy類實現AOP的,詳見地址:https://msdn.microsoft.com/zh-cn/library/dn574804.aspx
第四種:反射+ 經過定義統一的出入口,並運用一些特性實現AOP的效果,好比:常見的MVC、WEB API中的過濾器特性 ,我這裏根據MVC的思路,實現了相似的MVC過濾器的AOP效果,只是中間用到了反射,可能性能不佳,但效果仍是成功實現了各類攔截,正如MVC同樣,既支持過濾器特性,也支持Controller中的Action執行前,執行後,錯誤等方法實現攔截
實現思路以下:
A.過濾器及Controller特定方法攔截實現原理:
1.獲取程序集中全部繼承自Controller的類型;
2.根據Controller的名稱找到第1步中的對應的Controller的類型:FindControllerType
3.根據找到的Controller類型及Action的名稱找到對應的方法:FindAction
4.建立Controller類型的實例;
5.根據Action方法找到定義在方法上的全部過濾器特性(包含:執行前、執行後、錯誤)
6.執行Controller中的OnActionExecuting方法,隨後執行執行前的過濾器特性列表,如:ActionExecutingFilter
7.執行Action方法,得到結果;
8.執行Controller中的OnActionExecuted方法,隨後執行執行後的過濾器特性列表,如:ActionExecutedFilter
9.經過try catch在catch中執行Controller中的OnActionError方法,隨後執行錯誤過濾器特性列表,如:ActionErrorFilter
10.最後返回結果;
B.實現執行路由配置效果原理:
1.增長可設置路由模板列表方法:AddExecRouteTemplate,在方法中驗證controller、action,並獲取模板中的佔位符數組,最後保存到類全局對象中routeTemplates;
2.增長根據執行路由執行對應的Controller中的Action方法的效果:Run,在該方法中主要遍歷全部路由模板,而後與實行執行的請求路由信息經過正則匹配,若匹配OK,並能正確找到Controller及Action,則說明正確,並最終統一調用:Process方法,執行A中的全部步驟最終返回結果。
須要說明該模擬MVC方案並無實現Action方法參數的的綁定功能,由於ModelBinding自己就是比較複雜的機制,因此這裏只是爲了搞清楚AOP的實現原理,故不做這方面的研究,你們若是有空能夠實現,最終實現MVC不只是ASP.NET MVC,還能夠是Console MVC,甚至是Winform MVC等。
如下是實現的所有代碼,代碼中我已進行了一些基本的優化,能夠直接使用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
|
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中攔截髮出的消息!-{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中攔截髮出的消息!-{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中攔截髮出的消息!-{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(
"執行路由模板不正確,缺乏{controller}"
);
}
if
(!Regex.IsMatch(execRouteTemplate,
"{action}"
, RegexOptions.IgnoreCase))
{
throw
new
ArgumentException(
"執行路由模板不正確,缺乏{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($
"在已配置的路由模板列表中未找到與該執行路由相匹配的路由信息:{execRoute}"
);
}
}
public
object
Process(
string
ctrller,
string
actionName,
params
object
[] args)
{
Type matchedControllerType = FindControllerType(ctrller);
if
(matchedControllerType ==
null
)
{
throw
new
ArgumentException($
"未找到類型爲{ctrller}的Controller類型"
);
}
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}及參數個數:{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;
}
}
|
使用前,先定義一個繼承自Controller的類,如:TestController,並重寫相應的方法,或在指定的方法上加上所需的過濾器特性,以下代碼所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
public
class
TestController : Controller
{
public
override
void
OnActionExecuting(MethodInfo action)
{
Console.WriteLine($
"{action.Name}執行前,OnActionExecuting---{DateTime.Now.ToString()}"
);
}
public
override
void
OnActionExecuted(MethodInfo action)
{
Console.WriteLine($
"{action.Name}執行後,OnActionExecuted--{DateTime.Now.ToString()}"
);
}
public
override
void
OnActionError(MethodInfo action, Exception ex)
{
Console.WriteLine($
"{action.Name}執行,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(
"這是測試拋出的錯誤信息!"
);
}
[ActionExecutingFilter]
[ActionExecutedFilter]
public
int
Add(
int
a,
int
b)
{
return
a + b;
}
}
|
最後前端實際調用就很是簡單了,代碼以下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
class
MVCProgram
{
static
void
Main(
string
[] args)
{
try
{
var appContext =
new
AppContext();
object
rs = appContext.Process(
"Test"
,
"HelloWorld"
,
"夢在旅途"
);
Console.WriteLine($
"Process執行的結果1:{rs}"
);
Console.WriteLine(
"="
.PadRight(50,
'='
));
appContext.AddExecRouteTemplate(
"{controller}/{action}/{name}"
);
appContext.AddExecRouteTemplate(
"{action}/{controller}/{name}"
);
object
result1 = appContext.Run(
"HelloWorld/Test/夢在旅途-zuowenjun.cn"
);
Console.WriteLine($
"執行的結果1:{result1}"
);
Console.WriteLine(
"="
.PadRight(50,
'='
));
object
result2 = appContext.Run(
"Test/HelloWorld/夢在旅途-zuowenjun.cn"
);
Console.WriteLine($
"執行的結果2:{result2}"
);
Console.WriteLine(
"="
.PadRight(50,
'='
));
appContext.AddExecRouteTemplate(
"{action}/{controller}/{a}/{b}"
);
object
result3 = appContext.Run(
"Add/Test/500/20"
);
Console.WriteLine($
"執行的結果3:{result3}"
);
object
result4 = appContext.Run(
"Test/TestError/夢在旅途-zuowenjun.cn"
);
Console.WriteLine($
"執行的結果4:{result4}"
);
}
catch
(Exception ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($
"發生錯誤:{ex.Message}"
);
Console.ResetColor();
}
Console.ReadKey();
}
}
|
能夠看到,與ASP.NET MVC有點相似,只是ASP.NET MVC是經過URL訪問,而這裏是經過AppContext.Run 執行路由URL 或Process方法,直接指定Controller、Action、參數來執行。
經過以上調用代碼能夠看出路由配置仍是比較靈活的,固然參數配置除外。若是你們有更好的想法也能夠在下方評論交流,謝謝!
MVC代碼執行效果以下:
總結
以上就是這篇文章的所有內容了,但願本文的內容對你們的學習或者工做具備必定的參考學習價值,若是有疑問你們能夠留言交流,謝謝你們對腳本之家的支持。