Asp.net mvc - Accessing view Model from a custom A

2019-01-17 09:42发布

问题:

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?

回答1:

The model is at:

filterContext.Controller.ViewData.Model


回答2:

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);
    }
}


回答3:

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, 
    }


回答4:

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);
    }
}