开发者

ASP.NET MVC Ninject / DI - No parameterless constructor defined for this object

开发者 https://www.devze.com 2023-04-05 08:41 出处:网络
I am using trying to get my head round unit testing with DI/Mocks (Ninject/Moq) to inject a Product repository into my controller which I then pass to my view model in order to allow testing of that.

I am using trying to get my head round unit testing with DI/Mocks (Ninject/Moq) to inject a Product repository into my controller which I then pass to my view model in order to allow testing of that.

It is working great and is allowing me to unit test the controller action and the view model. However, when I run the application I get "No parameterless constructor defined for this object"....now I know this is due to the controller trying to initialise the View Model which doesn't have a parameterless constructor.

I could create the constructor and call my concrete repository from that (so unit tests still use the injected/mocked one).

Is this the correct approach? Any advice would be greatly appreciated!

Controller:

public class ProductsController : Controller
{
    private readonly IProductRepository productRe开发者_JS百科pository;

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

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

}

View model:

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


Your View Model should be a DTO (Data Transfer Object) ... in that it should only contain properties, and it should NOT be responsible for getting data. Your controller should get the data for the View Model, like so:

New View Model:

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

New Controller:

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

}


One approach would be to let Ninject resolve your ProductsIndex instances. If you do that, it will automatically fill in the constructor arguments as required, provided IProductRepository is resolved using Ninject as well.

In your case could be something like:

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

Now your ProductsController could look like this:

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

Keep in mind that this would not allow for request values to be mapped to your Viewmodel, so the data in your Viewmodel would only be dependent on the parameters you pass into it at the time you resolve it (in this case the product repository).

0

精彩评论

暂无评论...
验证码 换一张
取 消