메서드 특성을 통한 ASP.NET MVC 라우팅 [닫힌]


80

에서 StackOverflow의 포드 캐스트 # 54 , 제프들은 StackOverflow에 자신의 URL 경로는 방법을 처리하는 경로 위의 속성을 통해 코드베이스 등록 언급하고있다. 좋은 개념처럼 들립니다 (Phil Haack이 경로 우선 순위에 대해 제기 한 경고 포함).

누군가이를 위해 샘플을 제공 할 수 있습니까?

또한이 라우팅 스타일을 사용하기위한 "모범 사례"가 있습니까?

답변:


62

업데이트 : 이것은 codeplex 에 게시되었습니다. 전체 소스 코드와 사전 컴파일 된 어셈블리를 다운로드 할 수 있습니다. 아직 사이트에 문서를 게시 할 시간이 없었기 때문에 지금은이 글로 충분해야합니다.

업데이트 : 1) 경로 순서 지정, 2) 경로 매개 변수 제약 조건 및 3) 경로 매개 변수 기본값을 처리하기 위해 몇 가지 새로운 속성을 추가했습니다. 아래 텍스트는이 업데이트를 반영합니다.

실제로 MVC 프로젝트에 대해 이와 같은 작업을 수행했습니다 (Jeff가 stackoverflow로 어떻게 작업하는지 모르겠습니다). 사용자 지정 특성 집합 인 UrlRoute, UrlRouteParameterConstraint, UrlRouteParameterDefault를 정의했습니다. 경로, 제약 조건 및 기본값이 자동으로 바인딩되도록 MVC 컨트롤러 작업 메서드에 연결할 수 있습니다.

사용 예 :

(이 예제는 다소 인위적이지만 기능을 보여줍니다)

public class UsersController : Controller
{
    // Simple path.
    // Note you can have multiple UrlRoute attributes affixed to same method.
    [UrlRoute(Path = "users")]
    public ActionResult Index()
    {
        return View();
    }

    // Path with parameter plus constraint on parameter.
    // You can have multiple constraints.
    [UrlRoute(Path = "users/{userId}")]
    [UrlRouteParameterConstraint(Name = "userId", Regex = @"\d+")]
    public ActionResult UserProfile(int userId)
    {
        // ...code omitted

        return View();
    }

    // Path with Order specified, to ensure it is added before the previous
    // route.  Without this, the "users/admin" URL may match the previous
    // route before this route is even evaluated.
    [UrlRoute(Path = "users/admin", Order = -10)]
    public ActionResult AdminProfile()
    {
        // ...code omitted

        return View();
    }

