asp.net mvc - 如何强制执行控制器层超类型

时间:2011-08-08 12:55:12

标签: asp.net-mvc design-patterns controller

我想使用扩展Controller的类作为项目中控制器的默认基类型,而不是使用Controller本身。所以,我会这样做:

public class FooController : MyBaseController

有没有办法可以强制执行此操作,以便人们无法创建直接扩展Controller的控制器?

5 个答案:

答案 0 :(得分:6)

您始终可以创建一个单元测试(通过反射)检索从Controller派生的所有类,并断言每个类也是MyBaseController的子类。这将是

的路线
[TestMethod]
public class All_Controllers_Derive_From_MyBaseController()
{
    // Act
    var controllerTypes = AppDomain.CurrentDomain
                                   .GetAssemblies()
                                   .SelectMany(asm => asm.GetTypes())
                                   .Where(t => t.IsSubclassOf(typeof(Controller))
                                   .ToList();

   // Verify
   foreach (var type in controllerTypes)
   {
        // Make sure the type isn't the actual controller type
        if (type is Controller)
            continue;

        Assert.IsTrue(type.IsSubclassOf(typeof(MyBaseController)), 
                           string.Format("{0} is not a subclass of the MyBaseController class", type.FullName));
   }
}

现在,如果有人创建了一个不使用基本控制器的控制器,则单元测试将失败并告诉您哪些控制器不正确。

请注意,此代码是自由编写的,因此可能需要进行一些调整,但这是基本的想法。

答案 1 :(得分:3)

但是我更喜欢单元测试方法above这是另一个使用自定义控制器工厂。

public class MyControllerFactory<T> : DefaultControllerFactory where T : Controller
{
    #region Overrides of DefaultControllerFactory

    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        if (!typeof(T).IsAssignableFrom(controllerType))
        {
            throw new NotSupportedException();
        }

        return base.GetControllerInstance(requestContext, controllerType);
    }

    #endregion
}

您可以在Global.asax的应用程序启动方法中进行设置,如下所示:

ControllerBuilder.Current.SetControllerFactory(new MyControllerFactory<MyBaseController>());

这当然会在不从MyBaseController派生时导致运行时异常,这可能不适合您当前的场景。

答案 2 :(得分:1)

你有两个选择,都涉及编写一些代码。

选择#1 您可以创建过滤器并尝试在运行时捕获错误。您最好有一个良好的用户验收测试流程来触摸所有页面。

选择#2 涉及为MSBuild编写一个任务,检查每个控制器类是否来自您指定的类。只需加载应用程序组件(或程序集),然后前往城镇!

我更喜欢选择#2。它不会影响应用程序运行时性能并为您提供更好的覆盖率。您可以在构建结束时运行它。

http://msdn.microsoft.com/en-us/library/gg416513(VS.98).aspx

http://msdn.microsoft.com/en-us/library/t9883dzc.aspx

答案 3 :(得分:0)

我想问一下你的理由,但这里有一个答案:你可以使用的一个(略微不足之处)方法是将基类命名为“Controller”,并将其放在与各个控制器相同的命名空间中。只要人们没有专门扩展System.Web.Mvc.Controller,他们就会得到你的Controller类。没有更聪明,可能。

答案 4 :(得分:0)

您可以修改默认代码生成模板,以便始终创建一个继承自正确类的新控制器。缺点是这涉及将更新的模板分发给开发团队。有关更详细的说明,请参阅Scott Hanselman的博客。

http://www.hanselman.com/blog/ModifyingTheDefaultCodeGenerationscaffoldingTemplatesInASPNETMVC.aspx