2013-12-18 6 views
1


URL을 C#의 파스칼 케이스에서 SEO 친숙한 형식으로 다시 작성하려고합니다.
예를 들어, 나는 /User/Home/MyJumbledPageName 같은 것을 같이 할 :MapRoute 메서드에서 URL 재 작성을 일반적으로 어떻게 구현합니까?

/user/home/my-jumbled-page-name // lower-case, and words separated by dashes 


것은 다음의 URL에서 각각 "토큰"을 변환하는 나의 방법 :

public static string GetSEOFriendlyToken(string token) 
{ 
    StringBuilder str = new StringBuilder(); 

    for (int i = 0, len = token.Length; i < len; i++) 
    { 
     if (i == 0) 
     { 
      // setting the first capital char to lower-case: 
      str.Append(Char.ToLower(token[i])); 
     } 
     else if (Char.IsUpper(token[i])) 
     { 
      // setting any other capital char to lower-case, preceded by a dash: 
      str.Append("-" + Char.ToLower(token[i])); 
     } 
     else 
     { 
      str.Append(token[i]); 
     } 
    } 
    return str.ToString(); 
} 


.. 그리고 내 RouteConfig.cs 루트에있는 파일에서 다음 경로를 매핑했습니다.

이 코드


(10), /AboutTheAuthor내가 원하는 무엇으로 변환되지 등의 URL, /about-the-author 될 것이다.

내 메소드 호출이 무시 된 것 같습니다. 여기서 어떻게됩니까? 그리고 이것을 구현하는 전통적인 방법은 무엇입니까?

답변

2

당신은 당신의 자신의 RouteBase 클래스 또는 서브 클래스 Route

public class SeoFriendlyRoute : Route 
{ 
    private readonly string[] _valuesToSeo; 

    public SeoFriendlyRoute(string url, RouteValueDictionary defaults, IEnumerable<string> valuesToSeo, RouteValueDictionary constraints = null, RouteValueDictionary dataTokens = null, IRouteHandler routeHandler = null) 
     : base(url, defaults, constraints ?? new RouteValueDictionary(), dataTokens ?? new RouteValueDictionary(), routeHandler ?? new MvcRouteHandler()) 
    { 
     if (valuesToSeo == null) { throw new ArgumentNullException("valuesToSeo"); } 
     _valuesToSeo = valuesToSeo.ToArray(); 
    } 
    public override RouteData GetRouteData(HttpContextBase httpContext) 
    { 
     var routeData = base.GetRouteData(httpContext); 
     if (routeData != null) 
     { 
      foreach (var key in _valuesToSeo) 
      { 
       if (routeData.Values.ContainsKey(key)) 
       { 
        routeData.Values[key] = GetActualValue((string)routeData.Values[key]); 
       } 
      } 
     } 
     return routeData; 
    } 
    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values) 
    { 
     var seoFriendyValues = new RouteValueDictionary(values); 
     foreach (var key in _valuesToSeo) 
     { 
      if (seoFriendyValues.ContainsKey(key)) 
      { 
       seoFriendyValues[key] = GetSeoFriendlyValue((string)seoFriendyValues[key]); 
      } 
     } 
     return base.GetVirtualPath(requestContext, seoFriendyValues); 
    } 

    private string GetSeoFriendlyValue(string actualValue) 
    { 
     //your method 
     StringBuilder str = new StringBuilder(); 
     for (int i = 0, len = actualValue.Length; i < len; i++) 
     { 
      if (i == 0) 
      { 
       str.Append(Char.ToLower(actualValue[i])); 
      } 
      else if (Char.IsUpper(actualValue[i])) 
      { 
       str.Append("-" + Char.ToLower(actualValue[i])); 
      } 
      else 
      { 
       str.Append(actualValue[i]); 
      } 
     } 
     return str.ToString(); 
    } 

    private static string GetActualValue(string seoFriendlyValue) 
    { 
     //action name is not case sensitive 
     //one limitation is the dash can be anywhere but the action will still be resolved 
     // /my-jumbled-page-name is same as /myjumbled-pagename 
     return seoFriendlyValue.Replace("-", string.Empty); 
    } 
} 

