Reputation: 3001
I am using ASP.NET Core 2.2 I have a ResourceFilter that takes some arguments. I am using the ResourceFilter on my controller. What I would like to do is use the same filter type with different arguments on a specific action in that controller.
I have something like:
public class MyRequestFilter : IResourceFilter
{
private readonly string[] _someValues;
MyRequestFilter(string[] someValues)
{
_someValues = someValues;
}
public void OnResourceExecuting(ResourceExecutingContext context)
{
// do some checks here using _someValues
}
}
I use it on my controller like:
[TypeFilter(typeof(MyRequestFilter),
IsReusable = false,
Arguments = new object[] {
new[]{"some value",
"another value"}})]
public class MyController : Controller
{
}
What I would like to do is override that filter on a specific action method. Something like:
[TypeFilter(typeof(MyRequestFilter),
IsReusable = false,
Arguments = new object[] {
new[]{"value for this action",
"another value just for this action"}})]
public async Task<IActionResult> MyAction()
{
}
When I try the above and make a request to the endpoint that action is bound to I am seeing MyRequestFilter.OnResourceExecuting() get invoked with an instance that has the properties that were passed into the attribute on the controller. If I comment out the controller filter then I see the filter with values I passed in on the method. My question is - is there a way to tell the method to ignore the controllers filter for this specific route and use the filter defined on the method's attribute instead? Any advice would be appreciated. Thanks much!
Upvotes: 0
Views: 836
Reputation: 25350
My question is - is there a way to tell the method to ignore the controllers filter for this specific route and use the filter defined on the method's attribute instead
You can dynamically change the context.Filters
at runtime. For example,
class NopeFilter : IResourceFilter
{
public void OnResourceExecuted(ResourceExecutedContext context) { }
public void OnResourceExecuting(ResourceExecutingContext context) { }
}
check a condition at run-time and replace other filters of this type with a NopeFilter
. Let's say we want to reserve the first one only, here's an implementation:
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)
{
}
}
Upvotes: 1