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

发布于 2024-12-04 20:35:44 字数 1126 浏览 1 评论 0原文

我正在尝试使用 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();
    }
}

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

千鲤 2024-12-11 20:35:44

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

新视图模型:

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

}

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

}
梦言归人 2024-12-11 20:35:44

一种方法是让 Ninject 解析您的 ProductsIndex 实例。如果您这样做,它会根据需要自动填充构造函数参数,前提是 IProductRepository 也使用 Ninject 解析。

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

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 中的数据只会是取决于您在解析它时传递给它的参数(在本例中为产品存储库)。

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).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文