    // Path with multiple parameters and default value for the last
    // parameter if its not specified.
    [UrlRoute(Path = "users/{userId}/posts/{dateRange}")]
    [UrlRouteParameterConstraint(Name = "userId", Regex = @"\d+")]
    [UrlRouteParameterDefault(Name = "dateRange", Value = "all")]
    public ActionResult UserPostsByTag(int userId, string dateRange)
    {
        // ...code omitted

        return View();
    }

UrlRouteAttribute의 정의 :

/// <summary>
/// Assigns a URL route to an MVC Controller class method.
/// </summary>
[AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class UrlRouteAttribute : Attribute
{
    /// <summary>
    /// Optional name of the route.  If not specified, the route name will
    /// be set to [controller name].[action name].
    /// </summary>
    public string Name { get; set; }

    /// <summary>
    /// Path of the URL route.  This is relative to the root of the web site.
    /// Do not append a "/" prefix.  Specify empty string for the root page.
    /// </summary>
    public string Path { get; set; }

    /// <summary>
    /// Optional order in which to add the route (default is 0).  Routes
    /// with lower order values will be added before those with higher.
    /// Routes that have the same order value will be added in undefined
    /// order with respect to each other.
    /// </summary>
    public int Order { get; set; }
}

UrlRouteParameterConstraintAttribute의 정의 :

/// <summary>
/// Assigns a constraint to a route parameter in a UrlRouteAttribute.
/// </summary>
[AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class UrlRouteParameterConstraintAttribute : Attribute
{
    /// <summary>
    /// Name of the route parameter on which to apply the constraint.
    /// </summary>
    public string Name { get; set; }

    /// <summary>
    /// Regular expression constraint to test on the route parameter value
    /// in the URL.
    /// </summary>
    public string Regex { get; set; }
}

UrlRouteParameterDefaultAttribute의 정의 :

/// <summary>
/// Assigns a default value to a route parameter in a UrlRouteAttribute
/// if not specified in the URL.
/// </summary>
[AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class UrlRouteParameterDefaultAttribute : Attribute
{
    /// <summary>
    /// Name of the route parameter for which to supply the default value.
    /// </summary>
    public string Name { get; set; }

    /// <summary>
    /// Default value to set on the route parameter if not specified in the URL.
    /// </summary>
    public object Value { get; set; }
}

Global.asax.cs의 변경 사항 :

MapRoute에 대한 호출을 RouteUtility.RegisterUrlRoutesFromAttributes 함수에 대한 단일 호출로 바꿉니다.

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        RouteUtility.RegisterUrlRoutesFromAttributes(routes);
    }

RouteUtility.RegisterUrlRoutesFromAttributes의 정의 :

전체 소스는 codeplex에 있습니다. 피드백이나 버그 보고서가 있으면 사이트로 이동하십시오.


속성을 사용하면 경로 기본값과 경로 제약 조건을 사용하지 못하는 것 같습니다 ...
Nicolas Cadilhac

이 접근 방식에서는 각 경로를 특정 메서드에 바인딩하기 때문에 기본 경로가 필요하지 않았습니다. 당신은 제약에 대해 옳습니다. 제약 조건을 속성 속성으로 추가 할 수 있는지 살펴 보았지만 MVC 제약 조건이 익명 개체를 사용하여 지정되고 속성 속성이 단순 유형일 수 있다는 점에서 문제가 발생했습니다. 제약 조건을 속성 (더 많은 코딩 포함)으로 수행하는 것이 여전히 가능하다고 생각하지만 MVC 작업에 제약이 실제로 필요하지 않았기 때문에 아직 신경 쓰지 않았습니다 (경로 값의 유효성을 검사하는 경향이 있습니다). 컨트롤러에서).
DSO

3
아주 좋아요! RouteAttribute는 이와 매우 유사하며 약간의 추가 도우미 기능 만 추가합니다. 차이점을 자세히 설명하는 답변을 추가해야합니다.
Jarrod Dixon

1
이건 끝내줘. 나는 그것을 사랑 해요.
BowserKingKoopa

1
이것은 대단합니다! 나는 한동안 MvcContrib을 사용해 왔으며 이것이 거기에 있다는 것을 몰랐습니다. 원본 게시물에서 문서화 할 시간이 없다고 언급하셨습니다. 그래도 그래요? MvcContrib 문서에서 적어도 그것에 대한 언급은 개발자가 적어도 그것이 있다는 것을 알 수 있도록 매우 도움이 될 것 같습니다. 감사!
Todd Menier

44

github 또는 nuget을 통해 사용할 수있는 AttributeRouting 을 사용해 볼 수도 있습니다 .

제가 프로젝트 작성자이기 때문에 이것은 뻔뻔한 플러그입니다. 그러나 내가 그것을 사용하는 것이별로 행복하지 않다면 dang. 당신도 그럴 수 있습니다. github 저장소 위키 에는 많은 문서와 샘플 코드가 있습니다.

이 라이브러리를 사용하면 다음과 같은 많은 작업을 수행 할 수 있습니다.

  • GET, POST, PUT 및 DELETE 속성으로 작업을 장식하십시오.
  • 여러 경로를 단일 작업에 매핑하고 Order 속성으로 순서를 지정합니다.
  • 속성을 사용하여 경로 기본값 및 제약 조건을 지정합니다.
  • 간단한?로 선택적 매개 변수를 지정하십시오. 매개 변수 이름 앞의 토큰.
  • 명명 된 경로를 지원하기위한 경로 이름을 지정합니다.
  • 컨트롤러 또는 기본 컨트롤러에서 MVC 영역을 정의합니다.
  • 컨트롤러 또는 기본 컨트롤러에 적용된 경로 접두사를 사용하여 경로를 그룹화하거나 중첩합니다.
  • 레거시 URL을 지원합니다.
  • 작업에 대해 정의 된 경로, 컨트롤러 내, 컨트롤러 및 기본 컨트롤러 간의 경로 우선 순위를 설정합니다.
  • 소문자 아웃 바운드 URL을 자동으로 생성합니다.
  • 고유 한 사용자 지정 경로 규칙을 정의하고이를 컨트롤러에 적용하여 상용구 속성없이 컨트롤러 내에서 작업에 대한 경로를 생성합니다 (RESTful 스타일을 고려하십시오).
  • 제공된 HttpHandler를 사용하여 경로를 디버그합니다.

내가 잊고있는 다른 것들이있을 거라고 확신합니다. 확인 해봐. 너겟을 통해 설치하는 것은 어렵지 않습니다.

참고 : 2012 년 4 월 16 일부터 AttributeRouting은 새로운 웹 API 인프라도 지원합니다. 당신이 그것을 처리 할 수있는 것을 찾고 있다면. 감사합니다 subkamran !


10
다른 옵션은 언급보다이 프로젝트는 이상 (더 나은 문서, 더 기능, 완벽한 테스트 스위트를) 성숙 보인다
데이빗 레잉에게

3
동의합니다. 이것은 당신이 원하는 모든 것을 할 수 있고 좋은 예제 문서를 가지고 있습니다.
Mike Chamberlain

3
대단히 감사합니다. 이 솔루션을 기쁘게 사용하고 있으며 라우팅 충돌, 모호성 및 혼란을 모두 해결했습니다.
Valamas 2011

3
이봐, 난이 SO 게시물을 발견 나는 :) 자세한 내용은 사냥을했다 당신이, 당신의 GitHub의 페이지에 위의 글 머리 기호를 작성해야, 자리
GONeale

2
악마 옹호자 역할을하는 것만으로도 모든 경로를 한곳에서 선언하는 것이 어떤 이점이 있습니까? 우리는 무엇을 잃거나이 방법으로 전환하는 데 제한이 있습니까?
GONeale 2011 년

9

1. RiaLibrary.Web.dll을 다운로드 하고 ASP.NET MVC 웹 사이트 프로젝트에서 참조합니다.

2. [Url] 속성을 사용하여 컨트롤러 메서드를 장식합니다.

public SiteController : Controller
{
    [Url("")]
    public ActionResult Home()
    {
        return View();
    }

    [Url("about")]
    public ActionResult AboutUs()
    {
        return View();
    }

    [Url("store/{?category}")]
    public ActionResult Products(string category = null)
    {
        return View();
    }
}

BTW, '?' 로그인 '{? category}'매개 변수는 선택 사항임을 의미합니다. 다음과 같은 경로 기본값에 명시 적으로 지정할 필요가 없습니다.

routes.MapRoute("Store", "store/{category}",
new { controller = "Store", action = "Home", category = UrlParameter.Optional });

3. Global.asax.cs 파일 업데이트

public class MvcApplication : System.Web.HttpApplication
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapRoutes(); // This does the trick
    }

    protected void Application_Start()
    {
        RegisterRoutes(RouteTable.Routes);
    }
}

