ASP.NET 基于通用存储库接口的核心通用控制器实现

ASP.NET Core, generic controller implementation based on generic repository interface

我在为实体的 CRUD 操作实现通用控制器时遇到问题。

目前我有以下 classes:

public class BaseItem
    {
        public int? Id { get; set; }
    }

此 class 是多个实体的父实体:

public class Customer : BaseItem
    {
        // some fields
    }

    public class Project : BaseItem
    {
        // some fields
    }

然后是通用存储库的接口:

    public interface IGenericItemRepository<TDomain>
                     where TDomain : BaseItem
    {
        // methods
    }

并且基于这个接口还有更具体的接口:

    public interface ICustomerRepository : IGenericItemRepository<Customer> {}

现在为了不解决EF,我用mock classes。它们的完成方式如下:

public abstract class GenericMockRepository<TDomain> : IGenericItemRepository<TDomain> where TDomain : BaseItem
...

它实现了基本 CRUD 的所有逻辑。 具体模拟仓库是这样完成的:

    public class MockCustomerRepository : GenericMockRepository<Customer>, ICustomerRepository
    {
        public MockCustomerRepository() : base()
        {
            CreateCustomersList();
        }

        private void CreateCustomersList()
        {
            // method body
        }
    }

总的来说,我可以使用我现有的设置以这种方式实现控制器:

public class CustomersController : Controller
    {
        private ICustomerRepository _customerRepo;

        public CustomersController(ICustomerRepository customerRepo)
        {
            _customerRepo = customerRepo;
        }
    }

然后我尝试实现通用控制器:

    public interface IBaseController<TDomain, TDetailsViewModel, TEditViewModel, TRepo>
        where TDomain           :   BaseItem
        where TDetailsViewModel :   BaseViewModel, new()
        where TEditViewModel    :   BaseViewModel, new()
        where TRepo             :   IGenericItemRepository<BaseItem>
    {
        [HttpGet] public IActionResult Edit(int? id);
        [HttpPost] public IActionResult Edit(TDomain entity);
        [HttpGet] public IActionResult Details(int? id);
    }

public class BaseController<TDomain, TDetailsViewModel, TEditViewModel, TRepo> : Controller, IBaseController<TDomain, TDetailsViewModel, TEditViewModel, TRepo>
        where TDomain : BaseItem
        where TDetailsViewModel : BaseViewModel, new()
        where TEditViewModel : BaseViewModel, new()
        where TRepo : IGenericItemRepository<BaseItem>
    {
        private IGenericItemRepository<BaseItem> _repo;

        public BaseController(IGenericItemRepository<BaseItem> repo)
        {
            _repo = repo;
        }
    }

但是当我尝试将我的 CustomerController 更改为以下代码时:

public class CustomersController : BaseController<Customer, BaseViewModel, BaseViewModel, ICustomerRepository>
    {
        private ICustomerRepository _customerRepo;

        public CustomersController(ICustomerRepository customerRepo)
        {
            _customerRepo = customerRepo;
        }
    }

出现以下错误:

Error CS0311 The type 'DAL.Repositories.ICustomerRepository' cannot be used as type parameter 'TRepo' in the generic type or method 'BaseController<TDomain, TDetailsViewModel, TEditViewModel, TRepo>'. There is no implicit reference conversion from 'DAL.Repositories.ICustomerRepository' to 'DAL.Repositories.IGenericItemRepository<Domain.BaseItem>'.

但是我的 ICustomerRepositoryIGenericItemRepository 的类型,不是吗?

请问我如何修复错误并正确实现通用控制器,以便我可以在我的特定控制器中重用它? 我正在检查类似的主题,但是由于以另一种方式实现了通用存储库,我无法根据示例修复它......我为特定存储库提供额外接口的原因是对于每个实体类型都会有是更具体的方法,所以我想在特定的接口中定义它们(所以这就是为什么我没有像

public interface IBaseRepository
{
  T Get<T>(int id);
  void Save<T>(T entity);
}

非常感谢您的提前帮助!

BaseControllerIBaseController 中尝试 IGenericItemRepository<TDomain> 而不是 IGenericItemRepository<BaseItem>

public class BaseController<TDomain, TDetailsViewModel, TEditViewModel, TRepo> : Controller, IBaseController<TDomain, TDetailsViewModel, TEditViewModel, TRepo> 
    where TDomain : BaseItem
    where TDetailsViewModel : BaseViewModel, new()
    where TEditViewModel : BaseViewModel, new()
    where TRepo : IGenericItemRepository<TDomain>
{
    private IGenericItemRepository<TDomain> _repo;

    public BaseController(IGenericItemRepository<TDomain> repo)
    {
        _repo = repo;
    }
}

 public interface IBaseController<TDomain, TDetailsViewModel, TEditViewModel, TRepo>
    where TDomain           :   BaseItem
    where TDetailsViewModel :   BaseViewModel, new()
    where TEditViewModel    :   BaseViewModel, new()
    where TRepo             :   IGenericItemRepository<TDomain>
{
    [HttpGet] public IActionResult Edit(int? id);
    [HttpPost] public IActionResult Edit(TDomain entity);
    [HttpGet] public IActionResult Details(int? id);
}