ASP.NET Errore di dipendenza dipendenza core: Impossibile risolvere il servizio per il tipo durante il tentativo di attivazione


198

Ho creato un'applicazione .NET Core MVC e utilizzo l'iniezione delle dipendenze e il modello di repository per iniettare un repository nel mio controller. Tuttavia, visualizzo un errore:

InvalidOperationException: impossibile risolvere il servizio per il tipo "WebApplication1.Data.BloggerRepository" durante il tentativo di attivare "WebApplication1.Controllers.BlogController".

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

Repository (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 (codice pertinente)

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

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

Non sono sicuro di cosa sto facendo di sbagliato. Qualche idea?


So che questa è una vecchia domanda, ma ... Non dovresti disporre il contesto db all'interno di un servizio. Il contesto db viene automaticamente eliminato dal risolutore dell'ambito. Se lo si elimina all'interno di un servizio, potrebbe essere eliminato quando si chiama un servizio successivo all'interno della stessa richiesta / ambito.
Silvermind

1
Assicurati che il servizio (classe mancante) sia aggiunto usando ´services.AddTransient <YourClassOrInterface> (); ´
Mauricio Gracia Gutierrez

Risposte:


293

L'eccezione afferma che non è possibile risolvere il servizio WebApplication1.Data.BloggerRepositoryperché il costruttore sul controller richiede la classe concreta anziché l'interfaccia. Quindi basta cambiarlo:

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

7
Incredibile quanto sia facile trascurare un singolo personaggio ... grazie!
giovedì

Che campione, ricevuto questo durante l'utilizzo della HttpContextAccessorclasse, risulta che avevo bisogno diIHttpContextAccessor
mtbennett il

Sono così irritato perché ho resistito per più di 30 minuti su questo. Peggiore VS su Mac ti dà l'errore "donet smetti improvvisamente". Deve essere eseguito sul terminale per ottenere l'errore corretto, quindi ho incontrato questa soluzione.
NoloMokgosi,

57

Ho riscontrato questo problema perché nella configurazione dell'iniezione di dipendenza mancava una dipendenza di un repository che è una dipendenza di un controller:

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

Risolto per me, questo era il mio problema
anisanwesley,

Risolto il mio problema, perché avevo riconosciuto che i miei servizi non erano nello "spazio dei nomi" corretto.
user2982195

24

Nel mio caso stavo cercando di fare l'iniezione di dipendenza per un oggetto che richiedeva argomenti di costruzione. In questo caso, durante l'avvio ho appena fornito gli argomenti dal file di configurazione, ad esempio:

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

18

Avevo un problema diverso e sì, il costruttore con parametri per il mio controller era già stato aggiunto con l'interfaccia corretta. Quello che ho fatto è stato qualcosa di semplice. Vado solo al mio startup.csfile, dove ho potuto vedere una chiamata per registrare il metodo.

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

Nel mio caso, questo Registermetodo era in una classe separata Injector. Quindi ho dovuto aggiungere le mie interfacce appena introdotte lì.

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

Se vedi, il parametro per questa funzione è this IServiceCollection

Spero che questo ti aiuti.


Questo è quello che ho dimenticato di aggiungere. Ho perso il riferimento dell'iniettore al servizio. Necessario per .AddTransient <> (); Grazie ragazzi!
Omzig,

14

Solo se qualcuno ha la stessa situazione come me, sto facendo un tutorial di EntityFramework con un database esistente, ma quando il nuovo contesto del database viene creato nelle cartelle dei modelli, dobbiamo aggiornare il contesto all'avvio, ma non solo nei servizi. AddDbContext ma AddIdentity anche se si dispone dell'autenticazione degli utenti

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

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

7

È necessario aggiungere un nuovo servizio per DBcontextl'avvio

Predefinito

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

Aggiungi questo

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


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

Hai dimenticato di aggiungere "services.AddScoped" nel ConfigureServicesmetodo di avvio .


5

Ho avuto questo problema a causa di un errore piuttosto sciocco. Avevo dimenticato di agganciare la mia procedura di configurazione del servizio per rilevare automaticamente i controller nell'applicazione ASP.NET Core.

L'aggiunta di questo metodo lo ha risolto:

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

5

Ho dovuto aggiungere questa linea in ConfigureServices per funzionare.

services.AddSingleton<IOrderService, OrderService>();

3

Stavo diventando al di sotto dell'eccezione

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

Perché volevo che Register Factory creasse istanze di DbContext Classe derivata IBlogContextFactory e usassi il metodo Create per creare un'istanza di Blog Context in modo da poter usare il pattern sottostante insieme all'iniezione delle dipendenze e usare anche il derisione per i test unitari.

lo schema che volevo usare è

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

Ma invece del nuovo BloggingContext () voglio iniettare factory tramite il costruttore come nella classe BlogController sotto

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

ecco il mio codice di registrazione del servizio

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

e sotto sono i miei modelli e le mie classi di fabbrica

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

----- Per risolvere questo problema nel progetto .net Core MVC - Di seguito ho apportato modifiche alla registrazione delle dipendenze

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

In breve, lo sviluppatore core .net è responsabile dell'iniezione della funzione di fabbrica, che in caso di Unity e .Net Framework è stata curata.


3

Questo problema è dovuto al fatto che non hai registrato il componente di accesso ai dati con l'interfaccia scritta per esso. Prova a usare come segue

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

2

Se si utilizza AutoFac e si riceve questo errore, è necessario aggiungere un'istruzione "As" per specificare il servizio che l'implementazione concreta implementa.

Vale a dire. dovresti scrivere:

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

invece di

containerBuilder.RegisterType<DataService>();


2

La risoluzione di un servizio viene eseguita anche prima che venga raggiunto il codice di classe, quindi è necessario verificare le iniezioni di dipendenza.

Nel mio caso ho aggiunto

        services.AddScoped<IMeasurementService, MeasurementService>();

in StartupExtensions.cs


1

Aggiungi services.AddSingleton (); nel metodo ConfigureServices del file Startup.cs del progetto.

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

Per maggiori dettagli, visita questo URL: https://www.youtube.com/watch?v=aMjiiWtfj2M

per tutti i metodi (ad esempio AddSingleton vs AddScoped vs AddTransient) Si prega di visitare questo URL: https://www.youtube.com/watch?v=v6Nr7Zman_Y&list=PL6n9fhu94yhVkdrusLaQsfERmL_Jh4XmU&index=44 )


1

Ho avuto lo stesso problema e ho scoperto che il mio codice stava usando l'iniezione prima che fosse inizializzata.

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

So che non ha nulla a che fare con la domanda, ma da quando sono stato inviato a questa pagina, ho capito che potrebbe essere utile a qualcun altro.


0

Ho sostituito

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

Con

services.AddTransient<IMyLogger, MyLogger>();

E ha funzionato per me.


-1

Ho ricevuto questo errore perché ho dichiarato una variabile (sopra il metodo ConfigureServices) di tipo che era il mio contesto. Avevo:

CupcakeContext _ctx

Non sono sicuro di cosa stavo pensando. So che è legale farlo se si passa un parametro al metodo Configure.


-1

Ho ricevuto l'errore: "impossibile risolvere la dipendenza xxxxxxxx per tutte le versioni di .net core". Ho provato tutto ciò che era disponibile su Internet ed ero bloccato da giorni. L'unica soluzione che mi è venuta in mente è stata l'aggiunta del file nuget.config nel progetto e quindi l'utilizzo del ripristino dotnet per farlo funzionare.

Contenuto del file 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>
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.