I have a generic action filter, and i want to get current model in the OnActionExecuting
method. My current implementation is like below:
public class CommandFilter<T> : IActionFilter where T : class, new()
{
public void OnActionExecuting(ActionExecutingContext actionContext)
{
var model= (T)actionContext.ActionArguments["model"];
}
}
It works well if my all model names are same. But i want to use differnet model names.
How to solve this problem?
Edit
public class HomeController : Controller
{
[ServiceFilter(typeof(CommandActionFilter<CreateInput>))]
public IActionResult Create([FromBody]CreateInput model)
{
return new OkResult();
}
}
ActionExecutingContext.ActionArguments is just a dictionary,
/// <summary>
/// Gets the arguments to pass when invoking the action. Keys are parameter names.
/// </summary>
public virtual IDictionary<string, object> ActionArguments { get; }
And you need to loop through it if you need to avoid hardcoded parameter name ("model"). From the same SO answer for asp.net:
When we create a generic action filter that needs to work on a class of similar objects for some specific requirements, we could have our models implement an interface => know which argument is the model we need to work on and we can call the methods though the interface.
In your case you may write something like this:
public void OnActionExecuting(ActionExecutingContext actionContext)
{
foreach(var argument in actionContext.ActionArguments.Values.Where(v => v is T))
{
T model = argument as T;
// your logic
}
}
You can use ActionExecutingContext.Controller
property
/// <summary>
/// Gets the controller instance containing the action.
/// </summary>
public virtual object Controller { get; }
and converting result to base MVC Controller get access to model:
((Controller)actionExecutingContext.Controller).ViewData.Model
In case your controller action has multiple arguments and in your filter you want to select the one that is bound via [FromBody]
, then you can use reflection to do the following:
public void OnActionExecuting(ActionExecutingContext context)
{
foreach (ControllerParameterDescriptor param in context.ActionDescriptor.Parameters) {
if (param.ParameterInfo.CustomAttributes.Any(
attr => attr.AttributeType == typeof(FromBodyAttribute))
) {
var entity = context.ActionArguments[param.Name];
// do something with your entity...