【问题标题】:ASP.NET MVC Pass object from Custom Action Filter to ActionASP.NET MVC 将对象从自定义操作筛选器传递到操作
【发布时间】:2023-03-19 17:55:01
【问题描述】:

如果我在 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.....

}

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

【问题讨论】:

    标签: asp.net-mvc filter custom-action


    【解决方案1】:

    你可以使用HttpContext:

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

    你可以在动作中阅读它:

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

    【讨论】:

    • 我正在考虑使用 HttpContext.Items[] 及其可接受的解决方案,因为它将在请求结束时被清除。我不确定是否有一个地方可以存储仅在行动期间存在的东西。
    【解决方案2】:

    在 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 作为参数,但我不想仅仅为了解决我的问题而引入它。
    • 查看未输入版本的已编辑帖子。我仍然会使用第一个版本。也许参数名听起来很糟糕。它可以是任何类,不必是类型化视图的类。
    【解决方案3】:

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

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

    【讨论】:

    • 一个项目在 RouteData 中能存活多久?我只需要在当前执行的操作期间保留对象,或者最多保留当前请求,如果这是路由数据的工作方式,那么这就是答案,否则 HttpContext.Items 可能更好。
    • RouteData 是与当前执行的路由(动作)相关的数据。将其视为一个容器,代表根据您的路由规则解析和映射的请求 url。
    • RouteData 确实非常适合这样做,因为我今天学到了感谢您在这里的回答。我面前的漂亮的黑色和黄色 MVC 书(第四版)在有关过滤器的整章中都没有提及它或做任何类似的事情(或者至少我还没有找到它? )。无论如何,+1,谢谢!
    • filterContext.ControllerContext.RouteData.Values.Add("key",value); 为我工作! :)
    【解决方案4】:

    better approach 由 Phil Haack 描述。

    基本上这就是你所做的:

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

    【讨论】:

    • 非常好的方法,我绝对认为这比公认的答案要好得多。这应该是公认的答案!谢谢!
    • 为什么这比公认的答案更好?似乎没有理由会出现这种情况,而且额外的 [AddActionParameter] 显然是其他方法不需要运行的额外工作。
    • @ChrisBertrand 通过使用强类型,即Person 类,它更干净,并且避免了控制器中的编译时错误。它还使单元测试变得更加容易。
    • 这种方法的唯一问题是当您尝试这样做并同时发布帖子时。通过将其添加到操作参数中,它会参与模型验证,您最终可能会遇到一些奇怪的情况,即发布的数据是有效的,但 ModelState.IsValid 仍然是错误的,因为您传入的对象上有些东西是无效的。
    • 这不是一个很好的解决方案,因为现在您的 api 可以接受这些参数作为查询字符串,这是一个意想不到的副作用。当您拥有像 swagger 这样的文档库时,情况会更糟,当这些参数严格供内部使用时,它们会显示这些参数是 URL 的查询参数。
    猜你喜欢
    • 2020-03-21
    • 2014-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多