简体   繁体   English

MVC Model 是 OnExecuted 动作过滤器中的 null ......或者更优雅的方式来设置 model?

[英]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.我有一个 ActionFilter,它覆盖了 OnActionExecuted 方法。 The filterContext.Controller.ViewData.Model is always null on a POST operation. filterContext.Controller.ViewData.Model 在 POST 操作中始终为 null。 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.我确实发现以下文章似乎在说它不应该是 null 但这一定是 MVC 的早期版本。 This is MVC3.这是MVC3。 What should I be getting?我应该得到什么?

Model availability inside ActionFilter ActionFilter 内的 Model 可用性

UPDATE:更新:

I've figured out the answer to the original question.我已经找到了原始问题的答案。 I had a custom ActionResult that outputs JSON with a custom date formatter.我有一个自定义 ActionResult ,它使用自定义日期格式化程序输出 JSON 。 The problem was that the model is not being set in the controller.问题是 model 未在 controller 中设置。

In my custom ActionResult the ExecuteResult method get passed the ControllerContext which would be nice if I could set the Model there:在我的自定义 ActionResult 中,ExecuteResult 方法通过了 ControllerContext,如果我可以在那里设置 Model,那就太好了:

context.Controller.ViewData.Model = _data;

But this is to late in the cycle and the result is still null in the ActionFilter.但这是周期的后期,结果仍然是 ActionFilter 中的 null。 This seems to mean that I need to manually set the model in the controller:这似乎意味着我需要在controller中手动设置model:

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.这意味着我每次使用此自定义 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:在我发送到 controller 的 comstom ActionResult 的构造函数中,至少它会始终保持一致:

public JsonNetResult(object data, Controller controller) {
    SerializerSettings = new JsonSerializerSettings();
    _data = data;
    controller.ControllerContext.Controller.ViewData.Model = _data;
}

Another approach is to use a base controller to automatically handle the storing of the action parameters collection for later use:另一种方法是使用基础 controller 来自动处理动作参数集合的存储以供以后使用:

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.它使用不是很好的 HttpContext 项目,但我不知道您可以在属性中访问您的 ViewBag 或 ViewData 。

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
}

I found a solution like yours using the OnModelUpdated event to set that property before.我找到了一个像你这样的解决方案,之前使用 OnModelUpdated 事件设置该属性。

I have the ModelBinder:我有模型绑定器:

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:之后,您需要在 Global.asax 的 Application_Start() 部分中将默认绑定器设置为新的 model 绑定器:

ModelBinders.Binders.DefaultBinder = new CustomModelBinder(); ModelBinders.Binders.DefaultBinder = new CustomModelBinder();

Finally you can access your Model in an ActionFilter:最后,您可以在 ActionFilter 中访问您的 Model:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM