web-dev-qa-db-ja.com

メソッド属性によるASP.NET MVCルーティング

StackOverflow Podcast#54 で、Jeffは、ルートを処理するメソッドの上の属性を介してStackOverflowコードベースにURLルートを登録することに言及しています。良いコンセプトのように聞こえます(Phil Haackがルートの優先順位に関して提起した警告付き)。

誰かがこれを実現するためのサンプルを提供できますか?

また、このスタイルのルーティングを使用するための「ベストプラクティス」はありますか?

80
TorgoGuy

[〜#〜] update [〜#〜]:これは codeplexに投稿されました 。完全なソースコードとプリコンパイルされたアセンブリがダウンロードできます。私はまだサイトにドキュメントを投稿する時間がありませんでしたので、今のところSOの投稿で十分です。

[〜#〜] update [〜#〜]:I 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への変更:

RouteUtility.RegisterUrlRoutesFromAttributes関数の1回の呼び出しで、MapRouteの呼び出しを置き換えます。

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

        RouteUtility.RegisterUrlRoutesFromAttributes(routes);
    }

RouteUtility.RegisterUrlRoutesFromAttributesの定義:

完全なソースは codeplex にあります。フィードバックやバグ報告がある場合は、サイトにアクセスしてください。

62
DSO

AttributeRouting を試すこともできます。これは github または nuget から利用できます。

私はプロジェクトの著者であるため、これは恥知らずなプラグインです。しかし、私はそれを使用して非常に満足していない場合はダン。あなたもかもしれません。 githubリポジトリには多くのドキュメントとサンプルコードがあります wiki

このライブラリを使用すると、多くのことができます。

  • GET、POST、PUT、およびDELETE属性でアクションを飾ります。
  • 複数のルートを1つのアクションにマップし、Orderプロパティで順序付けします。
  • 属性を使用して、ルートのデフォルトと制約を指定します。
  • 単純な?でオプションのパラメーターを指定しますパラメータ名の前のトークン。
  • 名前付きルートをサポートするためのルート名を指定します。
  • コントローラーまたはベースコントローラーでMVCエリアを定義します。
  • コントローラーまたはベースコントローラーに適用されるルートプレフィックスを使用して、ルートをグループ化またはネストします。
  • レガシーURLをサポートします。
  • アクションに対して定義されたルート間、コントローラー内、およびコントローラーとベースコントローラー間のルートの優先順位を設定します。
  • 小文字のアウトバウンドURLを自動的に生成します。
  • 独自のカスタムルート規則を定義し、それらをコントローラーに適用して、ボイラープレート属性なしでコントローラー内のアクションのルートを生成します(RESTfulスタイルを考えてください)。
  • 提供されたHttpHandlerを使用してルートをデバッグします。

私は忘れている他のものがいくつかあると確信しています。見てみな。 nugetを使用してインストールするのは簡単です。

注:2012年4月16日の時点で、AttributeRoutingは新しいWeb APIインフラストラクチャもサポートしています。それを処理できるものを探している場合に備えて。 サブカムランに感謝

44
spot

1。 RiaLibrary.Web.dll をダウンロードし、ASP.NET MVC Webサイトプロジェクトで参照します

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();
    }
}

ところで、「?」サインイン '{?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();
}
9

この投稿は、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も呼び出します。そのため、実際に属性のルート名を実際のルート名にする必要があります。

もう1つ行うことは、既定の属性と制約属性をAttributeTargets.Parameterに変換して、paramsに固定できるようにすることです。

3

AsyncControllerを使用してasp.net mvc 2でITCloudルーティングを動作させる必要がありました。そのためには、ソースのRouteUtility.csクラスを編集して再コンパイルします。 98行目のアクション名から「完了」を削除する必要があります

// 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を使い慣れたUrlRouteおよびUrlRouteParameterDefault属性で装飾します。

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

同じ問題を抱えている人を助けることを願っています。

0
TimDog

私はこれらの2つのアプローチを組み合わせて、フランケンシュタインのバージョンを望んでいます。 (オプションのparam表記が好きでしたが、すべてが1つに混在するのではなく、デフォルト/制約とは別の属性であるべきだと考えました)。

http://github.com/djMax/AlienForce/tree/master/Utilities/Web/

0
Max Metral