Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVC Model is null in OnExecuted action filter ... or a more elegant way to set the model?

I have an ActionFilter with an override on the OnActionExecuted method. The filterContext.Controller.ViewData.Model is always null on a POST operation. I did find the following article that seems to be saying that it should not be null but this must have been an earlier version of MVC. This is MVC3. What should I be getting?

Model availability inside ActionFilter

UPDATE:

I've figured out the answer to the original question. I had a custom ActionResult that outputs JSON with a custom date formatter. The problem was that the model is not being set in the controller.

In my custom ActionResult the ExecuteResult method get passed the ControllerContext which would be nice if I could set the Model there:

context.Controller.ViewData.Model = _data;

But this is to late in the cycle and the result is still null in the ActionFilter. This seems to mean that I need to manually set the model in the controller:

ControllerContext.Controller.ViewData.Model = model; 

Or

View(model);

Which then means I need to remember to do this every time I use this custom ActionResult. Is there a more elegant way?

YET ANOTHER UPDATE:

I found a way to do this it just isn't as elegant as I hoped.

In my constructor for the comstom ActionResult I sending in the controller, that way at least it will alway be consistent:

public JsonNetResult(object data, Controller controller) {
    SerializerSettings = new JsonSerializerSettings();
    _data = data;
    controller.ControllerContext.Controller.ViewData.Model = _data;
}
like image 964
Mike Avatar asked May 27 '11 16:05

Mike


1 Answers

Another approach is to use a base controller to automatically handle the storing of the action parameters collection for later use:

public class BaseController : Controller
{
    protected override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        filterContext.HttpContext.Items["ActionParms"] = filterContext.ActionParameters.ToDictionary(p => p.Key, p => p.Value);
        base.OnActionExecuting(filterContext);
    }
}

then in your attribute:

public override void OnActionExecuted(ActionExecutedContext filterContext)
{
    var dictionary = filterContext.HttpContext.Items["ActionParms"] as Dictionary<string, object>;
    if (dictionary != null)
    {
        foreach (var o in dictionary.Keys)
        {
            // do something here
        }   
    }            
    base.OnActionExecuted(filterContext);
}

It uses HttpContext items which is not very nice but I don't know that you can access your ViewBag or ViewData in the attribute.

In order to decide whether you want to handle the request in your attribute, you can interrogate the action name and other parameter information:

var action = filterContext.ActionDescriptor.ActionName;
var parms = filterContext.ActionDescriptor.GetParameters();
foreach (var parameterDescriptor in parms)
{
    // do something here
}
like image 158
Rob Kent Avatar answered Oct 26 '22 18:10

Rob Kent