Erreur d'injection de dépendance ASP.NET Core: impossible de résoudre le service pour le type lors de la tentative d'activation


222

J'ai créé une application .NET Core MVC et j'utilise Dependency Injection and Repository Pattern pour injecter un référentiel dans mon contrôleur. Cependant, j'obtiens une erreur:

InvalidOperationException: impossible de résoudre le service pour le type «WebApplication1.Data.BloggerRepository» lors de la tentative d'activation de «WebApplication1.Controllers.BlogController».

Modèle (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; }
    }
}

Référentiel (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 (code pertinent)

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

Contrôleur (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);
        }
    }
}

Je ne suis pas sûr de ce que je fais de mal. Des idées?


Je sais que c'est une vieille question, mais ... Vous ne devriez pas disposer le contexte db dans un service. Le contexte db est automatiquement supprimé par le résolveur de portée. Si vous le supprimez dans un service, il peut être supprimé lors de l'appel d'un service suivant dans la même demande / portée.
Silvermind

1
Assurez-vous que le service (classe manquante) est ajouté en utilisant ´services.AddTransient <YourClassOrInterface> (); ´
Mauricio Gracia Gutierrez

Réponses:


334

L'exception indique qu'il ne peut pas résoudre le service WebApplication1.Data.BloggerRepositorycar le constructeur de votre contrôleur demande la classe concrète au lieu de l'interface. Alors changez simplement cela:

public BlogController(IBloggerRepository repository)
//                    ^
//                    Add this!
{
    _repository = repository;
}

9
Incroyable comme il est facile d'oublier un seul personnage ... merci!
jleach

Quel champion, a reçu cela en utilisant la HttpContextAccessorclasse, il s'avère que j'avais besoin duIHttpContextAccessor
mtbennett

Tellement irrité parce que j'ai perdu plus de 30 minutes à ce sujet. Le pire VS sur Mac vous donne l'erreur "ne pas quitter de manière inattendue". Doit fonctionner sur le terminal pour obtenir l'erreur correcte, puis je suis tombé sur cette solution.
NoloMokgosi

68

J'ai rencontré ce problème car dans la configuration d'injection de dépendance, il me manquait une dépendance d'un référentiel qui est une dépendance d'un contrôleur:

services.AddScoped<IDependencyOne, DependencyOne>();    <-- I was missing this line!
services.AddScoped<IDependencyTwoThatIsDependentOnDependencyOne, DependencyTwoThatIsDependentOnDependencyOne>();

2
Résolu pour moi, c'était mon problème
anisanwesley

J'ai résolu mon problème, car j'ai reconnu que mes services n'étaient pas dans le bon «espace de noms».
user2982195 le

C'était aussi mon problème. Merci!
Jedidiah le

26

Dans mon cas, j'essayais de faire une injection de dépendance pour un objet nécessitant des arguments de constructeur. Dans ce cas, au démarrage, je viens de fournir les arguments du fichier de configuration, par exemple:

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

20

J'avais un problème différent, et oui, le constructeur paramétré pour mon contrôleur a déjà été ajouté avec la bonne interface. Ce que j'ai fait était quelque chose de simple. Je vais juste à mon startup.csdossier, où je pourrais voir un appel à la méthode d'enregistrement.

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

Dans mon cas, cette Registerméthode était dans une classe distincte Injector. J'ai donc dû y ajouter mes interfaces nouvellement introduites.

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

Si vous voyez, le paramètre de cette fonction est this IServiceCollection

J'espère que cela t'aides.


C'est celui que j'ai oublié d'ajouter. J'ai manqué la référence de l'injecteur au service. Nécessaire à .AddTransient <> (); Merci les gars!
Omzig le

14

Seulement si quelqu'un a la même situation que moi, je fais un tutoriel sur EntityFramework avec la base de données existante, mais lorsque le nouveau contexte de base de données est créé sur les dossiers de modèles, nous devons mettre à jour le contexte au démarrage, mais pas seulement dans les services. AddDbContext mais AddIdentity aussi si vous avez l'authentification des utilisateurs

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

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

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

Vous avez oublié d'ajouter "services.AddScoped" dans la ConfigureServicesméthode de démarrage .



6

J'ai dû ajouter cette ligne dans les ConfigureServices pour pouvoir travailler.

services.AddSingleton<IOrderService, OrderService>();

5

J'ai eu ce problème à cause d'une erreur plutôt stupide. J'avais oublié de raccorder ma procédure de configuration de service pour découvrir automatiquement les contrôleurs dans l'application ASP.NET Core.

L'ajout de cette méthode l'a résolu:

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

4

Dans mon cas, l'API .Net Core 3.0 dans Startup.cs, dans la méthode

public void ConfigureServices(IServiceCollection services)

Je devais ajouter

services.AddScoped<IStateService, StateService>();

