2012-05-02 5 views
5

내가 좋아하는 설정 경로가 있습니다MVC 라우팅 제약

 context.MapRoute(
     name: "Area", 
     url: "Area/{controller}/{action}", 
     defaults: new 
     { 
      controller = "Home", 
      action = "Dashboard" 
     } 
     ); 

     context.MapRoute(
     name: "AccountArea", 
     url: "Area/{accountFriendlyId}/{controller}/{action}", 
     defaults: new 
     { 
      controller = "Home", 
      action = "Dashboard", 
      accountFriendlyId = RouteParameter.Optional 
     } 
     ); 

     context.MapRoute(
     name: "AccountCampaignArea", 
     url: "Area/{accountFriendlyId}/{campaignFriendlyId}/{controller}/{action}", 
     defaults: new 
       { 
        controller = "Home", 
        action = "Dashboard", 
        accountFriendlyId = RouteParameter.Optional, 
        campaignFriendlyId = RouteParameter.Optional 
       } 
     ); 

을 내가 Area/friendlyAccountName/HomeDashboard()에 데려다 가지고 불타는 욕망을 가지고 있지만이 (404)를 작동하지 않습니다. 그 이유는 friendlyAccountName 컨트롤러를 찾는 것입니다.

내 컨트롤러 중 하나가 고장 난 후 계정 이름을 지정해야한다면, 해당 컨트롤러를 찾지 못한 문자열의 경우 다음 경로로 넘어갈 수있는 방법이 있습니까? 리플렉션을 사용하고 컨트롤러 목록을 수정할 때마다 제약 조건을 유지하지 않는 방법이 있습니까?

편집

당신은 반사를 사용하지 않는 방법을 알고 있거나 적어도이 지역에 파생 형 검색을 포함 하는가? 두 번째 라우트 매개 변수가 컨트롤러 이름과 일치 할 때 두 번 오버 헤드가 발생한다는 생각이 맘에 들지 않습니다 (통과 제약 조건, 컨트롤러 구성시 다시 검색). 컨트롤러를 생성 한 다음 백업하고 다음 경로로 넘어가는 시점에서 예외를 잡을 수있는 방법이 있었으면 좋겠습니다.

답변

6

왜 첫 번째 경로가 필요합니까? {accountFriendlyId}이 선택 사항 인 경우이를 생략하고 처음 등록 된 경로와 동일한 경로 기본값을 가져야합니다.

그런 식으로 AccountArea 경로에서 먼저 이름이 지정되어 있습니다. 그러면 {accountFriendlyId}이 지정되지 않으면 컨트롤러의 첫 번째 토큰이 처리됩니다. 당신은 완전히 처음 두 경로를 제거 할 수 그냥 마지막에 충실해야처럼 처음 두 경로 매개 변수는 선택 사항이며 기본값이 동일하기 때문에

는 사실, 나는 생각합니다.

UPDATE

{accountFriendlyId}가 유효한 컨트롤러 작업 이름이 될 수 있기 때문에, 당신은 다른 것들의 몇 할 수 : 경로의 마지막에

  1. 이동 {accountFriendlyId}, 대신에를 처음. 이는 리소스 내에서 가장 구체적인 가장 구체적인 리소스에 대한 가장 자연스러운 URL 스타일을 따릅니다.
  2. route constraints을 사용하십시오. 이론적으로 리플렉션을 사용하여 custom constraint에서 컨트롤러 이름과 일치하는 정규식을 생성하거나 수동으로 작성하면됩니다. 이런 식으로 뭔가 :

context.MapRoute (

name: "Area", 
    url: "Area/{controller}/{action}", 
    defaults: new 
    { 
     controller = "Home", 
     action = "Dashboard", 
     new { controller = @"(Account|Profile|Maintenance)" } 
    } 

);

+0

를 처음 두 노선이 없으면,'아르곤 ea/Controller/Action'은 친숙한 id 매개 변수를 채우고 기본 컨트롤러와 액션으로 나를 보내고'Area/friendly/Controller/Action'은 실패합니다. –

+0

아, 미안하지만,'{accountFriendlyId}' 유효한 작업 이름이됩니다. 나는 대답을 업데이트 할 것이다. –

+0

이 문자열을 구문 분석하는 방법은 무엇입니까? 나는 당신이 문자 그대로 인라인으로 그것을 할 수 있다는 단서를 가지고 있지 않았다. (나는 이것을 특별히 사용하지 않을 것이다.) –

