ASP.NET Core 에서 표현 식 트 리 를 사용 하여 URL 을 만 드 는 방법 에 대한 자세 한 설명

표현 식 트 리(표현 식 트 리)
표현 식 트 리 는 실행 할 수 없 는 코드 입 니 다.트 리 모양 의 데이터 구 조 를 표시 하 는 데 사 용 됩 니 다.트 리 의 모든 노드 는 특정한 표현 식 형식 으로 표시 되 며 약 25 가지 표현 식 형식 이 있 습 니 다.모두 Expression 류 에서 파생 됩 니 다.표현 식 트 리 를 만 드 는 데 는 두 가지 장점 이 있 습 니 다.
1.표현 식 트 리 의 코드 를 편집 하고 수정 하여 표현 식 트 리 의 코드 를 동적 코드 로 바 꾸 고 서로 다른 데이터 베이스 에 따라 트 리 의 코드 논 리 를 수정 하여 데이터 베이스 조회 문 구 를 동적 으로 전환 하 는 목적 을 달성 합 니 다.표현 식 트 리 로 서로 다른 데이터 라 이브 러 리 에 대한 조회 문 구 를 동적 으로 구축 할 수 있 습 니 다.
2.알 수 없 는 대상 에 반사 적 으로 접근 하 는 속성 을 완성 하고 동적 구조 표현 식 트 리 를 통 해 의뢰 를 생 성 합 니 다.
ASP.NET Core 에서 action 을 만 드 는 url 은 이렇게 씁 니 다.

var url=_urlHelper.Action("Index", "Home");
이러한 쓰기 에 존재 하 는 문 제 는 두 문자열 형식의 인 자 를 전달 하 는 것 입 니 다.action 과 contrller 에 대한 이름 바 꾸 기 동작 을 피 할 수 없습니다.예 를 들 어 index 를 default 로 바 꾸 는 것 입 니 다.IDE 를 통 해 action 을 바 꾸 는 과정 에서

_urlHelper.Action("Index", "Home");
재 구성

UrlHelper.Action("Default", "Home");
그래서 우리 의 목 표 는 정적 검 사 를 가 진 API 를 설계 하여 IDE 가 이 오 류 를 알려 주 고 심지어 이름 을 바 꿀 때 관련 코드 를 직접 이름 을 바 꿀 수 있 도록 하 는 것 입 니 다.
목표.
유사 한 두 그룹의 API 를 설계 합 니 다:

var url = _urlHelper.Action((HomeController c) => c.Index());
//     /home/index
var link = _urlHelper.Link((ProductController c) => c.Details(10));
//     http://locahost/product/details/10
설계 API
위의 요구 에 따라 두 그룹의 API 를 정의 합 니 다.

public static string Action<TController>(this IUrlHelper helper, 
Expression<Action<TController>> action)
where TController : Controller
{
 //  
}

public static string Link<TController>(this IUrlHelper helper, 
Expression<Action<TController>> action,
string protocal = null, string host = null)
where TController : Controller
{
 //  
}
API 구현
우 리 는 결국 ASP.NET Core 가 제공 하 는 API 에 의존 해 야 한다.

var link = helper.Action(action: actionName, controller: 
controllerName, values: routes);
그래서 문 제 는(HomeController c) => c.Index()이러한 표현 식 에 따라 actionName,Controller Name,routeValues 를 어떻게 해석 하 느 냐 가 되 었 습 니 다.
1.분석 컨트롤 러 Name
Controller Name 을 분석 하 는 것 은 간단 하고 거 칠 습 니 다.표현 식 트 리 에서 HomeController 라 는 종 류 를 얻 었 기 때문에 홈 문자열 을 직접 가 져 오 면 됩 니 다.

private static string GetControllerName(Type controllerType)
{
 var controllerName = controllerType.Name.EndsWith("Controller")
 ? controllerType.Name.Substring(0,
 controllerType.Name.Length - "Controller".Length)
 : controllerType.Name;
 return controllerName;
}
2.ActionName 분석
표현 식(HomeController c) => c.Index() MethodCallExpression 형식 이기 때문에 Action 의 이름 은 방법 명 입 니 다.

