【问题标题】:Is it possible to make data from an Action Method available in an Action Filter?是否可以在动作过滤器中使用动作方法中的数据?
【发布时间】:2010-09-09 16:54:44
【问题描述】:

背景:

我们从客户那里获得了 html 文件——“包装器”——我们需要将我们生成的内容注入其中。它们对不同的页面有不同的包装器,我们必须将相应的内容注入到它们在包装器中提供的特殊标签中。

包装文件名对应于动作方法的名称。因此对于下面的示例,执行一个自定义操作过滤器,它将确定包装器的名称,然后调用 BaseController(每个控制器都实现)中的一个方法,该方法将加载包装器并将我们的内容注入其中。

    [WrapperAction]
    public ActionResult Home()
    {
        return View();
    }

我把它放在一个 ActionFilter 中的原因是因为我不想调用BaseController 的方法来填充每个需要包装器的操作方法中的包装器。我认为用 ActionFilterAttribute 装饰方法会更整洁

WrapperAction定义如下:

public class WrapperAction : ActionFilterAttribute
{
    public override void OnActionExecuted(ActionExecutedContext aec)
    {
        var baseController = (BaseController)filterContext.Controller;

        string wrapper = aec.RequestContext.RouteData.Values["action"].ToString();

        baseController.PopulateWrapper(wrapper);
    }
}

PopulateWrapper 被定义为

    public void PopulateWrapper(string wrapperName)
    {
        // get wrapper file from disk
        Wrapper wrapper = _wrapperService.GetWrapper(Site.Id, wrapperName);

        // populate the file with our CSS (it already has its own pre-populated CSS)
        // our CSS file is determined by the id of a Site object.
        AppHelper.PopulateWrapperCss(wrapper, this.Site.Id);

        // make wrapper sections available to the Master page, 
        // split so that we can place our content around them
        ViewData["WrapperTop"] = wrapper.WrapperTop;
        ViewData["WrapperMiddle"] = wrapper.WrapperMiddle;
        ViewData["WrapperBottom"] = wrapper.WrapperBottom;
    }

困境:

然而,现在出现了一个新要求。我需要填充包装器中的一些新标签,并且我必须根据调用包装器的操作方法使用不同的数据填充它们。该数据在操作方法中确定,但数据需要在由WrapperAction 调用的 PopulateWrapper 方法中使用。

我现在需要一个类似于

的方法

AppHelper.PopulateWrapperTags(wrapper, this.TagData);

而且我需要有一些方法让 BaseController 的 TagData 属性填充数据。我可以在 action 方法中分配属性,如下所示

    [WrapperAction]
    public ActionResult Home()
    {
        base.TagData = GetTagData();
        return View();
    }

但这样一来我就失去了 WrapperAction 的意义,因为我不想像那样引用 BaseController。

问题:

我有没有办法为 WrapperAction 提供填充包装器所需的数据?我需要接受打击并开始打电话吗

        var tagData = GetTagData();
        string wrapperName = RouteData.Values["action"].ToString();
        base.PopulateWrapper(wrapperName, tagData);

在每个控制器中?我有更好的方法吗?

【问题讨论】:

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


    【解决方案1】:

    你已经写的非常好,只需要稍作调整就可以满足你的新要求。

    关键是您的操作过滤器是OnActionExecuted 的类型,它您的操作代码完成之后运行,但在视图执行之前之前。因此,过滤器方法可以建立在 action 方法中发生的任何事情上。

    要满足您的要求,请在基本控制器中创建 tagData 变量,以便从它继承的控制器可以在必要时填充它。

    然后,在您的操作过滤器中,您只需要类似

    if (tagData == null)
       baseController.PopulateWrapper(wrapper)
    else
       baseController.PopulateWrapper(wrapper, tagData)
    

    我相信你明白了。

    【讨论】:

      【解决方案2】:

      恕我直言,以下是正确的,所以我看不出动作过滤器有多整洁:

      public ActionResult Home()
      {
         PopulateWrapper();
         return View();
      }
      

      在控制器基础中:

      public void PopulateWrapper(string wrapperName)
      {
         string wrapperName = RouteData.Values["action"].ToString();
         //... rest of populate wrapper
      

      然后你去:

      public ActionResult Home()
      {
          PopulateWrapper(GetTagData()); // after defining an overload in base
          return View();
      }
      

      假设您仍然采用动作过滤器方式,我不明白您为什么要强制依赖于控制器基础,即为什么 PopulateWrapper 位于控制器基础中。

      请注意,您也可以在 ViewData 中传递数据,但在您的场景中感觉最糟糕 - 特别是考虑到控制器库中的依赖关系。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-10-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多