【问题标题】:ASP.NET Core - System.InvalidOperationException: Unable to resolve service for type while attempting to activateASP.NET Core - System.InvalidOperationException:尝试激活时无法解析服务类型
【发布时间】:2021-12-02 18:48:29
【问题描述】:

在我的 ASP.NER Core Web API 项目中,我有以下代码:

public interface IUriPaginationService
{
    public Uri GetPaginationUri(int page, string actionUrl);
}

public class UriPaginationService : IUriPaginationService
{
    private readonly string _baseUri;
    public UriPaginationService(string baseUri)
    {
        _baseUri = baseUri;
    }
    public Uri GetPaginationUri(int page, string actionUrl)
    {
        string baseUrl = $"{_baseUri}{actionUrl}";
        return new Uri(baseUrl);
    }
}

public abstract class AuditableBaseEntity
{
    public AuditableBaseEntity()
    {
        CreatedDate = DateTime.Now;
    }

    [Key]
    public virtual long Id { get; set; }

    [JsonIgnore]
    public bool IsDeleted { get; set; }

    [DataType(DataType.DateTime)]
    public DateTime? CreatedDate { get; set; }
    public long? LastUpdatedBy { get; set; }
}

存储库:

public interface IBaseRepository<T> where T : AuditableBaseEntity
{

    Task<IEnumerable<T>> GetAll();
    Task<T> GetById(long id);
    bool EntityExists(long id);
}

public class BaseRepository<T> : IBaseRepository<T> where T : AuditableBaseEntity
{
    private readonly DDMDbContext _context;
    private DbSet<T> _entities;

    public BaseRepository(DDMDbContext context)
    {
        _context = context;
        _entities = context.Set<T>();
    }

    public async Task<IEnumerable<T>> GetAll()
    {
        var list = await _entities.Where(x => x.IsDeleted == false).ToListAsync();
        return list;
    }

    public async Task<T> GetById(long id)
    {
        return await _entities.FindAsync(id);
    }

    public bool EntityExists(long id)
    {
        return _entities.Any(x => x.Id == id && x.IsDeleted == false);
    }
}

工作单元:

public interface IUnitOfWork : IDisposable
{
    IBaseRepository<Merchant> MerchantRepository { get; }
}

public class UnitOfWork : IUnitOfWork
{
    private readonly DDMDbContext _context;

    public UnitOfWork(DDMDbContext context)
    {
        _context = context;
    }

    private readonly IBaseRepository<Merchant> _merchantRepository;
    public IBaseRepository<Merchant> MerchantRepository => _merchantRepository ?? new BaseRepository<Merchant>(_context);

    public void Dispose()
    {
        if (_context != null)
        {
            _context.Dispose();
        }
    }
}

服务:

public interface IMerchantService
{
    public Task<IEnumerable<Merchant>> GetMerchants();
    public bool EntityExists(long id);
    public Task<ResponsePagination<GenericPagination<MerchantGetDto>>> GetAll(int page, int sizeByPage);
}


public class MerchantService : IMerchantService
{
    private readonly IUnitOfWork _unitOfWork;
    private readonly IUriPaginationService _uriPaginationService;
    private readonly DDMDbContext _context;

    public MerchantService(IUnitOfWork unitOfWork, IUriPaginationService uriPaginationService, DDMDbContext context)
    {
        _unitOfWork = unitOfWork;
        _uriPaginationService = uriPaginationService;
        _context = context;
    }
    public async Task<IEnumerable<Merchant>> GetMerchants()
    {
        return await _unitOfWork.MerchantRepository.GetAll();
    }
    public async Task<ResponsePagination<GenericPagination<MerchantGetDto>>> GetAll(int page, int sizeByPage)
    {
        string nextRoute = null, previousRoute = null;
        IEnumerable<Merchant> data = await _unitOfWork.MerchantRepository.GetAll();

        var mapper = new EntityMapper();
        var merchantsDto = data.Select(m => mapper.FromMerchantToMerchantGetDto(m)).ToList();

        GenericPagination<MerchantGetDto> objGenericPagination = GenericPagination<MerchantGetDto>.Create(merchantsDto, page, sizeByPage);
        ResponsePagination<GenericPagination<MerchantGetDto>> response = new ResponsePagination<GenericPagination<MerchantGetDto>>(objGenericPagination);
        response.CurrentPage = objGenericPagination.CurrentPage;
        response.HasNextPage = objGenericPagination.HasNextPage;
        response.HasPreviousPage = objGenericPagination.HasPreviousPage;
        response.PageSize = objGenericPagination.PageSize;
        response.TotalPages = objGenericPagination.TotalPages;
        response.TotalRecords = objGenericPagination.TotalRecords;
        response.Data = objGenericPagination;

        if (response.HasNextPage)
        {
            nextRoute = $"/merchants?page={(page + 1)}";
            response.NextPageUrl = _uriPaginationService.GetPaginationUri(page, nextRoute).ToString();
        }
        else
        {
            response.NextPageUrl = null;
        }

        if (response.HasPreviousPage)
        {
            previousRoute = $"/merchants?page={(page - 1)}";
            response.PreviousPageUrl = _uriPaginationService.GetPaginationUri(page, previousRoute).ToString();
        }
        else
        {
            response.PreviousPageUrl = null;
        }

        return response;
    }