2

이것은 URL 공간 문제입니다. 당신은 어떻게 accountFriendlyId하는 campaignFriendlyId와 컨트롤러를 구분합니까? 쉬운 방법은 여러 가지 URL 세그먼트에 배치하는 것이지만 경로를 사용하면 컨트롤러를 두 번째, 세 번째 또는 네 번째 세그먼트로 만들 수 있습니다.당신은 명확하게 제약 조건을 사용하고,이처럼 그들을 주문해야 :

context.MapRoute(null, "Area/{controller}/{action}", 
    new { controller = "Home", action = "Dashboard" }, 
    new { controller = "Foo|Bar" }); 

context.MapRoute(null, "Area/{accountFriendlyId}/{controller}/{action}", 
    new { controller = "Home", action = "Dashboard" }, 
    new { controller = "Foo|Bar" }); 

context.MapRoute(null, "Area/{accountFriendlyId}/{campaignFriendlyId}/{controller}/{action}", 
    new { controller = "Home", action = "Dashboard" }); 

컨트롤러가 그 다음 일치하는 경로를 시도 발견되지 않는 경우, 제안 아이디어, 그것은 그런 식으로 작동하지 않는, 한 번 경로 그게 맞으면 UrlRoutingModule을 수정하여 그 작업을 시도해야합니다.

궁극적으로
+0

그리고이 영역에서만 컨트롤러 이름 문자열을 얻기 위해 반사를 필터링하는 것까지? 이 영역에'IController'와 컨트롤러 사이에 빈'IAreaController'를 써야하나요? –

+0

@ nik.shornikov 나는 당신이 무슨 말을하고 있는지, 디 나믹하게 제약 조건을 만들고 싶지는 모르겠다. –

+0

예 -'Assembly.GetCallingAssembly(). GetTypes(). 여기서 (type => type.IsSubclassOf (typeof (IController)))' –

6

, 나는 (응용 프로그램 동적으로 임의의 문자열과 컨트롤러 이름을 구분할 필요에 의존하는) 원하는 것을 촉진하기 위해이 같은 경로 설정 :

public override void RegisterArea(AreaRegistrationContext context) 
    { 
     context.MapRoute(
     name: "AccountCampaignArea", 
     url: "Area/{accountFriendlyId}/{campaignFriendlyId}/{controller}/{action}", 
     defaults: new 
      { 
       controller = "Home", 
       action = "Dashboard", 
       accountFriendlyId = RouteParameter.Optional, 
       campaignFriendlyId = RouteParameter.Optional, 
       id = UrlParameter.Optional 
      }, 
     constraints: new { accountFriendlyId = new ControllerNameConstraint(), campaignFriendlyId = new ControllerNameConstraint() } 
     ); 

     context.MapRoute(
      name: "AccountArea", 
      url: "Area/{accountFriendlyId}/{controller}/{action}", 
      defaults: new 
       { 
        controller = "Home", 
        action = "Dashboard", 
        accountFriendlyId = RouteParameter.Optional, 
        id = UrlParameter.Optional 
       }, 
      constraints: new { accountFriendlyId = new ControllerNameConstraint() } 
      ); 

     context.MapRoute(
     name: "Area", 
     url: "Area/{controller}/{action}", 
     defaults: new 
      { 
       controller = "Home", 
       action = "Dashboard" 
      } 
     ); 
    } 

을 그리고이 같은 제약 조건을 (설정 제약도) NotControllerNameContraint를 호출 할 수 있습니다 :

public class ControllerNameConstraint : IRouteConstraint 
{ 
    private static List<Type> GetSubClasses<T>() 
    { 
     return Assembly.GetCallingAssembly().GetTypes().Where(
      type => type.IsSubclassOf(typeof(T))).ToList(); 
    } 

    public List<string> GetControllerNames() 
    { 
     List<string> controllerNames = new List<string>(); 
     GetSubClasses<Controller>().ForEach(
      type => controllerNames.Add(type.Name)); 
     return controllerNames; 
    } 
    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) 
    { 
     if (values.ContainsKey(parameterName)) 
     { 
      string stringValue = values[parameterName] as string; 
      return !GetControllerNames().Contains(stringValue + "Controller"); 
     } 

     return true; 
    } 
} 

크레딧 : https://stackoverflow.com/a/1152735/938472