1
Salut, gars! ça l'a fait pour moi. Je savais que dans mon cas, c'était cette solution.
theITvideos

3

J'étais en dessous de l'exception

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

Parce que je voulais enregistrer Factory pour créer des instances de la classe DbContext Derived IBlogContextFactory et utiliser la méthode Create pour instancier une instance de Blog Context afin que je puisse utiliser le modèle ci-dessous avec l'injection de dépendances et que je puisse également utiliser la simulation pour les tests unitaires.

le modèle que je voulais utiliser est

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

Mais au lieu du nouveau BloggingContext (), je veux injecter l'usine via le constructeur comme ci-dessous la classe 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;
    }
}

voici mon code d'enregistrement de service

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

et ci-dessous mes modèles et classes d'usine

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

----- Pour résoudre ce problème dans le projet .net Core MVC - J'ai fait ci-dessous les modifications sur l'enregistrement des dépendances

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

En bref, dans .net, le développeur principal est responsable d'injecter la fonction d'usine, ce qui dans le cas de Unity et .Net Framework a été pris en charge.


3

Ce problème est dû au fait que vous n'avez pas enregistré le composant d'accès aux données avec l'interface écrite pour lui. Essayez d'utiliser comme suit

services.AddTransient<IMyDataProvider, MyDataAccess>();`

2

Si vous utilisez AutoFac et obtenez cette erreur, vous devez ajouter une instruction "As" pour spécifier le service que l'implémentation concrète implémente.

C'est à dire. vous devriez écrire:

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

au lieu de

containerBuilder.RegisterType<DataService>();


2

J'ai eu le même problème et j'ai découvert que mon code utilisait l'injection avant son initialisation.

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

Je sais que cela n'a rien à voir avec la question, mais depuis que j'ai été envoyé sur cette page, je pense que cela peut être utile à quelqu'un d'autre.


2

La résolution d'un service est effectuée avant même que le code de classe ne soit atteint, nous devons donc vérifier nos injections de dépendances.

Dans mon cas j'ai ajouté

        services.AddScoped<IMeasurementService, MeasurementService>();

dans StartupExtensions.cs


1

Ajouter des services.AddSingleton (); dans votre méthode ConfigureServices du fichier Startup.cs de votre projet.

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

Pour plus de détails, veuillez visiter cette URL: https://www.youtube.com/watch?v=aMjiiWtfj2M

pour toutes les méthodes (c'est-à-dire AddSingleton vs AddScoped vs AddTransient) Veuillez visiter cette URL: https://www.youtube.com/watch?v=v6Nr7Zman_Y&list=PL6n9fhu94yhVkdrusLaQsfERmL_Jh4XmU&index=44 )


0

j'ai remplacé

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

Avec

services.AddTransient<IMyLogger, MyLogger>();

Et cela a fonctionné pour moi.



0

J'ai eu des problèmes en essayant d'injecter à partir de mon fichier Program.cs , en utilisant CreateDefaultBuilder comme ci-dessous, mais j'ai fini par le résoudre en ignorant le classeur par défaut. (voir ci-dessous).

var host = Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
    webBuilder.ConfigureServices(servicesCollection => { servicesCollection.AddSingleton<ITest>(x => new Test()); });
    webBuilder.UseStartup<Startup>();
}).Build();

Il semble que la construction aurait dû être effectuée à l'intérieur de ConfigureWebHostDefaults pour que cela fonctionne, sinon la configuration sera ignorée, mais corrigez-moi si je me trompe.

Cette approche a bien fonctionné:

var host = new WebHostBuilder()
.ConfigureServices(servicesCollection =>
{
    var serviceProvider = servicesCollection.BuildServiceProvider();
    IConfiguration configuration = (IConfiguration)serviceProvider.GetService(typeof(IConfiguration));
    servicesCollection.AddSingleton<ISendEmailHandler>(new SendEmailHandler(configuration));
})
.UseStartup<Startup>()
.Build();

Cela montre également comment injecter une dépendance déjà prédéfinie dans .net core ( IConfiguration ) à partir de


-1

J'ai eu cette erreur parce que j'ai déclaré une variable (au-dessus de la méthode ConfigureServices) de type qui était mon contexte. J'avais:

CupcakeContext _ctx

Je ne sais pas à quoi je pensais. Je sais que c'est légal de faire cela si vous passez un paramètre à la méthode Configure.


-1

J'ai reçu l'erreur: "impossible de résoudre la dépendance xxxxxxxx pour toutes les versions de .net core". J'ai essayé tout ce qui est disponible sur Internet et je suis resté coincé pendant des jours. La seule solution que j'ai trouvée était d'ajouter le fichier nuget.config dans le projet, puis d'utiliser la restauration dotnet pour le faire fonctionner.

Contenu du fichier 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>
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.