5

私は現在asp.netmvc4アプリケーションに取り組んでおり、次のタイプのURLが必要です。

ルーティングする必要のあるURL

  1. http://www.mysite.com/foo/user1 <-------{ユーザー名}
  2. http://www.mysite.com/foo/edit
  3. http://www.mysite.com/foo/delete/1
  4. http://www.mysite.com/bar/user1 <-------{ユーザー名}
  5. http://www.mysite.com/bar/edit
  6. http://www.mysite.com/bar/delete/1

私が抱えている問題は、現在{username}がアクションとして扱われるため、次のルートを実装した問題を回避することですが、これは、新しいアクションを実装するたびに、または必要なコントローラーが必要になることを意味します{ユーザー名}、ルートを更新する必要があります:

表示されているのはFooルートのみ

routes.MapRoute("FooSomeAction", "foo/someaction", new { controller = "Food", action = "SomeAction" });            
routes.MapRoute("FooDelete", "foo/delete/{id}", new { controller = "Food", action = "Delete" });            


routes.MapRoute(
    "FooProfile",
    "foo/{username}",
    new { controller = "Foo", action = "Index", username = "" }
);


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

2つの質問

1)すべてのルートをハードコーディングせずに上記のURLを実現する方法はありますか?

2)誰かがたまたまコントローラーまたはアクション名と同じ名前のユーザー名を使用する状況を処理するための最良の方法は何ですか?

DotnetShadow

4

3 に答える 3

3

コントローラの可能なアクションにユーザー名が存在するかどうかを確認するカスタムルート制約を作成できます。アクションの一致が見つかった場合、失敗し、デフォルトルートを使用します(たとえば、編集)。パフォーマンス上の理由からリストをキャッシュすることをお勧めしますが、それはあなたに任せます。

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

    public static  List<string> GetActionNames(string controllerName)
    {
        controllerName = controllerName + "Controller";
        var controller = GetSubClasses<Controller>().FirstOrDefault(c => c.Name == controllerName);

        var names = new List<string>();
        if (controller != null)
        {
            var methods = controller.GetMethods(BindingFlags.Public | BindingFlags.Instance);
            foreach (var info in methods)
            {
                if (info.ReturnType == typeof(ActionResult))
                {
                    names.Add(info.Name);
                }
            }

        }
        return names;
    }


    public class UsernameNotAction : IRouteConstraint
    {
        public bool Match
            (
                HttpContextBase httpContext,
                Route route,
                string parameterName,
                RouteValueDictionary values,
                RouteDirection routeDirection
            )
        {
            int i = 0;
            var username = values["username"];
            var actionList =  GetActionNames(values["controller"].ToString());

            return !actionList.Any(a => a.ToUpper() == username.ToString().ToUpper());
        }
    }


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

        routes.MapRoute(
            "FooProfile",
            "{controller}/{username}",
            new { controller = "Home", action = "Index2", username = "" },
            new { IsParameterAction = new UsernameNotAction() }
        );
        // Default route
        routes.MapRoute(
            "Default", // Route name
            "{controller}/{action}/{id}",
            new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    }
于 2013-02-28T12:59:39.293 に答える
2

これは本当にあなたが探している答えではありません、ごめんなさい。

1)そのようにルーティングする方法はありません。あなたがしたこと以外に、これらのルートを互いに区別するものは何もありません。なぜこれが必要なのか疑問に思う必要があります。あなたには正当な理由があると確信していますが、それは私には意味がありません。まだインデックスアクションを使用しているので、/ foo / index/usernameだけではないのはなぜですか。私が思いつくことができるのは、何らかの理由でURLを制御できないということだけです。

2)デフォルトルートを使用すれば問題ありません。あなたのルーティングで、問題。唯一の実際のオプションは、コントローラーとアクションの名前を予約語にすることです(ユーザーがデータベース内のそれらのユーザー名で作成されないようにします)。

申し訳ありませんが、私は本当にあなたを助けることができませんでした。

于 2013-02-28T13:06:15.737 に答える
1

すべてのルートをルーティングしない限り、そのようにすることはできません。それが最善の方法ではありません。

アクション名を含めることの何が問題になっていますか?

于 2013-02-28T13:05:46.367 に答える