gpt4 book ai didi

asp.net-mvc - 一种在 ASP.NET MVC 中排除操作过滤器的方法?

转载 作者:行者123 更新时间:2023-12-03 10:28:23 24 4
gpt4 key购买 nike

我在 ASP.NET MVC 中遇到过几种情况,我想在除了一两个操作之外的每个操作上应用操作过滤器。例如,假设您有一个 AccountController。其中的每个操作都需要用户登录,因此您在 Controller 级别添加 [Authorize]。但是假设您想在 AccountController 中包含登录页面。问题是,发送到登录页面的用户未经授权,因此这将导致无限循环。

显而易见的解决方法(除了将 Login 操作移动到另一个 Controller )是将 [Authorize] 从 Controller 移动到除 Login 之外的所有操作方法。好吧,这并不好玩,尤其是当您有很多方法或忘记将 [Authorize] 添加到新方法时。

Rails 通过排除过滤器的功能使这变得容易。 ASP.NET MVC 不允许您这样做。所以我决定让它成为可能,这比我想象的要容易。

    /// <summary>
/// This will disable any filters of the given type from being applied. This is useful when, say, all but on action need the Authorize filter.
/// </summary>
[AttributeUsage(AttributeTargets.Method|AttributeTargets.Class, AllowMultiple=true)]
public class ExcludeFilterAttribute : ActionFilterAttribute
{

public ExcludeFilterAttribute(Type toExclude)
{
FilterToExclude = toExclude;
}

/// <summary>
/// The type of filter that will be ignored.
/// </summary>
public Type FilterToExclude
{
get;
private set;
}
}

/// <summary>
/// A subclass of ControllerActionInvoker that implements the functionality of IgnoreFilterAttribute. To use this, just override Controller.CreateActionInvoker() and return an instance of this.
/// </summary>
public class ControllerActionInvokerWithExcludeFilter : ControllerActionInvoker
{
protected override FilterInfo GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
{
//base implementation does all the hard work. we just prune off the filters to ignore
var filterInfo = base.GetFilters(controllerContext, actionDescriptor);
foreach( var toExclude in filterInfo.ActionFilters.OfType<ExcludeFilterAttribute>().Select(f=>f.FilterToExclude).ToArray() )
{
RemoveWhere(filterInfo.ActionFilters, filter => toExclude.IsAssignableFrom(filter.GetType()));
RemoveWhere(filterInfo.AuthorizationFilters, filter => toExclude.IsAssignableFrom(filter.GetType()));
RemoveWhere(filterInfo.ExceptionFilters, filter => toExclude.IsAssignableFrom(filter.GetType()));
RemoveWhere(filterInfo.ResultFilters, filter => toExclude.IsAssignableFrom(filter.GetType()));
}
return filterInfo;
}


/// <summary>
/// Removes all elements from the list that satisfy the condition. Returns the list that was passed in (minus removed elements) for chaining. Ripped from one of my helper libraries (where it was a pretty extension method).
/// </summary>
private static IList<T> RemoveWhere<T>(IList<T> list, Predicate<T> predicate)
{

if (list == null || list.Count == 0)
return list;
//note: didn't use foreach because an exception will be thrown when you remove items during enumeration
for (var i = 0; i < list.Count; i++)
{
var item = list[i];
if (predicate(item))
{
list.RemoveAt(i);
i--;
}
}
return list;
}
}

/// <summary>
/// An example of using the ExcludeFilterAttribute. In this case, Action1 and Action3 require authorization but not Action2. Notice the CreateActionInvoker() override. That's necessary for the attribute to work and is probably best to put in some base class.
/// </summary>
[Authorize]
public class ExampleController : Controller
{
protected override IActionInvoker CreateActionInvoker()
{
return new ControllerActionInvokerWithExcludeFilter();
}

public ActionResult Action1()
{
return View();
}

[ExcludeFilter(typeof(AuthorizeAttribute))]
public ActionResult Action2()
{
return View();
}

public ActionResult Action3()
{
return View();
}

}

这个例子就在那里。如您所见,这非常简单,而且效果很好。我希望它对任何人有用?

最佳答案

我更喜欢概述的解决方案 here .尽管它不像您的解决方案那样通用,但我发现它更简单一些。

就我而言,我正在寻找一种方法来为除少数项目之外的所有项目启用 CompressionFilter。所以我创建了一个像这样的空属性:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public sealed class DisableCompression : Attribute { }

然后在主属性中,检查属性是否存在,如下所示:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public class CompressionFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
bool disabled = filterContext.ActionDescriptor.IsDefined(typeof(DisableCompression), true) ||
filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(DisableCompression), true);
if (disabled)
return;

// action filter logic here...
}
}

尽管我链接到的页面提到这是针对 MVC 3 的,但它似乎在 MVC 1 中也能很好地工作。

编辑:在这里显示一些用法以回应评论。在我进行上述更改之前,它看起来完全像这样,除了没有 [DisableCompression] 属性标记我想要排除的方法。不涉及其他重构。
[CompressionFilter]
public abstract class BaseController : Controller
{
}

public class SomeController : BaseController
{
public ActionResult WantThisActionCompressed()
{
// code
}

[DisableCompression]
public ActionResult DontWantThisActionCompressed()
{
// code
}
}

关于asp.net-mvc - 一种在 ASP.NET MVC 中排除操作过滤器的方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4684150/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com