    public bool EntityExists(long id)
    {
        return _unitOfWork.MerchantRepository.EntityExists(id);
    }

    public async Task<Merchant> GetById(long id)
    {
        return await _unitOfWork.MerchantRepository.GetById(id);
    }
}

控制器:

[Produces("application/json")]
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class AdminController : ControllerBase
{
    private readonly IMerchantService _merchantService;

    public AdminController(MerchantService merchantService)
    {
        _merchantService = merchantService;
    }

    [HttpGet("merchants")]
    public async Task<ResponsePagination<GenericPagination<MerchantGetDto>>> GetAll(int page, int sizeByPage)
    {
        return await _merchantService.GetAll(page, sizeByPage);
    }
}

启动:

    public void ConfigureServices(IServiceCollection services)
    {
//        services.AddMvc();
        services.AddControllers();
        services.AddDb(Configuration);
        services.AddJwtAuthentication(Configuration);
        services.AddMvcCoreFramework(Configuration);
        services.AddAppAuthorization(Configuration);

        services.AddControllersWithViews();
        services.AddRazorPages();

        services.AddVersioning();

        services.AddSwagger();

        services.AddRouting(options => options.LowercaseUrls = true);

        services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
        services.AddSingleton<IUriPaginationService>(provider =>
        {
            var accesor = provider.GetRequiredService<IHttpContextAccessor>();
            var request = accesor.HttpContext.Request;
            var absoluteUri = string.Concat(request.Scheme, "://", request.Host.ToUriComponent());
            return new UriPaginationService(absoluteUri);
        });

        services.AddScoped(typeof(IBaseRepository<>), typeof(BaseRepository<>));
        services.AddScoped<IUnitOfWork, UnitOfWork>();
        services.AddTransient<IMerchantService, MerchantService>();
    }

当我在邮递员获取请求上使用它时:

https://localhost:44341/api/v1/merchant/mandates

我收到了这个错误:

System.InvalidOperationException:尝试激活“API.Web.Controllers.v1.MerchantController”时无法解析“API.Infrastructure.Services.Concrete.MerchantService”类型的服务。 在 Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired)

我该如何解决这个问题:

谢谢

【问题讨论】:

  • 你在哪里做依赖注入?
  • 您是否将服务添加到您的 Startup.cs 中?
  • @DiegoBascans - 是的,我在 startup.cs 有服务。我已经在帖子中更新了我的代码
  • 我怀疑您这里的代码比重现您的问题所必需的要多。换句话说,您的代码不是最小的。请查看minimal reproducible example。例如,为什么我们需要查看 IUriPaginationService、UriPaginationService、AuditableBaseEntity、IBaseRepository、BaseRepository、IUnitOfWork 和 IIUnitOfWork 类型?使用仍然重现您的问题所需的最少代码量。理想情况下,我应该能够在我的盒子上创建一个新的 ASP.NET 核心应用程序,放入您提供的类,然后重现错误。

标签: c# asp.net-core


【解决方案1】:

控制器依赖于实现(类)

public AdminController(MerchantService merchantService)
{
    _merchantService = merchantService;
}

当您注册抽象(接口)时。

services.AddTransient<IMerchantService, MerchantService>();

根据注册情况,控制器很可能依赖于接口(抽象)

public AdminController(IMerchantService merchantService) //<-- CHANGED TO INTERFACE
{
    _merchantService = merchantService;
}

将控制器构造函数更新为依赖于注册的抽象将修复显示的异常。

【讨论】:

    【解决方案2】:

    除了 Nkosi 回答之外,下面列出了三种注入服务及其范围。三种方法定义服务的生命周期

    1. 添加瞬态 每次请求时都会创建瞬态生命周期服务。此生命周期最适合轻量级、无状态的服务。

    2. 添加范围 范围内的生命周期服务为每个请求创建一次。

    3. 添加单例 单例生命周期服务在第一次被请求时创建(或者在运行 ConfigureServices 时,如果您在其中指定了一个实例),然后每个后续请求都将使用同一个实例。

    Brief explation can be found here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-09-23
      • 2023-03-24
      • 1970-01-01
      • 2021-12-25
      • 2020-07-01
      • 1970-01-01
      • 2022-09-24
      • 2018-04-06
      相关资源
      最近更新 更多