사용

참고로
routes.Add("Default", new SeoFriendlyRoute(
    url: "{controller}/{action}/{id}", 
    valuesToSeo: new string[] { "action", "controller" }, 
    defaults: new RouteValueDictionary(new { controller = "Home", action = "Index", id = UrlParameter.Optional })) 
); 
+0

감사합니다. @LostInComputer! 이것은 나를 위해 토끼 구멍을 조금 더 내려다 보니, 나는 당신의 코드를 연구 해왔다.나는 당신이 "null coalescing operator"를 사용하고 있다는 것을 배웠습니다. "??"는 삼항 연산자의 속기입니다. 또한 Visual Studio에서 'Route'를 마우스 오른쪽 버튼으로 클릭하고 'Peek Definition'을 선택하여 'Route'에 'base'를 호출하는 데 필요한 생성자 매개 변수를 사용하고 있음을 알 수 있습니다. 그렇지 않으면'GetRouteData'와'GetVirtualPath'를 오버라이드하는 방법을 어떻게 알고 있습니까? 프레임 워크에서 이러한 메소드가 호출되는 위치는 어디입니까? –

+0

내가 가진 다른 질문은'GetActualValue' 메소드가이 로직에 대한 요구 사항이고,이 클래스를 프로젝트에 넣을 좋은 곳은 어디입니까? –

+1

'GetVirtualPath'는 MVC가'@ Html.Action'을 호출 할 때처럼 URL을 생성하기 위해 호출됩니다. 'GetRouteData'는 그 반대로, URL로부터 컨트롤러 액션을 얻기 위해 MVC에 의해 호출됩니다. 내가 어떻게 알았지? 나는 때때로 오픈 소스 인 MVC 소스 코드를 통해 갈 것이다. – LostInComputer

2


를 정의해야합니다, 나는에 대한 @LostInComputer의 코드가 작동하는 방법을 발견했다 지역뿐만 아니라. 영역에 사용되는 클래스는 에 대해 IRouteWithArea을 구현하여 영역의 RegisterArea 메소드에서 작동해야합니다. 여기

는 지역 (이것은 위의 SEOFriendlyRoute 클래스를 확장)에 사용할 수있는 제네릭 클래스입니다 :

public class AreaSEOFriendlyRoute : SEOFriendlyRoute, IRouteWithArea 
{ 
    private readonly string _areaName; 

    // constructor: 
    public AreaSEOFriendlyRoute(string areaName, string url, RouteValueDictionary defaults, IEnumerable<string> valuesToSeo, 
     RouteValueDictionary constraints = null, RouteValueDictionary dataTokens = null, IRouteHandler routeHandler = null) 
     : base(url, defaults, valuesToSeo, constraints, dataTokens, routeHandler) 
    { 
     this._areaName = areaName; 
    } 

    // implemented from IRouteWithArea: 
    public string Area 
    { 
     get 
     { 
      return this._areaName; 
     } 
    } 
} 


... 그리고 그 '사용 :

public override void RegisterArea(AreaRegistrationContext context) 
{ 
    context.Routes.Add("Example", new AreaSEOFriendlyRoute(
     areaName: this.AreaName, 
     url: "my-area/{action}/{id}", 
     valuesToSeo: new string[] { "action", "controller" }, 
     defaults: new RouteValueDictionary(new { controller = "MyController", action = "MyDefaultPage", id = UrlParameter.Optional })) 
    ); 
} 


주 으로 정의 된 context.Routes.Add을 호출 할 때 추가 인수가 전달됩니다. 생성자의 동일한 이름의 형식적 매개 변수는 Area 메서드에서이 값을 반환하는 데 사용되며 IRouteWithArea에서 구현됩니다.


그래서 링크는 다음과 같은 :


@Html.ActionLink("my link text", "MyJumbledPageName", "MyController", 
new { area = "MyArea" }, null) 
은 ... URL을 my-area/my-jumbled-page-name 될 것입니다. URL의 앞의 " my-area"은 경로의 url 인수에 하드 코딩하여 얻습니다.

관련 문제