2009-05-20 84 views
1

我有一個自定義ViewEngine,我想根據請求的動作是否具有Authorize屬性過濾器來修改主頁面。在ASP.NET MVC的ViewEngine中查找動作的序列號

這樣到目前爲止,我只是用反射:

var method = controllerContext.Controller.GetType().GetMethod(viewName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase); 
if (method != null) 
{ 
    if (method.GetCustomAttributes(typeof(AuthorizeAttribute), true).Length > 0) 
    { 
     masterName = "Admin.master"; 
    } 
} 

但我不使用反射的重複性任務的一個巨大的風扇。我知道我可以使用視圖緩存在第一次之後加快速度,但是我想知道是否有更直接的方法可以訪問應用於ViewEngineFindView方法中的動作的過濾器列表?

回答

1

你幾乎侷限於使用反射來獲取任何屬性信息,無論包括MVC動作方法在內的任何東西。 ;)

唯一的其他技術來獲取這些信息是經過ControllerDescriptor途徑

在你的情況,你可以直接跳過尋找所有的授權屬性,如果用戶被授權與否,只是問給他們他們需要的主頁面。

我已經在自定義視圖引擎中動態設置了母版頁,而最高性能的選項是查看任何HttpContextBase信息。對於一種場景,我只需傳遞查詢參數或在{masterPage}路由參數上追加需要使用的參數。

唯一的其他行動信息路徑是ReflectedControllerDescriptor路由。這種方法的問題是非常冗長,需要大量代碼來完成你的工作。

這裏有一點點的代碼(我發現在stackoverflow!)的「描述符」技術來做安全鏈接修剪修剪。如果該代碼位於自定義視圖引擎中,則該代碼也可用於動態設置該母版頁。它不是你想要的,但可以幫助其他人完成相同的動態主頁設置其他地方:

public static bool HasActionPermission(this HtmlHelper htmlHelper, string actionName, string controllerName) 
    { 
     //if the controller name is empty the ASP.NET convention is: 
     //"we are linking to a different controller 
     ControllerBase controllerToLinkTo = string.IsNullOrEmpty(controllerName) 
               ? htmlHelper.ViewContext.Controller 
               : GetControllerByName(htmlHelper, controllerName); 

     var controllerContext = new ControllerContext(htmlHelper.ViewContext.RequestContext, controllerToLinkTo); 

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

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

     return ActionIsAuthorized(controllerContext, actionDescriptor); 
    } 


    private static bool ActionIsAuthorized(ControllerContext controllerContext, ActionDescriptor actionDescriptor) 
    { 
     if (actionDescriptor == null) 
      return false; // action does not exist so say yes - should we authorise this?! 

     AuthorizationContext authContext = new AuthorizationContext(controllerContext); 

     // run each auth filter until on fails 
     // performance could be improved by some caching 
     foreach (IAuthorizationFilter authFilter in actionDescriptor.GetFilters().AuthorizationFilters) 
     { 
      authFilter.OnAuthorization(authContext); 

      if (authContext.Result != null) 
       return false; 
     } 

     return true; 
    }