首页 > 解决方案 > 使用一个 From Action 方法覆盖控制器上的 ResourceFilter

问题描述

我正在使用 ASP.NET Core 2.2 我有一个带有一些参数的 ResourceFilter。我在我的控制器上使用 ResourceFilter。我想做的是在该控制器中的特定操作上使用具有不同参数的相同过滤器类型。

我有类似的东西:

public class MyRequestFilter : IResourceFilter
{
    private readonly string[] _someValues;

    MyRequestFilter(string[] someValues)
    {
        _someValues = someValues;
    }

    public void OnResourceExecuting(ResourceExecutingContext context)
    {
        // do some checks here using _someValues
    }
}

我在我的控制器上使用它,例如:

[TypeFilter(typeof(MyRequestFilter),
    IsReusable = false,
    Arguments = new object[] {
        new[]{"some value",
        "another value"}})]
public class MyController : Controller
{

}

我想做的是在特定的操作方法上覆盖该过滤器。就像是:

[TypeFilter(typeof(MyRequestFilter),
    IsReusable = false,
    Arguments = new object[] {
        new[]{"value for this action",
        "another value just for this action"}})]
public async Task<IActionResult> MyAction()
{

}

当我尝试上述操作并向绑定到该操作的端点发出请求时,我看到 MyRequestFilter.OnResourceExecuting() 被一个实例调用,该实例具有传递到控制器上的属性中的属性。如果我注释掉控制器过滤器,那么我会看到带有我在方法中传递的值的过滤器。我的问题是 - 有没有办法告诉方法忽略此特定路由的控制器过滤器并使用在方法属性上定义的过滤器?任何意见,将不胜感激。非常感谢!

标签: c#asp.net-mvcasp.net-core

解决方案


我的问题是 - 有没有办法告诉方法忽略此特定路由的控制器过滤器并使用在方法属性上定义的过滤器

context.Filters您可以在运行时动态更改。例如,

  1. 创建一个什么都不做的 nope 过滤器
    class NopeFilter : IResourceFilter
    {
        public void OnResourceExecuted(ResourceExecutedContext context) { }
        public void OnResourceExecuting(ResourceExecutingContext context) { }
    }
    
  2. 在运行时检查条件并将其他此类过滤器替换为NopeFilter. 假设我们只想保留第一个,这是一个实现:

    public class MyRequestFilter : IResourceFilter
    {
        // ... fields and constructor 
    
        // a helper method that will replace the extra MyRequestFilters with NopeFilter at runtime
        private void  DistinctThisTypeFilters(IList<IFilterMetadata> filters){
            var nopeFilter = new NopeFilter() ;
            var count = filters.Count();
            var thisTypeFilterCount = filters.OfType<MyRequestFilter>().Count();  // the total number: filters of this type 
            if(thisTypeFilterCount > 1){
                var alreadyReplaced = 0;  // the number that we have replaced till now
                for(var i = count -1 ; i > 0 ; i--){    // replace in reverse order
                    var filter = filters[i];
                    if(filter.GetType()== typeof(MyRequestFilter))
                    {
                        if(alreadyReplaced < thisTypeFilterCount -1 ){
                            filters[i]= nopeFilter;
                            alreadyReplaced++;
                        }
                    }
                }
            }
        }
    
        public void OnResourceExecuting(ResourceExecutingContext context)
        {
            this.DistinctThisTypeFilters(context.Filters);  // add this line so that only the first one will take effect. 
            // do some checks here using _someValues
            ...
        }
    
        public void OnResourceExecuted(ResourceExecutedContext context)
        {
        }
    }
    

推荐阅读