Проблема с внедрением зависимостей, если интерфейс не создан - PullRequest
0 голосов
/ 15 марта 2020

Я разрабатываю API, используя EntityFramework. Все шло хорошо.

namespace ControlTec.Controllers

{

    [Route("api/[controller]")]
    [ApiController]
    public class ZoneController : Controller, IBaseController<Zone>, IBaseRules<Zone>
    {
        private readonly IBaseRepository<Zone> _zoneRepository;
        public const int ID_INSERT = 0;
        public ZoneController(IBaseRepository<Zone> zoneRepository)
        {
            _zoneRepository = zoneRepository;
        }

        [HttpGet]
        public async Task<ActionResult<List<Zone>>> GetAll()
        {
            return await _zoneRepository.GetAll();
        }
    }
}

namespace ControlTec.Models
{
    public interface IBaseRepository<T> where T : new()
    {
        Task<T> Add(T objModel);
        Task<T> Update(T objModel);
        Task<T> Remove(int id);
        Task<T> GetById(int id);
        Task<List<T>> GetAll();
    }
}

namespace ControlTec.Models
{
    public class ZoneRepository : IBaseRepository<Zone>
    {
        private readonly DataContext _context;

        public ZoneRepository(DataContext context)
        {
            _context = context;
        }

        public async Task<Zone> Add(Zone objModel)
        {
            _context.Zone.Add(objModel);
            await _context.SaveChangesAsync();
            return await GetById(objModel.Id); 
        }

        public async Task<Zone> GetById(int id)
        {
            var zone = await _context.Zone.FirstOrDefaultAsync(t => t.Id == id);
            return zone;
        }

        public async Task<Zone> GetByName(string name)
        {
            var zone = await _context.Zone.FirstOrDefaultAsync(t => t.Name == name);
            return zone;
        }

        public async Task<List<Zone>> GetAll()
        {
            return await _context.Zone.ToListAsync();
        }

        public async Task<Zone> Remove(int id)
        {
            var zone = await GetById(id);
            _context.Remove(zone);
            await _context.SaveChangesAsync();
            return zone;
        }

        public async Task<Zone> Update(Zone objModel)
        {
            var zone = await GetById(objModel.Id);
            zone.Name = objModel.Name;
            await _context.SaveChangesAsync();
            return objModel;
        }

    }
}

ConfigureServices

public void ConfigureServices(IServiceCollection services)
        {
            services.ConfigureProblemDetailsModelState();
           // services.AddGlobalExceptionHandlerMiddleware();


            services.AddControllers();


            //------------------------------------------------------------------------------------------//

            var connection = Configuration["ConexaoSqlite:SqliteConnectionString"];

            services.AddDbContext<DataContext>(options => {
                options.UseSqlite(connection);
            });

            services.AddScoped<IBaseRepository<Zone>, ZoneRepository>();

        }

Проблема возникла, когда мне нужно было создать новый метод в ZoneRepository, и я не хотел реализовывать его в интерфейсе.

Таким образом, я больше не могу создавать экземпляр IBaseRepository.

Код был:

namespace ControlTec.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class ZoneController : Controller, IBaseController<Zone>, IBaseRules<Zone>
    {
        private readonly ZoneRepository _zoneRepository; //here
        public const int ID_INSERT = 0;
        public ZoneController(ZoneRepository zoneRepository) //here
        {
            _zoneRepository = zoneRepository;
        }

        [HttpGet]
        public async Task<ActionResult<List<Zone>>> GetAll()
        {
            return await _zoneRepository.GetAll();
        }
}

После изменения вы получите исключение ниже.

