是否可以通过Action Filter中的Action Method提供数据?

时间:2010-09-08 22:02:50

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

背景:

我们提供了html文件 - 'wrappers' - 来自我们的客户端,我们需要注入我们生成的内容。它们具有不同页面的不同包装器,我们必须将相应的内容注入它们在包装器中提供的特殊标签。

包装器文件名对应于操作方法的名称。因此,对于下面的示例,将执行自定义操作过滤器,该过滤器将确定包装器的名称,然后调用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属性填充数据。我可以在动作方法中对属性进行设置,如下所示

    [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);

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

2 个答案:

答案 0 :(得分:1)

您已经写好的内容非常好,只需稍加调整即可满足您的新要求。

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

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

然后,在您的动作过滤器中,您只需要像

这样的内容
if (tagData == null)
   baseController.PopulateWrapper(wrapper)
else
   baseController.PopulateWrapper(wrapper, tagData)

我相信你会得到一般的想法。

答案 1 :(得分:0)

imho以下内容恰到好处,所以我看不到动作过滤器的整洁程度如何:

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中传递数据,但在您的场景中感觉最糟糕 - 特别是在控制器基础中的依赖性。