Erro de injeção de dependência de núcleo do ASP.NET: Não é possível resolver o serviço para o tipo ao tentar ativar

198

Criei um aplicativo .NET Core MVC e usei o Dependency Injection and Repository Pattern para injetar um repositório no meu controlador. No entanto, estou recebendo um erro:

InvalidOperationException: não foi possível resolver o serviço para o tipo 'WebApplication1.Data.BloggerRepository' ao tentar ativar 'WebApplication1.Controllers.BlogController'.

Modelo (Blog.cs)

namespace WebApplication1.Models
{
    public class Blog
    {
        public int BlogId { get; set; }
        public string Url { get; set; }
    }
}

DbContext (BloggingContext.cs)

using Microsoft.EntityFrameworkCore;
using WebApplication1.Models;

namespace WebApplication1.Data
{
    public class BloggingContext : DbContext
    {
        public BloggingContext(DbContextOptions<BloggingContext> options)
            : base(options)
        { }
        public DbSet<Blog> Blogs { get; set; }
    }
}

Repositório (IBloggerRepository.cs & BloggerRepository.cs)

using System;
using System.Collections.Generic;
using WebApplication1.Models;

namespace WebApplication1.Data
{
    internal interface IBloggerRepository : IDisposable
    {
        IEnumerable<Blog> GetBlogs();

        void InsertBlog(Blog blog);

        void Save();
    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using WebApplication1.Models;

namespace WebApplication1.Data
{
    public class BloggerRepository : IBloggerRepository
    {
        private readonly BloggingContext _context;

        public BloggerRepository(BloggingContext context)
        {
            _context = context;
        }

        public IEnumerable<Blog> GetBlogs()
        {
            return _context.Blogs.ToList();
        }

        public void InsertBlog(Blog blog)
        {
            _context.Blogs.Add(blog);
        }

        public void Save()
        {
            _context.SaveChanges();
        }

        private bool _disposed;

        protected virtual void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                if (disposing)
                {
                    _context.Dispose();
                }
            }
            _disposed = true;
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    }
}

Startup.cs (código relevante)

public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddDbContext<BloggingContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

    services.AddScoped<IBloggerRepository, BloggerRepository>();

    services.AddMvc();

    // Add application services.
    services.AddTransient<IEmailSender, AuthMessageSender>();
    services.AddTransient<ISmsSender, AuthMessageSender>();
}

Controlador (BlogController.cs)

using System.Linq;
using Microsoft.AspNetCore.Mvc;
using WebApplication1.Data;
using WebApplication1.Models;

namespace WebApplication1.Controllers
{
    public class BlogController : Controller
    {
        private readonly IBloggerRepository _repository;

        public BlogController(BloggerRepository repository)
        {
            _repository = repository;
        }

        public IActionResult Index()
        {
            return View(_repository.GetBlogs().ToList());
        }

