Error de inyección de dependencia de núcleo de ASP.NET: no se puede resolver el servicio para el tipo al intentar activar

198

Creé una aplicación .NET Core MVC y uso la inyección de dependencia y el patrón de repositorio para inyectar un repositorio en mi controlador. Sin embargo, recibo un error:

InvalidOperationException: no se puede resolver el servicio para el tipo 'WebApplication1.Data.BloggerRepository' al intentar activar '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; }
    }
}

Repositorio (IBloggerRepository.cs y 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);
        }
    }
}

No estoy seguro de lo que estoy haciendo mal. ¿Algunas ideas?

kimbaudi
fuente
Sé que esta es una vieja pregunta, pero ... No debe disponer el contexto db dentro de un servicio. El solucionador de alcance elimina automáticamente el contexto db. Si lo dispone dentro de un servicio, podría eliminarse cuando llame a un próximo servicio dentro de la misma solicitud / alcance.
Silvermind
1
Asegúrese de agregar el servicio (clase faltante) usando ´services.AddTransient <YourClassOrInterface> (); ´
Mauricio Gracia Gutierrez

Respuestas:

293

La excepción dice que no puede resolver el servicio WebApplication1.Data.BloggerRepositoryporque el constructor en su controlador está pidiendo la clase concreta en lugar de la interfaz. Así que solo cambia eso:

public BlogController(IBloggerRepository repository)
//                    ^
//                    Add this!
{
    _repository = repository;
}
DavidG
fuente
77
Increíble lo fácil que es pasar por alto a un solo personaje ... ¡gracias!
jleach
Qué campeón, que recibió esto mientras usaba la HttpContextAccessorclase, resultó que necesitaba elIHttpContextAccessor
mtbennett
Estoy tan irritado porque hice esto por más de 30 minutos. El peor VS en Mac te da el error "no se cierra inesperadamente". Tiene que ejecutarse en la terminal para obtener el error correcto, luego me topé con esta solución.
NoloMokgosi
57

Me encontré con este problema porque en la configuración de inyección de dependencia me faltaba una dependencia de un repositorio que es una dependencia de un controlador:

services.AddScoped<IDependencyOne, DependencyOne>();    <-- I was missing this line!
services.AddScoped<IDependencyTwoThatIsDependentOnDependencyOne, DependencyTwoThatIsDependentOnDependencyOne>();
hsop
fuente
Resuelto para mí, este era mi problema
anisanwesley
Solucioné mi problema porque reconocí que mis servicios no estaban en el "espacio de nombres" correcto.
user2982195
24

En mi caso, estaba tratando de hacer una inyección de dependencia para un objeto que requería argumentos de constructor. En este caso, durante el inicio, solo proporcioné los argumentos del archivo de configuración, por ejemplo:

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

Estaba teniendo un problema diferente, y sí, el constructor parametrizado para mi controlador ya estaba agregado con la interfaz correcta. Lo que hice fue algo sencillo. Solo voy a mi startup.csarchivo, donde pude ver una llamada para registrar el método.

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

En mi caso, este Registermétodo estaba en una clase separada Injector. Así que tuve que agregar mis interfaces recién introducidas allí.

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

Si ve, el parámetro para esta función es this IServiceCollection

Espero que esto ayude.

Sibeesh Venu
fuente
Este es el que olvidé agregar. Perdí la referencia del inyector al servicio. Necesario para .AddTransient <> (); ¡Gracias chicos!
Omzig
14

Solo si alguien tiene la misma situación que yo, estoy haciendo un tutorial de EntityFramework con la base de datos existente, pero cuando se crea el nuevo contexto de la base de datos en las carpetas de los modelos, necesitamos actualizar el contexto en el inicio, pero no solo en los servicios. AddDbContext pero AddIdentity también si tiene autenticación de usuarios

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

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

Necesita agregar un nuevo servicio para DBcontexten el inicio

Defecto

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

Agrega esto

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

Olvidó agregar "services.AddScoped" en el ConfigureServicesmétodo de inicio .

Prakash CS
fuente
5

Tengo este problema debido a un error bastante tonto. Había olvidado conectar mi procedimiento de configuración de servicio para descubrir controladores automáticamente en la aplicación ASP.NET Core.

Agregar este método lo resolvió:

// Add framework services.
            services.AddMvc()
                    .AddControllersAsServices();      // <---- Super important
fuego de seda
fuente
5

Tuve que agregar esta línea en ConfigureServices para poder trabajar.

services.AddSingleton<IOrderService, OrderService>();
Miguel
fuente
3

Me estaba poniendo por debajo de la excepción

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

Porque quería registrar Factory para crear instancias de la clase DbContext Derived IBlogContextFactory y usar el método Create para crear instancias de Blog Context para que pueda usar el siguiente patrón junto con la Inyección de dependencia y también puedo usar burlas para pruebas unitarias.

el patrón que quería usar es

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

Pero en lugar de nuevo BloggingContext () quiero inyectar fábrica a través del constructor como en la siguiente clase BlogController

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

aquí está mi código de registro de servicio

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

y abajo están mis modelos y clases 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 arreglar esto en el proyecto .net Core MVC - Hice los siguientes cambios en el registro de dependencia

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

En resumen, en .net core developer es responsable de inyectar la función de fábrica, que en el caso de Unity y .Net Framework se encargaron.

Rajnikant
fuente
3

Este problema se debe a que no registró el componente de acceso a datos con la interfaz escrita para él. Intenta usar lo siguiente

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

Si está utilizando AutoFac y obtiene este error, debe agregar una instrucción "As" para especificar el servicio que implementa la implementación concreta.

Es decir. Deberías escribir:

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

en vez de

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

La resolución de un servicio se realiza incluso antes de alcanzar el código de clase, por lo que debemos verificar nuestras inyecciones de dependencia.

En mi caso agregué

        services.AddScoped<IMeasurementService, MeasurementService>();

en StartupExtensions.cs

Onat Korucu
fuente
1

Agregar servicios. AgregarSingleton (); en su método ConfigureServices del archivo Startup.cs de su proyecto.

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

Para obtener más detalles, visite esta URL: https://www.youtube.com/watch?v=aMjiiWtfj2M

Para todos los métodos (es decir, AddSingleton vs AddScoped vs AddTransient) Visite esta URL: https://www.youtube.com/watch?v=v6Nr7Zman_Y&list=PL6n9fhu94yhVkdrusLaQsfERmL_Jh4XmU&index=44 )

Bhanu Pratap
fuente
1

Tuve el mismo problema y descubrí que mi código estaba usando la inyección antes de que se inicializara.

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

Sé que no tiene nada que ver con la pregunta, pero como me enviaron a esta página, creo que puede ser útil para otra persona.

Sauleil
fuente
0

Reemplacé

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

Con

services.AddTransient<IMyLogger, MyLogger>();

Y funcionó para mí.

satish madarapu
fuente
-1

Recibí este error porque declaró una variable (por encima del método ConfigureServices) de tipo que era mi contexto. Yo tenía:

CupcakeContext _ctx

No estoy seguro de lo que estaba pensando. Sé que es legal hacer esto si pasas un parámetro al método Configure.

athomas
fuente
-1

Recibí el error: "no se puede resolver la dependencia xxxxxxxx para todas las versiones de .net core". Probé todo lo que estaba disponible en Internet y estuve atrapado durante días. La única solución que se me ocurrió fue agregar el archivo nuget.config en el proyecto y luego usar dotnet restore para que funcione.

Contenido del archivo 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
fuente