ASP.NET MVC将对象从“自定义操作筛选器”传递到“操作”


69

如果我在ASP.NET MVC中的“自定义操作过滤器”中创建对象

public override void OnActionExecuting(ActionExecutingContext filterContext)
{
    DetachedCriteria criteria = DetachedCriteria.For<Person>();
    criteria.Add("stuff");

    // Now I need to access 'criteria' from the Action.....

}

有什么方法可以从当前正在执行的操作中访问对象。

Answers:


56

我建议将其放入“路线”数据中。

    protected override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        filterContext.RouteData.Values.Add("test", "TESTING");
        base.OnActionExecuting(filterContext);
    }

    public ActionResult Index()
    {
        ViewData["Message"] = RouteData.Values["test"];

        return View();
    }

2
一个项目在RouteData中可以生存多长时间?我只需要在当前执行操作的持续时间内保留对象,或者最多保留当前请求的对象,如果这是路由数据的工作方式,那么这就是答案,否则HttpContext.Items可能更好。
09年

1
RouteData是与当前正在执行的路线(动作)相关的数据。将其视为代表根据您的路由规则解析和映射的请求URL的容器。
Neal 2010年

RouteData由于您今天在这里得到的答复,我今天已经学到了,这样做当然非常好。我在我面前的漂亮的黑色和黄色MVC书(第四版)在过滤器的整个章节中都没有提及它,或者没有做任何与此类似的事情(或者至少我还没有找到它? )。无论如何,+ 1,谢谢!
Funka 2013年

filterContext.ControllerContext.RouteData.Values.Add("key",value);为我工作!:)
Ajay Aradhya

64

更好的办法是通过菲尔哈克描述。

基本上,这就是您要做的:

public class AddActionParameterAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        base.OnActionExecuting(filterContext);

        // Create integer parameter.
        filterContext.ActionParameters["number"] = 123;

        // Create object parameter.
        filterContext.ActionParameters["person"] = new Person("John", "Smith");
    }
}

唯一的问题是,如果要创建对象参数,则您的类(在本例中为Person)必须具有默认的构造函数,否则将发生异常。

使用上述过滤器的方法如下:

[AddActionParameter]
public ActionResult Index(int number, Person person)
{
    // Now you can use number and person variables.
    return View();
}

2
非常好的方法,我绝对认为这比公认的答案要好。这应该是公认的答案!谢谢!
2014年

为什么这比公认的答案更好?似乎没有理由为什么会这样,附加的[AddActionParameter]显然是其他方法不需要执行的附加工作。
克里斯

@ChrisBertrand通过使用强类型(即-Person类),它更干净,并且避免了控制器中的编译时错误。这也使单元测试变得更加容易。
niaher

1
这种方法的唯一问题是,当您尝试执行此操作和同时发布信息时。通过将其添加到动作参数,它再参与模型验证,并且可以与在发布数据有效奇数的情况下结束了,但ModelState.IsValid仍是假的,因为有些东西不是你传入的对象有效。
克里斯·普拉特

6
这不是一个很好的解决方案,因为现在您的api可以将这些参数作为querystrings接受,这是意外的副作用。更糟糕的是,如果您拥有诸如swagger之类的文档库,它们会在严格供内部使用时显示这些参数为URL的查询参数。
arviman

41

您可以使用HttpContext

filterContext.HttpContext.Items["criteria"] = criteria;

您可以在操作中阅读它:

[YourActionFilter]
public ActionResult SomeAction() 
{
    var criteria = HttpContext.Items["criteria"] as DetachedCriteria;
}

1
我正在考虑使用HttpContext.Items []及其可接受的解决方案,因为它将在请求结束时清除。我不确定是否存在可以存储仅在操作期间存在的内容的地方。
09年

3

如果将项目作为参数传递给操作,则在ViewData或ViewModel中设置项目。在这里,我设置了ViewModel的属性

public override void OnActionExecuting(ActionExecutingContext filterContext)
 {
     ViewModelBase viewModel = null;
     foreach (object parameter in filterContext.ActionParameters.Values)
     {
         if (parameter is ViewModelBase)
         {
             viewModel = (ViewModelBase)parameter;
             break;
         }
     }
     if(viewModel !=null)
     {
         viewModel.SomeProperty = "SomeValue";
     }
 }


    public ActionResult About(ViewModelBase model)
    {
      string someProperty= model.SomeProperty;
}

这是我认为您更喜欢的无类型版本:

   public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        filterContext.Controller.ViewData.Add("TestValue", "test");

    }

       [FilterWhichSetsValue]
        public ActionResult About()
        {
            string test = (string)ViewData["TestValue"];
            return View();
        }

感谢您的建议。我的动作虽然没有将ViewModelBase作为参数,但我不希望仅仅为了解决我的问题就不引入它。
09年

有关未键入的版本,请参见编辑过的帖子。我仍然会使用第一个版本。也许参数名听起来很糟糕。它可以是任何类,而不必是类型化视图的类。
Mathias F
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.