        public IActionResult Create()
        {
            return View();
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public IActionResult Create(Blog blog)
        {
            if (ModelState.IsValid)
            {
                _repository.InsertBlog(blog);
                _repository.Save();
                return RedirectToAction("Index");
            }
            return View(blog);
        }
    }
}

Não tenho certeza do que estou fazendo de errado. Alguma ideia?

kimbaudi
fonte
Sei que essa é uma pergunta antiga, mas ... Você não deve descartar o contexto db dentro de um serviço. O contexto db é descartado automaticamente pelo resolvedor de escopo. Se você descartá-lo dentro de um serviço, ele poderá ser descartado ao chamar um próximo serviço dentro da mesma solicitação / escopo.
precisa
1
Verifique se o serviço (classe ausente) é adicionado usando'services.AddTransient <YourClassOrInterface> (); '
Mauricio Gracia Gutierrez

Respostas:

293

A exceção diz que não pode resolver o serviço WebApplication1.Data.BloggerRepositoryporque o construtor no seu controlador está solicitando a classe concreta em vez da interface. Então, basta mudar isso:

public BlogController(IBloggerRepository repository)
//                    ^
//                    Add this!
{
    _repository = repository;
}
DavidG
fonte
7
Incrível como é fácil ignorar um único personagem ... obrigado!
Jleach #
O que um campeão, recebido isso enquanto usava a HttpContextAccessorclasse, descobriu que eu precisava doIHttpContextAccessor
mtbennett 26/03
Tão irritado porque eu gastei mais de 30 minutos com isso.Worst VS no Mac dá a você o erro "não saia inesperadamente". Tem que correr no terminal para obter o erro correto, então eu topei com esta solução.
NoloMokgosi 10/04
57

Corri para esse problema porque na configuração da injeção de dependência estava faltando uma dependência de um repositório que é uma dependência de um controlador:

services.AddScoped<IDependencyOne, DependencyOne>();    <-- I was missing this line!
services.AddScoped<IDependencyTwoThatIsDependentOnDependencyOne, DependencyTwoThatIsDependentOnDependencyOne>();
hsop
fonte
Resolvido para mim, este era o meu problema
anisanwesley
Resolvi meu problema, porque reconheci que meus serviços não estavam no "espaço para nome" correto.
user2982195 29/04
24

No meu caso, eu estava tentando fazer injeção de dependência para um objeto que exigia argumentos construtores. Nesse caso, durante a inicialização, apenas forneci os argumentos do arquivo de configuração, por exemplo:

var config = Configuration.GetSection("subservice").Get<SubServiceConfig>();
services.AddScoped<ISubService>(provider => new SubService(config.value1, config.value2));
riqitang
fonte
18

Eu estava tendo um problema diferente e, sim, o construtor parametrizado para o meu controlador já foi adicionado com a interface correta. O que eu fiz foi algo direto. Acabei de ir ao meu startup.csarquivo, onde pude ver uma chamada para registrar o método.

public void ConfigureServices(IServiceCollection services)
{
   services.Register();
}

No meu caso, esse Registermétodo estava em uma classe separada Injector. Então eu tive que adicionar minhas interfaces recém-introduzidas lá.

public static class Injector
{
    public static void Register(this IServiceCollection services)
    {
        services.AddTransient<IUserService, UserService>();
        services.AddTransient<IUserDataService, UserDataService>();
    }
}

Se você vir, o parâmetro para esta função é this IServiceCollection

Espero que isto ajude.

Sibeesh Venu
fonte
Este é o que eu esqueci de adicionar. Perdi a referência do injetor ao serviço. Necessário para .AddTransient <> (); Obrigado pessoal!
Omzig 16/06
14

Somente se alguém tiver a mesma situação que eu, estou fazendo um tutorial do EntityFramework com o banco de dados existente, mas quando o novo contexto do banco de dados é criado nas pastas de modelos, precisamos atualizar o contexto na inicialização, mas não apenas nos serviços. AddDbContext, mas AddIdentity também se você tiver autenticação de usuários

services.AddDbContext<NewDBContext>(options =>
                options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

services.AddIdentity<ApplicationUser, IdentityRole>()
                .AddEntityFrameworkStores<NewDBContext>()
                .AddDefaultTokenProviders();
Adrian
fonte
7

Você precisa adicionar um novo serviço para DBcontextna inicialização

Padrão

services.AddDbContext<ApplicationDbContext>(options =>
                options.UseSqlServer(
                    Configuration.GetConnectionString("DefaultConnection")));

Adicione isso

services.AddDbContext<NewDBContext>(options =>
                options.UseSqlServer(
                    Configuration.GetConnectionString("NewConnection")));
Warit Taveekarn
fonte
7
Public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<IEventRepository, EventRepository>();           
}

Você esqueceu de adicionar "services.AddScoped" no ConfigureServicesmétodo de inicialização .

Prakash CS
fonte
5

Eu peguei esse problema por causa de um erro bobo. Eu tinha esquecido de conectar meu procedimento de configuração de serviço para descobrir controladores automaticamente no aplicativo ASP.NET Core.

A adição deste método resolveu:

// Add framework services.
            services.AddMvc()
                    .AddControllersAsServices();      // <---- Super important
silkfire
fonte
5

Eu tive que adicionar esta linha no ConfigureServices para funcionar.

services.AddSingleton<IOrderService, OrderService>();
Mike
fonte
3

Eu estava ficando abaixo da exceção

