ebrown
ebrown

Reputation: 801

Asp.net mvc - Accessing view Model from a custom Action filter

I am trying to access the Model data passed to the view in the action filter OnActionExecuted. Does anyone know if this is possible?

I am trying to do something like this:

public override void OnActionExecuted(ActionExecutedContext filterContext)
{
    //get model data
    //...

    sitemap.SetCurrentNode(model.Name);
}

Any advice?

Upvotes: 42

Views: 24215

Answers (5)

Arun Kumar A.J
Arun Kumar A.J

Reputation: 171

Making the base.OnActionExecuted() call the last line of the method solved the 'Model being null' problem for me.

(This is a comment to @Steven Lyons 's answer, but I'm posting as an answer because I can't comment.)

Upvotes: 4

Safin Ahmed
Safin Ahmed

Reputation: 580

In .Net Core you have an ActionArguments IDictionary on the context, with all the parameters from your method

So if you have the following controller method

    [HttpPost]
    public void Post([FromBody]BaseRequest request)
    {
    }

You can access the field like so

    public override void OnActionExecuting(ActionExecutingContext context)
    {
      var request = context.ActionArguments["request"] as BaseRequest;`
      //do whatever, 
    }

Upvotes: 2

gustavocs
gustavocs

Reputation: 200

I don't know why but filterContext.Controller.ViewData.Model is always null even when the model bind is executed before OnActionExecuted. I found a solution using the OnModelUpdated event to set that property before.

I have the model binder:

public class CustomModelBinder: DefaultModelBinder
{
    protected override void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        controllerContext.Controller.ViewData.Model = bindingContext.Model;
        base.OnModelUpdated(controllerContext, bindingContext);
    }
}

After that you need to set the default binder to your new model binder in Application_Start() section in Global.asax:

ModelBinders.Binders.DefaultBinder = new CustomModelBinder();

Finally you can access your Model in an ActionFilterAttribute:

public class TraceLog : ActionFilterAttribute
{
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        //filterContext.Controller.ViewData.Model now isn't null
        base.OnActionExecuted(filterContext);
    }
}

Upvotes: 19

Matas Vaitkevicius
Matas Vaitkevicius

Reputation: 61401

If you are getting null - as alternative to @Gustavo Clemente's answer you can try overriding OnActionExecuted and passing your viewModel into view in following way:

Action:

[Breadcrumb("Index")]
public ActionResult UnitIndex()
{
    View(new Answers());
}

Attribute:

public class BreadcrumbAttribute : ActionFilterAttribute
{
    public string Page { get; set; }

    public BreadcrumbAttribute(string page)
    {
        Page = page;
    }

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        var model = (IBreadcrumbs)filterContext.Controller.ViewData.Model;
        model.Breadcrumbs = BreadcrumbHelper.GetBreadCrumbs(string.Format("{0}", filterContext.RouteData.DataTokens["area"]), Page);
    }
}

enter image description here

Upvotes: 1

Steven Lyons
Steven Lyons

Reputation: 8218

The model is at:

filterContext.Controller.ViewData.Model

Upvotes: 59

Related Questions