7

私が持っているのは、次の拡張メソッドです。

public MyCustomAttribute[] GetActionAttributes(
    this Controller @this,
    string action,
    string controller,
    string area,
    string method)
{
}

ASP.NET MVC 3 は、領域、コントローラー、アクション名、およびメソッド (GET、POST) を指定して、アクション メソッドをどのように見つけますか?

今のところ、私には何もありません...これを行う方法についての手がかりはありません。

現在、コントローラー アクション内のスタック トレースを探して、MVC がそれをどのように発見したかを調べています。

これらの属性が必要な理由

私の属性には、特定のユーザーがアクセスできるかどうかに関する情報が含まれています...しかし、アクセスできるかどうかに応じて、一部の html フィールド、リンク、およびそのアクションを呼び出すことができるその他のものを表示または非表示にしたくありません.

その他の用途

これを使用してアクションに属性を配置し、それを呼び出すためにレンダリングされるリンクの css クラスに指示することを考えました...そして他のいくつかの UI ヒント...そしてそのリンクをレンダリングする HtmlHelper を構築します、これらの属性を見てください。

重複していません

はい、これはおそらくこの質問の複製であると言う人もいます...それには私が望む答えがありません:

リクエストを受けて呼び出されるコントローラ アクションの MethodInfo を取得するにはどうすればよいですか?

そのため、質問の状況を特定しました。

4

4 に答える 4

11

私は MVC 3 のソース コードを調べ、MVC 4 でテストし、その方法を発見しました。質問に間違ったタグを付けました... MVC 3用ではなく、MVC 4を使用しています.MVC 3コードを見て解決策を見つけることができたので、MVC 3でも動作する可能性があります

最後に... 試行錯誤を繰り返しながら 5 時間の調査を行う価値があることを願っています。

で動作します

  • MVC 3(だと思います)
  • MVC 4 (テスト済み)

私のソリューションの欠点

残念ながら、このソリューションは非常に複雑で、私があまり好きではないものに依存しています。

  • 静的オブジェクトControllerBuilder.Current(単体テストには非常に悪い)
  • MVC からの多くのクラス(高結合は常に悪い)
  • 普遍的ではありません (MVC 3 の既定のオブジェクトでは機能しますが、MVC から派生した他の実装では機能しない可能性があります。たとえば、派生した MvcHandler、カスタム IControllerFactory など...)
  • 内部の依存関係(MVC 3 の特定の側面に依存します (MVC 4 もこのように動作します)、MVC 5 は異なる場合があります。たとえばRouteData、コントローラーの種類を見つけるためにオブジェクトが使用されないことがわかっているため、単純にスタブ RouteData オブジェクトを使用します)
  • データを渡すための複雑なオブジェクトのモック (モックHttpContextWrapperを作成し、をorHttpRequestWrapperに設定する必要がありました... これらの非常に単純な値は、複雑なオブジェクトから取得されます (なんてこった! =\ ))http methodPOSTGET

コード

public static Attribute[] GetAttributes(
    this Controller @this,
    string action = null,
    string controller = null,
    string method = "GET")
{
    var actionName = action
        ?? @this.RouteData.GetRequiredString("action");

    var controllerName = controller
        ?? @this.RouteData.GetRequiredString("controller");

    var controllerFactory = ControllerBuilder.Current
        .GetControllerFactory();

    var controllerContext = @this.ControllerContext;

    var otherController = (ControllerBase)controllerFactory
        .CreateController(
            new RequestContext(controllerContext.HttpContext, new RouteData()),
            controllerName);

    var controllerDescriptor = new ReflectedControllerDescriptor(
        otherController.GetType());

    var controllerContext2 = new ControllerContext(
        new MockHttpContextWrapper(
            controllerContext.HttpContext.ApplicationInstance.Context,
            method),
        new RouteData(),
        otherController);

    var actionDescriptor = controllerDescriptor
        .FindAction(controllerContext2, actionName);

    var attributes = actionDescriptor.GetCustomAttributes(true)
        .Cast<Attribute>()
        .ToArray();

    return attributes;
}

編集

モッククラスを忘れた

class MockHttpContextWrapper : HttpContextWrapper
{
    public MockHttpContextWrapper(HttpContext httpContext, string method)
        : base(httpContext)
    {
        this.request = new MockHttpRequestWrapper(httpContext.Request, method);
    }

    private readonly HttpRequestBase request;
    public override HttpRequestBase Request
    {
        get { return request; }
    }

    class MockHttpRequestWrapper : HttpRequestWrapper
    {
        public MockHttpRequestWrapper(HttpRequest httpRequest, string httpMethod)
            : base(httpRequest)
        {
            this.httpMethod = httpMethod;
        }

        private readonly string httpMethod;
        public override string HttpMethod
        {
            get { return httpMethod; }
        }
    }
}

これがすべて誰かに役立つことを願っています...

みんなでハッピーコーディング!

于 2012-10-24T07:44:49.763 に答える
3

AuthorizeAttributeを使用して、この機能を実現できます。OnAuthorizationメソッドで Controller と Action の名前を取得できます。以下のサンプルコードを見つけてください。

 public sealed class AuthorizationFilterAttribute : AuthorizeAttribute
    {
        /// <summary>
        /// Use for validate user permission and  when it also validate user session is active.
        /// </summary>
        /// <param name="filterContext">Filter Context.</param>
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            string actionName = filterContext.ActionDescriptor.ActionName;
            string controller = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
            if (!IsUserHasPermission(controller, actionName))
            {
               // Do your required opeation
            }
        }
    }
于 2012-10-24T06:20:32.717 に答える
0

これは急な通知です!必ずfilterContext.RouteData.DataTokens["area"];を使用してください。filterContext.RouteData.Values["area"]の代わりに;

幸運を。

于 2013-02-07T17:02:39.867 に答える
0

次のように構成されたデフォルトルートがある場合

routes.MapRoute(
        "Area",
        "",
        new { area = "MyArea", controller = "Home", action = "MyAction" }
    );

次のようなコントローラーアクション内のルート情報を取得できます

ht tp://localhost/Admin

あなたにあげます

public ActionResult MyAction(string area, string controller, string action)
{
 //area=Admin
 //controller=Home
 //action=MyAction
 //also you can use RouteValues to get the route information
}

Phil Haack RouteDebugger 2.0によるすばらしいブログ投稿とユーティリティを次に示します。

于 2012-10-24T05:04:59.313 に答える