기본값 및 제약 조건을 설정하는 방법은 무엇입니까? 예:

public SiteController : Controller
{
    [Url("admin/articles/edit/{id}", Constraints = @"id=\d+")]
    public ActionResult ArticlesEdit(int id)
    {
        return View();
    }

    [Url("articles/{category}/{date}_{title}", Constraints =
         "date=(19|20)\d\d-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])")]
    public ActionResult Article(string category, DateTime date, string title)
    {
        return View();
    }
}

주문 설정 방법? 예:

[Url("forums/{?category}", Order = 2)]
public ActionResult Threads(string category)
{
    return View();
}

[Url("forums/new", Order = 1)]
public ActionResult NewThread()
{
    return View();
}

1
아주 좋아요! 나는 특히 {?param}선택적 매개 변수에 대한 명명법을 좋아합니다 .
Jarrod Dixon

3

이 게시물은 DSO의 답변을 확장하기위한 것입니다.

내 경로를 속성으로 변환하는 동안 ActionName 속성을 처리해야했습니다. 따라서 GetRouteParamsFromAttribute에서 :

ActionNameAttribute anAttr = methodInfo.GetCustomAttributes(typeof(ActionNameAttribute), false)
    .Cast<ActionNameAttribute>()
    .SingleOrDefault();

