从ASP.NET MVC中的ViewEngine中查找关于操作的atrributes

时间:2009-05-20 05:22:30

标签: asp.net-mvc routing master-pages viewengine

我有一个自定义的ViewEngine,我想修改所使用的母版页,具体取决于所请求的操作是否有Authorize属性过滤器。

到目前为止,我只是使用这样的反射:

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";
    }
}

但我不喜欢将反射用于重复性任务。我知道我可以使用视图缓存来加快第一次之后的速度,但我想知道是否有更直接的方式来访问应用于FindView方法中的操作的过滤器列表ViewEngine

1 个答案:

答案 0 :(得分:1)

您几乎不得不使用反射来获取任何属性信息,无论包括MVC操作方法在内的任何内容。 ;)

获取此信息的唯一其他技术是通过ControllerDescriptor路径

在您的情况下,您可以跳过查找authorize属性,只是询问用户是否获得授权,并为他们提供所需的母版页。

我之前在自定义视图引擎中动态设置了母版页,最高性能的选项是查看可用的H​​ttpContextBase信息。对于一种情况,我只需传递查询参数或在我需要使用时附加在{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;
    }