c# dependency-injection asp.net-core asp.net-core-mvc

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



dependency-injection asp.net-core (15)

Creé una aplicación .NET Core MVC y uso el patrón de inyección de dependencia y 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?


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


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

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

En mi caso, este método de Register estaba en un Injector clase separada. 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.


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


La excepción dice que no puede resolver el servicio para WebApplication1.Data.BloggerRepository porque 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; }


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


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 DbContext Derived class 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.


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

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.


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


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


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


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

services.AddSingleton<IOrderService, OrderService>();



DBcontext agregar un nuevo servicio para DBcontext en el inicio

Defecto

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

Agrega esto

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


services.Add(new ServiceDescriptor(typeof(IMyLogger), typeof(MyLogger))) Con services.AddTransient<IMyLogger, MyLogger>()

Y funcionó para mí.


Public void ConfigureServices(IServiceCollection services) { services.AddScoped<IEventRepository, EventRepository>(); }

Olvidaste agregar Addscope en el método de inicio de Configureservices .