10

我正在尝试使用 Unity 容器来更轻松地对我的控制器进行单元测试。我的控制器使用一个构造函数,该构造函数接受一个存储库的接口。在 global.asax 文件中,我实例化了一个 UnityContainerFactory 并将其注册到 MVC 框架,然后注册存储库及其实现。我将 [Dependency] 属性添加到控制器的 CTOR 存储库参数中。这一切似乎都可以正常工作,只是偶尔会多次调用工厂的 GetControllerInstance(Type controllerType) 并将 null 参数作为 controllerType 传递。

对工厂的第一次调用是正确的,并且控制器类型“ProductsController”作为参数传入。但有时,在控制器的视图显示为空值后,工厂被调用了几次,我不知道为什么。当传递控制器类型的正确值时,“调用堆栈”对我来说是有意义的,但是当传递空值时,我不确定为什么或谁在进行调用。有任何想法吗?

该示例的代码和调用堆栈如下所示。

工作时调用堆栈

Test.DLL!Test.UnityHelpers.UnityControllerFactory.GetControllerInstance(System.Type controllerType = {Name = "ProductsController" FullName = "Test.Controllers.ProductsController"}) 第 23 行 C# Test.DLL!Test._Default.Page_Load(object sender = {ASP.default_aspx}, System.EventArgs e = {System.EventArgs}) 第 18 行 + 0x1a 字节 C#

在 controllerType 传递 NULL 时调用 Stack

Test.DLL!Test.UnityHelpers.UnityControllerFactory.GetControllerInstance(System.Type controllerType = null) 第 27 行 C#

首先我创建了一个 UnityControllerFactory

public class UnityControllerFactory : DefaultControllerFactory
{
    UnityContainer container;

    public UnityControllerFactory(UnityContainer container)
    {
        this.container = container;
    }

    protected override IController GetControllerInstance(Type controllerType)
    {
        if (controllerType != null)
        {
            return container.Resolve(controllerType) as IController;
        }
        else
        {
            return null; // I never expect to get here, but I do sometimes, the callstack does not show the caller
        }
    }
}

接下来,我在 global.asax 文件中添加以下代码来实例化容器工厂

    protected void Application_Start()
    {
        RegisterRoutes(RouteTable.Routes);

        // Create Unity Container if needed
        if (_container == null)
        {
            _container = new UnityContainer();
        }

        // Instantiate a new factory
        IControllerFactory unityControllerFactory = new UnityControllerFactory(_container);

        // Register it with the MVC framework
        ControllerBuilder.Current.SetControllerFactory(unityControllerFactory);

        // Register the SqlProductRepository
        _container.RegisterType<IProductsRepository, SqlProductRepository>
            (new ContainerControlledLifetimeManager());
    }

该应用程序有一个控制器

public class ProductsController : Controller
{
    public IProductsRepository productsRepository;

    public ProductsController([Dependency]IProductsRepository productsRepository)
    {
       this.productsRepository = productsRepository;
    }
}
4

1 回答 1

9

这可能是由于某些文件类型未映射到您的路由中的控制器。(例如图像)。根据我的经验,当您使用 Cassini 进行本地调试时,这种情况会更频繁地发生,因为 Cassini 允许所有请求通过 ASP.NET 进行路由,而在 IIS 中,IIS 会为您处理很多请求。这也是为什么您在堆栈中看不到此请求的代码的原因。如果您关闭 Visual Studio 中的“仅我的代码”选项,您有时可以获得关于这些内容的更好提示。

不过,这不是发生这种情况的唯一原因,但它很常见。

适当的做法是允许基本方法在这些情况下处理请求。这通常只是一个简单的文件请求,应该不会对您产生任何影响。

最简单的做法是像这样对它进行门控:

    if (controllerType != null)
    {
        return container.Resolve(controllerType) as IController;
    }
    else
    {
        return base.GetControllerInstance(requestContext, controllerType);
    }

那应该这样做。

要查看请求的用途,您可以检查 HttpContext.Current.Request 以查看您的路由中没有哪个文件。很多时候这不是你想要控制的东西,但知道请求的来源会让你感觉更好。

于 2009-08-21T16:04:18.980 回答