System.InvalidOperationException: невозможно разрешить службу для типа 'ControlTe c .Models.ZoneRepository' при попытке активировать 'ControlTe c .Controllers.ZoneController'. \ R \ n для объекта Microsoft.Extensions.DependencyInjection. ActivatorUtilities.GetService (IServiceProvider sp, Type type, Type requiredBy, bool isDefaultParameterRequired) \ r \ n
в объекте lambda_method (Закрытие, IServiceProvider, object []) \ r \ n в Func Microsoft.AspNetCore. Mvc .ontrollers .ControllerActivatorProvider.CreateActivator (дескриптор ControllerActionDescriptor) + (ControllerContext controllerContext) => {} \ r \ n в Func Microsoft.AspNetCore. Mvc .Controllers.ControllerFactoryProvider.CreateControllerFactory (дескриптор ControllerActionDescriptor) + CreateController (ControllerContext controllerContext) \ r \ n в задаче Microsoft.AspNetCore. Mvc ref. область действия, состояние объекта ref, ref bool isCompleted) \ r \ n в задаче Microsoft.AspNetCore. Mvc .Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsyn c () \ r \ n в asyn c Задача Microsoft.AspNetCore. Mvc .Infrastructure.ResourceInvoker.InvokeFilterPipelineAsyn c () + Ожидается (?) \ R \ n в asyn c Задача Microsoft.AspNetCore. Mvc .Infrastructure.ResourceInvoker.InvokeAsyn c () + Записано (?) \ r \ n в asyn c Задача Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke (HttpContext httpContext) + AwaitRequestTask (?) \ r \ n в asyn c Задача Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMidxttep ) + Ожидается (?)

Ответы [ 2 ]

3 голосов
/ 15 марта 2020

Если вы хотите разрешить ZoneRepository, вам нужно также зарегистрировать его как таковое.

services.AddScoped<ZoneRepository, ZoneRepository>();

Хотя я бы порекомендовал создать новый интерфейс IZoneRepository, который наследуется от IBaseRepository<Zone>, чтобы это было легко проверить.

1 голос
/ 15 марта 2020

Желая использовать другой метод в ZonRepository, которого нет в интерфейсе, вы нарушаете принцип LSP в SOLID принципах. Репозитории IMO generi c являются антипаттернами, поскольку они сильно ограничивают возможности, предлагаемые EF ради «согласованности». Мое золотое правило: «Не пытайтесь быть последовательными ради согласованности».

Чтобы добавить к ответу Карла, вы должны создать контрактный интерфейс с именем IZoneRepository, который расширяет IBaseRepository<Zone>, и добавить сюда нужные методы. .

public interface IZoneRepository : IBaseRepository<Zone>
{
    void SomethingZoneSpecific();
}

Тогда в вашем классе:

public class ZoneRepository : IZoneRepository
{
    public void SomethingZoneSpecific()
    {
        //...
    }

    // And all of the IBaseRepository<Zone> implementations...
}

Затем зарегистрируйте ZoneRepository вместо IZoneRepository вместо IBaseRepository<Zone> и измените зависимость вашего контроллера на IZoneRepository.

Вам следует пересмотреть использование шаблона c generi из-за таких методов, как ваша реализация "GetAll ()". В Entity Framework использование таких методов крайне неэффективно. Вы можете фильтровать, сортировать и разбивать на страницы в вашем контроллере, используя такой код:

var data = Repository.GetAll()
    .Where(x => x.ParentId == parentId)
    .OrderByDescending(x => x.CreatedAt)
    .Skip(pageSize * page)
    .Take(pageSize)
    .ToList();

Но ваш метод GetAll() уже извлекает все строки из таблицы перед фильтрацией на стороне клиента. Это много данных для отправки из БД на сервер и много памяти, необходимой для запроса на сервере, чтобы потенциально гораздо меньше данных было отправлено обратно клиенту. Тогда возникает проблема, когда у вас могут быть связанные объекты (свойства навигации), к которым можно получить доступ. Это может привести к отложенным загрузкам, поэтому запускаются дополнительные запросы. Эти ограничения часто приводят к тому, что разработчикам приходится искать отклонения от шаблонов «поймать все» c, когда возникают проблемы с производительностью. EF может очень хорошо смягчить эти проблемы с помощью проекции, в которой методы Select вместе с OrderBy, Where и вызовами Pagination против IQueryable могут привести к запросам, которые возвращают только те данные, которые требуются из БД. По этим причинам следует избегать шаблона generi c, поскольку в конечном итоге вы теряете большую часть того, что EF может принести на стол для построения эффективных и высокопроизводительных систем.

...