2011-11-30 3 views
0

아니기 때문에 단일 URL로 와야하는 사이트가 있으며 쿠키가 귀하가 소속 된 고객을 추적하도록 설정되어 있습니다. 나는 특정 컨트롤러는이 같은 URL을 사용하도록이 설정을 변경하려면 :역방향 URL 호환성을 유지하면서 동적 접두어로 MVC 라우팅을 변경하십시오.

/{의 FriendlyName}/{컨트롤러}/{지수}/{ID} 친숙한 이름이 고유 나를을 선택할 수 있다는

쿠키 고름을 사용하지 않고 올바른 고객.

저는 컨트롤러가 있습니다 : Home, Redirect 나는 친숙한 이름 부분을 원하지 않습니다.

저는이 카테고리에 맞는 몇 가지 다른 것들을 가지고 있습니다. 해당 지역을 유효한 친근한 이름으로 포함시키지 않으려면 어떻게해야합니까? 예를 들어 Framed이라는 iframe에서 콘텐츠를 제공하는 컨트롤러가 있습니다. 현재이 URL은/Framed/action/id처럼 보입니다. 이 컨트롤러를 액션과 같은 이름의 Framed이라는 영역에 넣을 수 있으며, 나는 여전히 같은 URL을 유지할 수 있어야합니다. 컨트롤러 Error를 들어

내가 친숙한 이름은 선택되고 싶어

내가 친숙한 이름이 필요 할 다른 컨트롤러가 : SignIn, SignOut, Account

내가 라우팅이되면, 문제는 내 리디렉션이 friendlyurl을 유지하도록 코드를 변경하는 것입니다. 어떻게하는지에 대한 아이디어가 있습니까?

내 문제는 방금 내 사이트의 라우팅을 변경하는 방법에 대한 좋은 계획을 세우고 있습니다. I 의 일부 URL의 하위 호환성을 유지해야합니다. 즉, 내가 언급 한 컨트롤러를 포함하여 친숙한 URL 부분을 원하지 않는 것입니다. 나는 이것을 레이아웃하고 변경 사항을 변경하는 방법에 대한 좋은 제안을 찾고 있습니다.

답변

3

목표를 달성하려면 경로 조합과 RouteConstraints이 필요합니다. 또한 friendlyName이 고유하며 모든 컨트롤러 또는 영역의 이름과 다른 규칙을 적용해야합니다.

다음 노선 Global.asax.cs에 RegisterRoutes()에 충분해야한다 :

routes.MapRoute(
    "WithFriendlyName", 
    "{friendlyName}/{controller}/{index}/{id}", 
    new { controller = "Home", action = "Index", id = UrlParameter.Optional }, 
    new { friendlyName = new MustBeFriendlyName() } 
); 

routes.MapRoute(
    "Default", // Route name 
    "{controller}/{action}/{id}", // URL with parameters 
    new { controller = "Home", action = "Index", id = UrlParameter.Optional }, 
    new { controller = new MustNotRequireFriendlyName() } 
); 

RouteConstraints는 다음과 같이 보일 것이다 :

using System; 
using System.Web; 
using System.Web.Routing; 

namespace Examples.Extensions 
{ 
    public class MustBeFriendlyName : IRouteConstraint 
    { 
     public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) 
     { 
      // return true if this is a valid friendlyName 
      // MUST BE CERTAIN friendlyName DOES NOT MATCH ANY 
      // CONTROLLER NAMES OR AREA NAMES 
      var _db = new DbContext(); 
      return _db.FriendlyNames.FirstOrDefault(x => x.FriendlyName.ToLowerInvariant() == 
       values[parameterName].ToString().ToLowerInvariant()) != null; 
     } 
    } 

    public class MustNotRequireFriendlyName : IRouteConstraint 
    { 
     private const string controllersRequiringFriendlyNames = 
      "SignIn~SignOut~Account"; 

     public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) 
     { 
      // return true if this controller does NOT require a friendlyName 
      return controllersRequiringFriendlyNames.ToLowerInvariant() 
       .Contains(values[parameterName].ToString().ToLowerInvariant()); 
     } 
    } 
} 

이것은 당신이 시작할 수 있어야합니다.

리디렉션에 의해 생성 된 URL의 경우 라우팅이 올바르게 설정된 경우 URL 생성이 이어져야하므로 {friendlyName}이 (가) 전달되어야한다는 내용 만 필요할 수 있습니다.

변경 사항을 추가 할 때 경로 및 제약 조건을 추가해야 할 수 있습니다.

+0

구현하려고 할 때 코드에 몇 가지 오타가 있다고 생각합니다. '{friendly}}/{controller}/{action}/{id}''대신'{friendly}}/{controller}/{index}/{id}''를 사용하고'MustNotRequireFriendlyName' 주석이 정확하다면, 명령문에는 not 연산자가 필요합니다. – Josh

1

옵션 접두어가 지난 며칠간 나를 물어 뜯기 때문에 이걸 추가하고 싶었습니다. @counsellorben에서 제공하는 솔루션을 사용하고자 할 때도 같은 이름으로 경로를 처리 할 수 ​​있어야했습니다. 두 경로를 사용할 때는 불가능합니다.

나는 머리를 쓰는 데 약간의 시간이 걸렸지 만 마침내 해결책은 실제로 매우 단순 해 보였다.

public class AggregateRoute : RouteBase 
{ 
    private readonly RouteBase[] _routes; 

    public AggregateRoute(params RouteBase[] routes) 
    { 
    _routes = routes; 
    } 

    public override RouteData GetRouteData(HttpContextBase httpContext) 
    { 
    RouteData routeData = null; 
    foreach (var route in _routes) 
    { 
     routeData = route.GetRouteData(httpContext); 
     if (routeData != null) break; 
    } 

    return routeData; 
    } 

    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values) 
    { 
    VirtualPathData virtualPath = null; 
    foreach (var route in _routes) 
    { 
     virtualPath = route.GetVirtualPath(requestContext, values); 
     if (virtualPath != null) break; 
    } 

    return virtualPath; 
    } 
} 

이 나를 수행 할 수 있습니다 : 난 그냥 중간 집계 경로를 만드는 데 필요한

별도로 두 경로를 추가 할 때 불가능하다 같은 이름에 의해 해결 경로 중 하나를 수
routes.Add(
    "RouteName", 
    new AggregateRoute(
     new Route("{path}", new MvcRouteHandler()), 
     new Route("{prefix}/{path}", new MvcRouteHandler()) 
    ) 
); 

:

Url.RouteLink("RouteName", new RouteValueDictionary{ 
    new{path="some-path"}}); 

Url.RouteLink("RouteName", new RouteValueDictionary{ 
    new{path="some-prefix/some-path"}}); 
관련 문제