C\#를 이용 하여 AOP 에서 흔히 볼 수 있 는 몇 가지 방법 에 대한 상세 한 설명 을 실현 합 니 다.
23098 단어 c#절단면 프로 그래 밍aop
AOP 는 Aspect Oriented Programming 의 줄 임 말로 절단면 프로 그래 밍 을 위 한 사전 컴 파일 방식 과 런 타임 동적 대 리 를 통 해 프로그램 기능 을 실현 하 는 중 업무 논 리 를 통일 적 으로 처리 하 는 기술 로 흔히 볼 수 있 는 장면 은 로그 기록,오류 캡 처,성능 모니터링 등 이다.
AOP 의 본질은 대리 대상 을 통 해 실제 대상 을 간접 적 으로 집행 하 는 것 이다.대리 류 에 다음 과 같은 추가 업무 코드 를 추가 하 는 경우 가 많다.
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 를 프 록 시 리 얼 A 에 의뢰 하여 실행 해 야 합 니 다.프 록 시 클래스 에서 속성 과 호출 방법 을 설정 할 때 로 그 를 기록 하 는 코드 를 추가 하면 됩 니 다.이렇게 하면 코드 의 깨끗 하고 깨끗 하 며 코드 의 후기 유지 에 도 편리 합 니 다.(C\#에서 이불 클래스 를 다시 쓰 려 면 부모 클래스 는 가상 방법 이나 가상 속성 virtual 이 어야 합 니 다)다음 코드:
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");이 코드 역시 매우 간단 하 다.바로 프 록 시 리 얼 A 가 리 얼 A 류 를 계승 하면 프 록 시 리 얼 A 대리 리 얼 A 로 볼 수 있 고 프 록 시 리 얼 A 가 각종 속성 과 방법 을 제공 하여 호출 할 수 있다.이렇게 하면 ProxyRealA 류 내부 속성 및 방법 집행 전후 에 로 그 를 통일 적 으로 기록 하 는 코드 가 있 습 니 다.어디서 든 이 RealA 류 를 사용 하면 ProxyRealA 류 로 직접 대체 할 수 있 습 니 다.리 씨 교체 원칙 으로 인해 부 류 는 하위 클래스 로 교체 할 수 있 습 니 다.그리고 나중에 로그 기록 코드 방식 을 변경 하려 면 ProxyRealA 에서 만 변경 하면 됩 니 다.이렇게 하면 모든 프 록 시 리 얼 A 류 의 로그 가 바 뀌 어 시원 하지 않 습 니까?상기 집행 결 과 는 다음 과 같다.
이상 은 프 록 시 클래스 를 정의 하 는 방식 으로 방법 에서 각종 실행 점 의 차단 코드 논리 처 리 를 통일 적 으로 할 수 있 습 니 다.차단 점(또는 횡단면,절단면 점)은 보통 실행 전,실행 후 오류 가 발생 합 니 다.전에 실제 클래스 인 RealA 를 직접 사용 할 때 각종 논리 코드 를 반복 적 으로 추가 해 야 하 는 문 제 를 해결 하 였 지만,그러나 이에 따 른 새로운 문제 가 또 생 겼 다.그것 은 시스템 에 클래스 가 매우 많 을 때 우리 가 모든 클래스 에 대해 하나의 에이전트 클래스 를 정의 하면 시스템 의 클래스 의 개수 가 배로 증가 하고 서로 다른 에이전트 클래스 에서 일부 차단 업무 논리 코드 가 똑 같 을 수 있다 는 것 이다.이런 상황 도 허용 할 수 없 는 것 이다.그러면 좋 은 방법 이 없 을 까?답 은 긍정 적 입 니 다.다음은 제 가 인터넷 자원 과 개인 정 리 를 결합 한 다음 과 같은 몇 가지 흔히 볼 수 있 는 AOP 를 실현 하 는 방식 입 니 다.여러분 은 참고 하여 공부 하 실 수 있 습 니 다.
첫 번 째:정적 삽입,즉 컴 파일 할 때 AOP 차단 과 관련 된 각종 코드 를 일정한 규칙 에 부합 되 는 클래스 에 주입 합 니 다.컴 파일 된 코드 는 우리 가 RealA 호출 속성 이나 방법 전후 에 코드 를 추가 하 는 것 과 같 습 니 다.다만 이 작업 은 컴 파일 러 에 의 해 이 루어 집 니 다.
PostSharp:PostSharp 의 Aspect 는 Attribute 를 사용 하여 이 루어 집 니 다.우 리 는 OnMethod Boundary Aspect 를 계승 한 다음 에 몇 가지 흔히 볼 수 있 는 방법 을 다시 쓰 면 됩 니 다.예 를 들 어 OnEntry,OnExit 등 은 마지막 으로 AOP 차단 이 필요 한 속성 이나 방법 에 AOP 차단 특성 류 를 추가 하면 됩 니 다.PostSharp 는 정적 으로 짜 여 져 있 기 때문에 다른 반사 나 EMIT 반 사 를 통 해 효율 이 가장 높 지만 PostSharp 는 유 료 버 전 이 고 인터넷 의 튜 토리 얼 이 비교적 많 기 때문에 저 는 여기 서 중복 설명 하지 않 겠 습 니 다.
두 번 째:EMIT 반사,즉:Emit 반사 동적 생 성 에이전트 클래스 를 통 해 다음 과 같 습 니 다
Castle.DynamicProxyAOP 실현 방식 은 코드 도 비교적 간단 합 니 다.효율 은 첫 번 째 보다 느 리 지만 일반적인 반사 에 있어 서 는 높 습 니 다.코드 는 다음 과 같 습 니 다.
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!");
}
}
}코드 원 리 를 간략하게 설명 하고 프 록 시 Generator 클래스 인 스 턴 스 를 만 듭 니 다.이름 에서 알 수 있 듯 이 프 록 시 생 성기 입 니 다.그 다음 에 StandardInterceptor 를 계승 하 는 TestInterceptor 를 예화 합 니 다.이 TestInterceptor 는 사용자 정의 차단기 입 니 다.마지막 으로generator.CreateClassProxy<TestA>(new TestInterceptor())동적 으로 TestA 를 계승 하 는 동적 프 록 시 클래스 를 만 들 었 습 니 다.이 프 록 시 클래스 는 실행 할 때 만 생 성 됩 니 다.그 다음 에 코드 와 같이 동적 프 록 시 대상 인 스 턴 스 Test 로 TestA 의 모든 속성 과 방법 을 직접 조작 할 수 있 습 니 다.물론 여기 서 주의해 야 합 니 다.동적 프 록 시 클래스 에 의 해 대리 되 고 차단 되 어야 한다 면 부모 클래스 의 속성 이나 방법 은 virtual 이 어야 합 니 다.이 점 은 제 가 위 에서 말 한 프 록 시 클래스 와 같 습 니 다.상기 코드 실행 효 과 는 다음 과 같 습 니 다.
세 번 째:일반 반사+Remoting 의 원 격 방문 대상 을 이용 할 때 직 실 대리 류 를 실현 합 니 다.코드 는 다음 과 같 습 니 다.이것 은 상기 두 가지 에 비해 약간 복잡 할 수 있 습 니 다.
이상 코드 구현 절차 설명:
1.여기 서 정 의 된 실제 클래스 인 AopClass 는 ContextBoundObject 클래스 에서 계승 해 야 합 니 다.ContextBoundObject 클래스 는 Marshalby RefObject 클래스 에서 직접 계승 되 어 컨 텍스트 바 인 딩 대상 임 을 나타 내 고 원 격 처 리 를 지원 하 는 응용 프로그램 에서 응용 프로그램 도 메 인 경계 방문 대상 을 뛰 어 넘 을 수 있 습 니 다.말하자면 이 실제 클래스 의 모든 정 보 를 얻 을 수 있 습 니 다.동적 에이전트 가 생 성 될 수 있 도록 합 니 다.
2.프 록 시 Attribute 에서 계승 하 는 프 록 시 특성 표지 류 AopAttribute 를 정의 하여 어떤 종류 가 대 리 될 수 있 는 지 를 나타 내 는 동시에 Create Instance 방법 을 다시 쓰 는 것 에 주의 하고 Create Instance 방법 에서 투명 프 록 시 클래스 를 위탁 하고 생 성 하 는 과정 을 실현 합 니 다
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.필터 및 컨트롤 러 의 특정 방법 차단 실현 원리:
1.가 져 오기 프로그램 은 모든 계승 컨트롤 러 의 유형 을 집중 합 니 다.
2.Controller 의 이름 에 따라 첫 번 째 단계 에 대응 하 는 Controller 의 종 류 를 찾 습 니 다:FindController Type
3.찾 은 Controller 유형 및 Action 이름 에 따라 해당 하 는 방법 찾기:FindAction
4.Controller 형식의 인 스 턴 스 만 들 기;
5.Action 방법 에 따라 방법 에 정 의 된 모든 필터 특성 을 찾 습 니 다(실행 전,실행 후,오류 포함)
6.Controller 의 OnAction Executing 방법 을 실행 한 다음 실행 전 필터 특성 목록 을 실행 합 니 다.예 를 들 어 Action Executing Filter
7.액 션 방법 을 실행 하여 결 과 를 얻는다.
8.Controller 의 OnAction Executed 방법 을 실행 한 다음 실행 후의 필터 특성 목록 을 실행 합 니 다.예 를 들 어 Action Executed Filter
9.try catch 를 통 해 catch 에서 Controller 의 OnAction Error 방법 을 실행 한 다음 에 오류 필터 특성 목록 을 실행 합 니 다.예 를 들 어 Action Error Filter
10.마지막 으로 결 과 를 되 돌려 줍 니 다.
B.실행 경로 설정 효과 원리:
1.경로 템 플 릿 목록 을 설정 할 수 있 는 방법 을 추가 합 니 다.AddExecRouteTemplate,방법 에서 contrller,action 을 검증 하고 템 플 릿 의 자리 표시 자 배열 을 가 져 옵 니 다.마지막 으로 클래스 전역 대상 에 routeTemplates 를 저장 합 니 다.
2.실행 경로 에 따라 대응 하 는 Controller 의 Action 방법 을 실행 하 는 효 과 를 증가 합 니 다.Run 은 이 방법 에서 모든 경로 템 플 릿 을 옮 겨 다 닌 다음 에 실 행 된 요청 경로 정보 와 정규 로 일치 합 니 다.OK 와 일치 하면 Controller 와 Action 을 정확하게 찾 을 수 있 으 면 정확 한 설명 을 하고 최종 적 으로 통일 적 으로 호출 합 니 다.Process 방법,A 의 모든 절 차 를 실행 하고 결 과 를 되 돌려 줍 니 다.
이 시 뮬 레이 션 MVC 방안 이 Action 방법 파라미터 의 연결 기능 을 실현 하지 못 했다 는 것 을 설명해 야 한다.ModelBinding 자체 가 비교적 복잡 한 메커니즘 이기 때문에 여 기 는 AOP 의 실현 원 리 를 알 기 위해 서 이 분야 의 연 구 를 하지 않 는 다.여러분 이 시간 이 있 으 면 MVC 를 실현 할 수 있다.최종 적 으로 MVC 는 ASP.NET MVC 뿐만 아니 라 Console MVC,심지어 Winform MVC 등 도 실현 할 수 있다.
다음은 실 현 된 모든 코드 입 니 다.코드 에서 저 는 기본 적 인 최적화 를 했 기 때문에 직접 사용 할 수 있 습 니 다.
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,그리고 해당 하 는 방법 을 다시 쓰 거나 지정 한 방법 에 필요 한 필터 특성 을 추가 합 니 다.다음 코드 는 다음 과 같 습 니 다.
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;
}
}마지막 으로 전단 의 실제 호출 은 매우 간단 합 니 다.코드 는 다음 과 같 습 니 다.
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 코드 실행 효 과 는 다음 과 같 습 니 다.
총결산
이상 은 이 글 의 전체 내용 입 니 다.본 논문 의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 참고 학습 가치 가 있 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 댓 글 을 남 겨 주 셔 서 저희 에 대한 지지 에 감 사 드 립 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
C#Task를 사용하여 비동기식 작업을 수행하는 방법라인이 완성된 후에 이 라인을 다시 시작할 수 없습니다.반대로 조인(Join)만 결합할 수 있습니다 (프로세스가 현재 라인을 막습니다). 임무는 조합할 수 있는 것이다. 연장을 사용하여 그것들을 한데 연결시키는 것이...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.