        System.InvalidOperationException: Unable to resolve service for type 'System.Func`1[IBlogContext]' 
        while attempting to activate 'BlogContextFactory'.\r\n at 
        Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type serviceType, Type implementationType, ISet`1 callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)\r\n at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(Type serviceType, Type implementationType, ISet`1 callSiteChain)\r\n at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, Type serviceType, ISet`1 callSiteChain)\r\n at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(Type serviceType, ISet`1 callSiteChain)\r\n at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(Type serviceType, ISet`1 callSiteChain)\r\n at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type serviceType, Type implementationType, ISet`1 callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)\r\n at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(Type serviceType, Type implementationType, ISet`1 callSiteChain)\r\n at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, Type serviceType, ISet`1 callSiteChain)\r\n at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(Type serviceType, ISet`1 callSiteChain)\r\n at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(Type serviceType, ISet`1 callSiteChain)\r\n at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(Type serviceType, ServiceProvider serviceProvider)\r\n at System.Collections.Concurrent.ConcurrentDictionaryExtensions.GetOrAdd[TKey, TValue, TArg] (ConcurrentDictionary`2 dictionary, TKey key, Func`3 valueFactory, TArg arg)\r\n at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType)\r\n at Microsoft.Extensions.Internal.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired)\r\n at lambda_method(Closure , IServiceProvider , Object[] )\r\n at Microsoft.AspNetCore.Mvc.Controllers.ControllerFactoryProvider.<>c__DisplayClass5_0.<CreateControllerFactory>g__CreateController|0(ControllerContext controllerContext)\r\n at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)\r\n at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync()\r\n at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextExceptionFilterAsync()

Como eu queria registrar o Factory para criar instâncias da classe derivada DbContext IBlogContextFactory e usar o método Create para instanciar a instância do Contexto do Blog para que eu possa usar o padrão abaixo junto com a injeção de dependência e também usar simulação para testes de unidade.

o padrão que eu queria usar é

public async Task<List<Blog>> GetBlogsAsync()
        {
            using (var context = new BloggingContext())
            {
                return await context.Blogs.ToListAsync();
            }
        }

Mas, em vez do novo BloggingContext (), quero injetar fábrica via construtor, como na classe BlogController abaixo

    [Route("blogs/api/v1")]

public class BlogController : ControllerBase
{
    IBloggingContextFactory _bloggingContextFactory;

    public BlogController(IBloggingContextFactory bloggingContextFactory)
    {
        _bloggingContextFactory = bloggingContextFactory;
    }

    [HttpGet("blog/{id}")]
    public async Task<Blog> Get(int id)
    {
        //validation goes here 
        Blog blog = null;
        // Instantiage context only if needed and dispose immediately
        using (IBloggingContext context = _bloggingContextFactory.CreateContext())
        {
            blog = await context.Blogs.FindAsync(id);
        }
        //Do further processing without need of context.
        return blog;
    }
}

aqui está o meu código de registro de serviço

            services
            .AddDbContext<BloggingContext>()
            .AddTransient<IBloggingContext, BloggingContext>()
            .AddTransient<IBloggingContextFactory, BloggingContextFactory>();

e abaixo estão meus modelos e classes de fábrica

    public interface IBloggingContext : IDisposable
{
    DbSet<Blog> Blogs { get; set; }
    DbSet<Post> Posts { get; set; }
}

public class BloggingContext : DbContext, IBloggingContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseInMemoryDatabase("blogging.db");
        //optionsBuilder.UseSqlite("Data Source=blogging.db");
    }
}

public interface IBloggingContextFactory
{
    IBloggingContext CreateContext();
}

public class BloggingContextFactory : IBloggingContextFactory
{
    private Func<IBloggingContext> _contextCreator;
    public BloggingContextFactory(Func<IBloggingContext> contextCreator)// This is fine with .net and unity, this is treated as factory function, but creating problem in .netcore service provider
    {
        _contextCreator = contextCreator;
    }

    public IBloggingContext CreateContext()
    {
        return _contextCreator();
    }
}

public class Blog
{
    public Blog()
    {
        CreatedAt = DateTime.Now;
    }

    public Blog(int id, string url, string deletedBy) : this()
    {
        BlogId = id;
        Url = url;
        DeletedBy = deletedBy;
        if (!string.IsNullOrWhiteSpace(deletedBy))
        {
            DeletedAt = DateTime.Now;
        }
    }
    public int BlogId { get; set; }
    public string Url { get; set; }
    public DateTime CreatedAt { get; set; }
    public DateTime? DeletedAt { get; set; }
    public string DeletedBy { get; set; }
    public ICollection<Post> Posts { get; set; }

