ASP.NET MVC和Unity 1.2容器问题

时间:2009-08-20 21:24:47

标签: asp.net-mvc unity-container

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

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

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

工作时调用堆栈

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时调用堆栈

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;
    }
}

1 个答案:

答案 0 :(得分:9)

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

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

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

最简单的方法就是按照这样做:

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

应该这样做。

要查看请求的内容,您可以检查HttpContext.Current.Request以查看路径中没有的文件。很多时候,这不是你需要控制的事情,但它会让你感觉更好,知道请求的来源是什么。