【问题标题】:How do I pass a variable from an ActionFilter to a Controller Action in C# MVC?如何将变量从 ActionFilter 传递到 C# MVC 中的控制器操作?
【发布时间】:2016-08-09 13:34:16
【问题描述】:

采用简单的操作过滤器,检查用户是否登录并检索其用户 ID。

public class LoginFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {    
        // Authenticate (somehow) and retrieve the ID
        int id = Authentication.SomeMethod();
        // Pass the ID through to the controller?
        .....
    }
}

然后我怎样才能将此 ID 传递给我的控制器操作?

[LoginFilter]
public class Dashboard : Controller
{
    public ActionResult Index()
    {
        // I'd like to be able to use the ID from the LoginFilter here
        int id = ....
    }
}

是否有与 ViewBag 等效的工具可以让我这样做?或者其他一些允许我在过滤器和控制器操作之间传递变量和对象的技术?

【问题讨论】:

    标签: c# asp.net asp.net-mvc action-filter actionfilterattribute


    【解决方案1】:

    我相信ActionExecutingContext 包含对调用控制器的引用。将其与从基类 Controller 派生的自定义控制器类混合使用,然后将 id 存储为控制器的实例变量可能会做到这一点。

    自定义控制器

    Public Class MyController : Controller
    {
        Public int Id {get;set;}
    }
    

    登录过滤器

    public class LoginFilter : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {    
            // Authenticate (somehow) and retrieve the ID
            int id = Authentication.SomeMethod();
            ((MyController)filterContext.Controller).Id = id; 
            //Assign the Id by casting the controller (you might want to add a if ... is MyController before casting)
        }
    }
    

    控制器

    [LoginFilter]
    public class Dashboard : MyController
    {
        public ActionResult Index()
        {
            //Read the Id here
            int id = this.Id
        }
    }
    

    【讨论】:

    • 我喜欢这个解决方案的逻辑,因为它将 ID 直接植入控制器并且非常“整洁”,但决定不使用它,因为实际实现对任何人来说似乎有点不透明稍后维护代码 - ID 似乎被神奇地设置了,没有解释。
    • 如果我们想走100%无状态的方式,那么我们应该选择这种方式。 +1 投票给你的好解决方案@Francis Lord。谢谢。
    【解决方案2】:

    你可以像这样使用ViewData/ViewBag

    1.) 使用ViewData

    注意:如果是 ViewData,您需要执行一个步骤,即您必须对其进行类型转换

    public class LoginFilter : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {    
            // Authenticate (somehow) and retrieve the ID
            int idValue = Authentication.SomeMethod();
    
            // Pass the ID through to the controller?
            filterContext.Controller.ViewData.Add("Id", idValue);
        }
    }
    

    然后在Controller函数中

    [LoginFilter]
    public class Dashboard : Controller
    {
        public ActionResult Index()
        {
            // I'd like to be able to use the ID from the LoginFilter here
            int id = (int)ViewData["Id"];
        }
    }
    

    2.) 使用ViewBag

    public class LoginFilter : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {    
            // Authenticate (somehow) and retrieve the ID
            int idValue = Authentication.SomeMethod();
    
            // Pass the ID through to the controller?
    
            filterContext.Controller.ViewBag.Id = idValue; 
        }
    }
    

    然后在控制器中

    [LoginFilter]
    public class Dashboard : Controller
    {
        public ActionResult Index()
        {
            // I'd like to be able to use the ID from the LoginFilter here
            int id = ViewBag.Id;
        }
    }
    

    【讨论】:

    • 谢谢,虽然我最终使用了 TempData(如@luiso 的回答所建议的那样)而不是 ViewBag 或 ViewData,但您的提供了有关如何实际使用它的最佳细节,以及示例和ViewBag 的技术与 TempData 相同。我认为这是临时数据,而不是任何用于视图的数据,因此使用 TempData 更合乎逻辑
    【解决方案3】:

    您可以通过以下方式使用ViewBag

    filterContext.Controller.ViewBag.Id = id;
    

    应该这样做,一旦您执行filterContext.Controller,您就可以访问其中的所有字段,例如TempData

    即便如此,如果您使用的是OWIN,那么也许要获取用户的 id,您可以使用 Controller.User,它具有获取 Id 的扩展方法和获取大多数其他标准数据的属性,例如 Name等等

    【讨论】:

    • 嗯,这似乎是一个很好的解决方案。从逻辑上讲,使用 ViewBag 可能没有意义:但 TempData 可能是它的好地方。我没有使用 OWIN(或者至少在项目的这一部分中没有使用,因为我们正在混合身份验证技术)
    【解决方案4】:

    这是我在旧应用程序中看到的一种方法,它避免使用 viewbag,而是让控制器参数指定它们所期望的:

    public class LoginFilter : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {    
            // Authenticate (somehow) and retrieve the ID
            int id = Authentication.SomeMethod();
            
            // Check if there's an action parameter on the controller: set it to your ID
            if (filterContext.ActionParameters.ContainsKey("authId"))
            {
                filterContext.ActionParameters["authId"] = id;
            }
        }
    }
    
    [LoginFilter]
    public class Dashboard : Controller
    {
        public ActionResult Index(int authId)
        {
            // authId parameter is available to each action bearing LoginFilter
            // It's instantiated if it's present in the method signature
            ...
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2013-04-07
      • 1970-01-01
      • 1970-01-01
      • 2021-09-20
      • 2012-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多