我们什么时候应该实现自定义MVC ActionFilter?

时间:2011-07-20 00:32:41

标签: asp.net-mvc action-filter

我们是否应该将假设在Controller中的逻辑(如呈现局部视图的数据)移动到ActionFilter?

例如,我正在创建一个CMS网站。应该有一个广告块要在几个页面上呈现,而不是所有页面。我应该制作 [ShowAd(categoryId)] ActionFilter 属性并使用此属性修饰操作方法吗?

此控制器的实现将包括服务调用以从数据库检索信息,构建视图模型并放入 ViewData 。如果存在 ViewData 中的数据,则会有一个 HtmlHelper 来呈现部分视图。

2 个答案:

答案 0 :(得分:4)

这对我来说似乎很难过。

当我想弄清楚我是否需​​要一个ActionFilter时,我的第一个问题是,这是一个贯穿各领域的问题吗?。乍一看,你的特定用例不适合这种情况。原因是,广告只是在网页上呈现的另一件事。没有什么特别之处可以让它横切。如果您在问题中将“广告”替换为“广告”,则所有相同的事实都是正确的。

所以就是这样,然后是关注点和可测试性的分离。一旦你有ActionFilter,你的控制器有多可测试?这是你在测试时必须模拟的其他东西,更糟糕的是你必须用你添加ActionFilter的每个控制器来模拟这些依赖项。

我问的第二个问题是,“我怎样才能以我正在使用的平台中最惯用的方式做到这一点?”

对于这个特殊问题,它听起来像RenderAction,AdController就是这样。

原因如下:

  1. 广告是自己的资源;它通常与页面上的任何其他内容没有密切联系;它存在于它自己的小世界中。
  2. 它有自己的数据访问策略
  3. 您真的不想重复代码来在您可以使用它的每个地方生成广告(这是RenderPartial方法带给您的地方)
  4. 所以这就是这样一只野兽的样子:

    public AdController : Controller
    {
        //DI'd in
        private AdRepository AdRepository;
    
        [ChildActionOnly]
        public ActionResult ShowAd(int categoryId)
        {
            Ad ad = Adrepository.GetAdByCategory(categoryId);
            AdViewModel avm = new AdViewModel(ad);
            return View(avm);
        }
    }
    

    然后你可以有一个围绕这个设置的自定义局部视图,并且不需要在每个动作(或每个控制器)上放置一个过滤器,并且你没有尝试适合方形钉(一个动作)过滤器)在一个圆孔(动态视图)。

    将广告添加到现有页面变得非常简单:

    <% Html.RenderAction("ShowAd", "Ad" new { categoryId = Model.CategoryId }); %>
    

答案 1 :(得分:0)

如果您的广告系统足够简单,则没有理由您/不应该使用操作过滤器在视图数据中插入足够的信息以在视图代码中生成广告。

对于一个简单的广告系统,比如说...一个特定类别的广告在每个页面的布局中显示在同一个地方,就是这样,那么更好方式除了准备将来对系统的更改。虽然这些担忧可能是合法的,但您也可能拥有良好的权威,这一要求永远不会改变。但是,即使需求确实发生变化,将所有生成广告的代码包装在一个地方也是最重要的方面,并且比预期更强大的解决方案可以为您节省更多时间。显然,有很多方法可以将这些代码包装在一个地方。

至于你选择这样做的方式,我会让你的动作过滤器更清晰,只是让它将类别插入到视图数据中,并让所有的魔法发生在你的html帮助器中,这将把类别作为一个参数。构建视图模型以推入视图数据将需要一些额外的工作,并且当代码不需要在那里时将代码放在所有地方。保持简单,并在负责...构建html的html帮助器中执行所有html生成。

相关问题