ASP.NET MVC Ninject / DI - 没有为此对象定义的无参数构造函数

时间:2011-09-17 18:13:54

标签: asp.net-mvc asp.net-mvc-3 unit-testing

我正在尝试使用DI / Mocks(Ninject / Moq)进行单元测试以将产品存储库注入我的控制器,然后将其传递给我的视图模型以便进行测试。

它工作得很好,允许我对控制器动作和视图模型进行单元测试。但是,当我运行应用程序时,我得到“没有为此对象定义无参数构造函数”....现在我知道这是由于控制器试图初始化没有无参数构造函数的视图模型。

我可以创建构造函数并从中调用我的具体存储库(因此单元测试仍然使用注入/模拟的)。

这是正确的做法吗?任何建议将不胜感激!

控制器:

public class ProductsController : Controller
{
    private readonly IProductRepository productRepository;

    public ProductsController(IProductRepository productRepository)
    {
        this.productRepository = productRepository;
    }

    //
    // GET: /Products/
    public ActionResult Index(ViewModels.ProductsIndex vm)
    {
        return View(vm);
    }

}

查看型号:

public class ProductsIndex
{
    public List<CTEntities.Product> ProductList { get; set; }

    public ProductsIndex(IProductRepository prods)
    {
        ProductList = prods.List().ToList();
    }

    //Adding this constructor would fix my issue but is there a cleaner way?
    public ProductsIndex()
    {
        var prod = new CTDAL.Product();
        ProductList = prod.List().ToList();
    }
}

2 个答案:

答案 0 :(得分:2)

您的视图模型应该是DTO(数据传输对象)...因为它应该只包含属性,并且它不应该负责获取数据。您的控制器应该获取View Model的数据,如下所示:

新视图模型:

public class ProductsIndex
{
    public List<CTEntities.Product> ProductList { get; set; }
}

新控制器:

public class ProductsController : Controller
{
    private readonly IProductRepository productRepository;

    public ProductsController(IProductRepository productRepository)
    {
        this.productRepository = productRepository;
    }

    //
    // GET: /Products/
    public ActionResult Index()
    {
        var products = productRepository.List().ToList();
        return View(products);
    }

}

答案 1 :(得分:1)

一种方法是让Ninject解析你的ProductsIndex实例。如果你这样做,它会自动填写构造函数参数,只要使用Ninject解析IProductRepository

在你的情况下可能是这样的:

Kernel.Bind<IProductRepository>().To<CTDAL.Product>();
Kernel.Bind<ProductsIndex>().ToSelf();

现在您的ProductsController看起来像这样:

public class ProductsController : Controller
{
    private readonly IProductRepository productRepository;
    private readonly ProductsIndex productsIndex;
    public ProductsController(IProductRepository productRepository, 
                              ProductsIndex productsIndex)
    {
        this.productRepository = productRepository;
        this.productsIndex = productsIndex;
    }

    //
    // GET: /Products/
    public ActionResult Index()
    {
        return View(productsIndex);
    }
}

请注意,这不允许将请求值映射到Viewmodel,因此Viewmodel中的数据仅取决于您在解析时传递给它的参数(在本例中为产品)库)。