// Add to list of routes.
routeParams.Add(new MapRouteParams()
{
    RouteName = routeAttrib.Name,
    Path = routeAttrib.Path,
    ControllerName = controllerName,
    ActionName = (anAttr != null ? anAttr.Name : methodInfo.Name),
    Order = routeAttrib.Order,
    Constraints = GetConstraints(methodInfo),
    Defaults = GetDefaults(methodInfo),
});

또한 경로 이름이 적합하지 않음을 발견했습니다. 이름은 controllerName.RouteName을 사용하여 동적으로 빌드됩니다. 그러나 내 경로 이름은 컨트롤러 클래스의 const 문자열이며 해당 const를 사용하여 Url.RouteUrl도 호출합니다. 그래서 실제로 경로의 실제 이름이되는 속성의 경로 이름이 필요합니다.

내가 할 또 다른 일은 기본 및 제약 조건 속성을 AttributeTargets.Parameter로 변환하여 매개 변수에 고정 할 수 있도록하는 것입니다.


예, 저는 경로 이름 지정 동작에 약간의 진동을가했습니다. 당신이 한 일을하는 것이 가장 좋을 것입니다. 속성에있는 것을 그대로 사용하거나 null로 만드십시오. 매개 변수 자체에 기본값 / 제약 조건을 설정하는 것이 좋습니다. 변경 사항을 더 잘 관리하기 위해 언젠가 codeplex에 게시 할 것입니다.
DSO


0

AsyncController를 사용하여 asp.net mvc 2에서 ITCloud 라우팅이 작동하도록해야했습니다. 그렇게하려면 소스에서 RouteUtility.cs 클래스를 편집하고 다시 컴파일하기 만하면됩니다. 98 행의 작업 이름에서 "Completed"를 제거해야합니다.

// Add to list of routes.
routeParams.Add(new MapRouteParams()
{
    RouteName = String.IsNullOrEmpty(routeAttrib.Name) ? null : routeAttrib.Name,
    Path = routeAttrib.Path,
    ControllerName = controllerName,
    ActionName = methodInfo.Name.Replace("Completed", ""),
    Order = routeAttrib.Order,
    Constraints = GetConstraints(methodInfo),
    Defaults = GetDefaults(methodInfo),
    ControllerNamespace = controllerClass.Namespace,
});

그런 다음 AsyncController에서 XXXXCompleted ActionResult를 익숙한 속성 UrlRouteUrlRouteParameterDefault속성으로 장식 합니다.

[UrlRoute(Path = "ActionName/{title}")]
[UrlRouteParameterDefault(Name = "title", Value = "latest-post")]
public ActionResult ActionNameCompleted(string title)
{
    ...
}

같은 문제를 가진 사람에게 도움이되기를 바랍니다.


참고로, 규칙은 ActionNameCompleted 메서드가 아닌 ActionNameAsync 메서드에 MVC 관련 특성을 갖는 것입니다.
Erv Walter

고마워-몰랐어.
TimDog
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.