private static MethodCallExpression
GetMethodCallExpression<TController>(
Expression<Action<TController>> actionSelector)
{
 var call = actionSelector.Body as MethodCallExpression;
 if (call == null)
 {
 throw new ArgumentException("You must call a method on " +
 typeof(TController).Name, "actionSelector");
 }
 
 return call;
}

var methodCallExpression = GetMethodCallExpression(action);
var actionName = methodCallExpression.Method.Name;
3.RouteValues 분석
위의 두 단 계 는 Controller Name 과 Action Name 을 분 석 했 습 니 다.즉,위의 분석 을 통 해 아래 호출 을 완료 할 수 있 습 니 다.

var action = helper.Action(action: "index", controller: "home", values: null);
//   
var url = _urlHelper.Action((HomeController c) => c.Index());
//   /home/index
하지만 다음 액 션 을 고려 해 보 자.

[HttpGet,Route("product/{id}")]
public IActionResult Details(int id)
{
 //...
}
이 Action 은 int 형식의 id 가 들 어 오 기 를 기대 합 니 다.즉,이러한 방식 으로 url 을 생 성 하 겠 다 는 것 입 니 다.

var action = helper.Action(action: "details", controller: 
"product", values: new { id = 10 });
그래서 우리 의 API 가 정상적으로 작 동 하려 면 object 형식 을 만들어 야 합 니 다new { id = 10 }이 object 형식의 속성 은 표현 식 트 리 에서 인 자 를 호출 할 수 있 습 니 다.

var action = _urlHelper.Action((ProductController c) => c.Details(10));
이 익명 의 대상 을 만 들 려 면 표현 식 의 모든 인 자 를 옮 겨 다 니 며 속성 명,예 를 들 어 id 를 분석 해 야 합 니 다.값마지막 으로 분 석 된 매개 변수 사전 을 dynamic 형식의 대상 으로 생 성 합 니 다.
표현 식 트 리 를 어떻게 해석 하 는 지 보 세 요expression-trees

public class RouteValueExtractor
{
 public static object GetRouteValues(MethodCallExpression call)
 {
 var routes = new Dictionary<string, object>();

 var parameters = call.Method.GetParameters();
 var pairs = call.Arguments.Select((a, i) => new
 {
  Argument = a,
  ParamName = parameters[i].Name
 });
 foreach (var item in pairs)
 {
  string name = item.ParamName;
  object value = GetValue(item.Argument);
  if (value != null)
  {
  var valueType = value.GetType();
  if (valueType.IsValueType)
  {
   routes.Add(name, value);
  }
  else
  {
   throw new NotSupportedException("Unsupported parameter type {0}");
  }

  }
 }

 return DictionaryToObject(routes);
 }

 private static object GetValue(Expression expression)
 {
 if (expression.NodeType == ExpressionType.Constant)
 {
  return ((ConstantExpression) expression).Value;
 }

 throw new NotSupportedException("Unsupported parameter expression");
 }

 private static dynamic DictionaryToObject(IDictionary<string, object> dictionary)
 {
 var expandoObj = new ExpandoObject();
 var expandoObjCollection = (ICollection<KeyValuePair<string, object>>) expandoObj;

 foreach (var keyValuePair in dictionary)
 {
  expandoObjCollection.Add(keyValuePair);
 }

 dynamic eoDynamic = expandoObj;
 return eoDynamic;
 }
}
완전한 API 구현:

public static string Action<TController>(this IUrlHelper helper, 
Expression<Action<TController>> action)
where TController : Controller
{
 var controllerName = GetControllerName(typeof(TController));
 var methodCallExpression = GetMethodCallExpression(action);
 var actionName = methodCallExpression.Method.Name;

 var routes = RouteValueExtractor.GetRouteValues(methodCallExpression);

 var link = helper.Action(action: actionName, controller: 
 controllerName, values: routes);

 return link;
}
총결산
이상 은 이 글 의 전체 내용 입 니 다.본 논문 의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 참고 학습 가치 가 있 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 댓 글 을 남 겨 주 셔 서 저희 에 대한 지지 에 감 사 드 립 니 다.

좋은 웹페이지 즐겨찾기