    public override string ToString()
    {
        return $"id:{BlogId} , Url:{Url} , CreatedAt : {CreatedAt}, DeletedBy : {DeletedBy}, DeletedAt: {DeletedAt}";
    }
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
    public int BlogId { get; set; }
    public Blog Blog { get; set; }
}

----- Para corrigir isso no projeto .net Core MVC - fiz abaixo as alterações no registro de dependência

            services
            .AddDbContext<BloggingContext>()
            .AddTransient<IBloggingContext, BloggingContext>()
            .AddTransient<IBloggingContextFactory, BloggingContextFactory>(
                    sp => new BloggingContextFactory( () => sp.GetService<IBloggingContext>())
                );

Em resumo, o desenvolvedor do núcleo .net é responsável por injetar a função de fábrica, a qual, no caso do Unity e do .Net Framework, foi cuidada.

Rajnikant
fonte
3

Esse problema ocorre porque você não registrou o componente de acesso a dados com a interface criada para ele. Tente usar da seguinte maneira

services.AddTransient<IMyDataProvider, MyDataAccess>();`
Shailesh Tiwari
fonte
2

Se você estiver usando o AutoFac e obtendo esse erro, adicione uma instrução "Como" para especificar o serviço que a implementação concreta implementa.

Ou seja. você deve escrever:

containerBuilder.RegisterType<DataService>().As<DataService>();

ao invés de

containerBuilder.RegisterType<DataService>();
thebfactor
fonte
2

A resolução de um serviço é feita antes mesmo de o código da classe ser alcançado, portanto, precisamos verificar nossas injeções de dependência.

No meu caso eu adicionei

        services.AddScoped<IMeasurementService, MeasurementService>();

em StartupExtensions.cs

Onat Korucu
fonte
1

Adicionar services.AddSingleton (); no método ConfigureServices do arquivo Startup.cs do seu projeto.

public void ConfigureServices(IServiceCollection services)
    {
        services.AddRazorPages();
        // To register interface with its concrite type
        services.AddSingleton<IEmployee, EmployeesMockup>();
    }

Para mais detalhes, visite este URL: https://www.youtube.com/watch?v=aMjiiWtfj2M

para Todos os métodos (por exemplo, AddSingleton vs AddScoped vs AddTransient) Visite este URL: https://www.youtube.com/watch?v=v6Nr7Zman_Y&list=PL6n9fhu94yhVkdrusLaQsfERmL_Jh4XmU&index=44 )

Bhanu Pratap
fonte
1

Eu tive o mesmo problema e descobri que meu código estava usando a injeção antes de ser inicializada.

services.AddControllers(); // Will cause a problem if you use your IBloggerRepository in there since it's defined after this line.
services.AddScoped<IBloggerRepository, BloggerRepository>();

Sei que não tem nada a ver com a pergunta, mas desde que fui enviada para esta página, acho que pode ser útil para outra pessoa.

Sauleil
fonte
0

Eu troquei

services.Add(new ServiceDescriptor(typeof(IMyLogger), typeof(MyLogger)));

Com

services.AddTransient<IMyLogger, MyLogger>();

E funcionou para mim.

satish madarapu
fonte
-1

Eu recebi esse erro porque declarei uma variável (acima do método ConfigureServices) do tipo que era meu contexto. Eu tinha:

CupcakeContext _ctx

Não tenho certeza do que estava pensando. Eu sei que é legal fazer isso se você estiver passando um parâmetro para o método Configure.

athomas
fonte
-1

Eu recebi o erro: "Incapaz de resolver a dependência xxxxxxxx para todas as versões do núcleo .net". Eu tentei tudo disponível na internet e fiquei preso por dias. A única solução que encontrei foi adicionar o arquivo nuget.config no projeto e, em seguida, usar a restauração do dotnet para fazê-lo funcionar.

Conteúdo do arquivo nuget.config:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <add key="AspNetCore" value="https://dotnet.myget.org/F/aspnetcore-ci-dev/api/v3/index.json" />
    <add key="AspNetCoreTools" value="https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json" />
    <add key="NuGet" value="https://api.nuget.org/v3/index.json" />
  </packageSources>
</configuration>
Shantanu Gautam
fonte