ASP.NET Core Dependency Injection-Fehler: Dienst kann beim Aktivieren nicht nach Typ aufgelöst werden

192

Ich habe eine .NET Core MVC-Anwendung erstellt und mithilfe von Abhängigkeitsinjektion und Repository-Muster ein Repository in meinen Controller eingefügt. Ich erhalte jedoch eine Fehlermeldung:

InvalidOperationException: Dienst für Typ 'WebApplication1.Data.BloggerRepository' kann nicht aufgelöst werden, während versucht wird, 'WebApplication1.Controllers.BlogController' zu aktivieren.

Modell (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 (relevanter Code)

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

Ich bin mir nicht sicher, was ich falsch mache. Irgendwelche Ideen?

Kimbaudi
quelle
Ich weiß, dass dies eine alte Frage ist, aber ... Sie sollten den Datenbankkontext nicht innerhalb eines Dienstes entsorgen. Der Datenbankkontext wird vom Scope Resolver automatisch entsorgt. Wenn Sie es innerhalb eines Dienstes entsorgen, wird es möglicherweise entsorgt, wenn Sie einen nächsten Dienst innerhalb derselben Anforderung / desselben Bereichs aufrufen.
Silvermind
1
Stellen Sie sicher, dass der Dienst (fehlende Klasse) mit ´services.AddTransient <YourClassOrInterface> (); ´
Mauricio Gracia Gutierrez

Antworten:

287

Die Ausnahme besagt, dass der Dienst nicht aufgelöst werden kann, WebApplication1.Data.BloggerRepositoryda der Konstruktor auf Ihrem Controller die konkrete Klasse anstelle der Schnittstelle anfordert. Also ändere das einfach:

public BlogController(IBloggerRepository repository)
//                    ^
//                    Add this!
{
    _repository = repository;
}
DavidG
quelle
6
Erstaunlich, wie einfach es ist, einen einzelnen Charakter zu übersehen ... danke!
Jleach
Was für ein Champion, der dies während des HttpContextAccessorUnterrichts erhalten hat, stellte sich heraus, dass ich dasIHttpContextAccessor
mtbennett
So irritiert, weil ich mehr als 30 Minuten darauf gewartet habe. Worst VS auf dem Mac gibt Ihnen den Fehler "Nicht unerwartet beenden". Muss auf dem Terminal laufen, um den richtigen Fehler zu erhalten, dann bin ich auf diese Lösung gestoßen.
NoloMokgosi
54

Ich bin auf dieses Problem gestoßen, weil mir beim Setup der Abhängigkeitsinjektion eine Abhängigkeit eines Repositorys fehlte, das eine Abhängigkeit eines Controllers ist:

services.AddScoped<IDependencyOne, DependencyOne>();    <-- I was missing this line!
services.AddScoped<IDependencyTwoThatIsDependentOnDependencyOne, DependencyTwoThatIsDependentOnDependencyOne>();
hsop
quelle
Für mich gelöst, war dies mein Problem
Anisanwesley
Mein Problem wurde behoben, da ich erkannte, dass sich meine Dienste nicht im richtigen "Namespace" befanden.
user2982195
24

In meinem Fall habe ich versucht, eine Abhängigkeitsinjektion für ein Objekt durchzuführen, für das Konstruktorargumente erforderlich waren. In diesem Fall habe ich beim Start nur die Argumente aus der Konfigurationsdatei angegeben, zum Beispiel:

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

Ich hatte ein anderes Problem und ja, der parametrisierte Konstruktor für meinen Controller wurde bereits mit der richtigen Schnittstelle hinzugefügt. Was ich tat, war etwas Unkompliziertes. Ich gehe einfach zu meiner startup.csDatei, wo ich einen Aufruf zur Registrierung der Methode sehen konnte.

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

In meinem Fall war diese RegisterMethode in einer separaten Klasse Injector. Also musste ich dort meine neu eingeführten Interfaces hinzufügen.

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

Wenn Sie sehen, ist der Parameter für diese Funktion this IServiceCollection

Hoffe das hilft.

Sibeesh Venu
quelle
Dies ist die, die ich vergessen habe hinzuzufügen. Ich habe den Injector-Verweis auf den Service verpasst. Wird benötigt, um .AddTransient <> (); Danke Jungs!
Omzig
14

Nur wenn jemand die gleiche Situation wie ich hat, mache ich ein Tutorial von EntityFramework mit vorhandener Datenbank, aber wenn der neue Datenbankkontext in den Modellordnern erstellt wird, müssen wir den Kontext beim Start aktualisieren, aber nicht nur in Diensten. AddDbContext, aber auch AddIdentity, wenn Sie über eine Benutzerauthentifizierung verfügen

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

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

Sie müssen DBcontextbeim Start einen neuen Dienst hinzufügen

Standard

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

Füge das hinzu

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

Sie haben vergessen, "services.AddScoped" in der Startmethode hinzuzufügen ConfigureServices.

Prakash CS
quelle
5

Ich habe dieses Problem wegen eines ziemlich dummen Fehlers bekommen. Ich hatte vergessen, meine Dienstkonfigurationsprozedur zu verknüpfen, um Controller in der ASP.NET Core-Anwendung automatisch zu erkennen.

Das Hinzufügen dieser Methode löste es:

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

Ich musste diese Zeile in die ConfigureServices einfügen, um arbeiten zu können.

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

Dieses Problem liegt daran, dass Sie die Datenzugriffskomponente nicht mit der dafür geschriebenen Schnittstelle registriert haben. Versuchen Sie es wie folgt

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

Wenn Sie AutoFac verwenden und diesen Fehler erhalten, sollten Sie eine "As" -Anweisung hinzufügen, um den Dienst anzugeben, den die konkrete Implementierung implementiert.

Dh. du solltest schreiben:

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

anstatt

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

Ich war unter der Ausnahme

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

Weil ich wollte, dass Factory registriert Instanzen der von DbContext abgeleiteten Klasse IBlogContextFactory erstellt und die Methode Create verwendet, um die Instanz von Blog Context zu instanziieren, sodass ich das folgende Muster zusammen mit der Abhängigkeitsinjektion verwenden und auch das Verspotten für Unit-Tests verwenden kann.

Das Muster, das ich verwenden wollte, ist

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

Anstelle von neuem BloggingContext () möchte ich die Factory über den Konstruktor wie in der folgenden BlogController-Klasse injizieren

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

Hier ist mein Service-Registrierungscode

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

und unten sind meine Modelle und Fabrikklassen

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

----- Um dies im .net Core MVC-Projekt zu beheben, habe ich unten Änderungen an der Abhängigkeitsregistrierung vorgenommen

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

Kurz gesagt, in .net ist der Kernentwickler dafür verantwortlich, die Factory-Funktion einzufügen, für die im Fall von Unity und .Net Framework gesorgt wurde.

Rajnikant
quelle
2

ohh, danke @kimbaudi, ich bin diesen Tuts gefolgt

https://dotnettutorials.net/lesson/generic-repository-pattern-csharp-mvc/

und habe den gleichen Fehler wie Ihr. Aber nachdem ich Ihren Code gelesen hatte, fand ich heraus, dass meine Lösung hinzugefügt wurde

services.AddScoped (IGenericRepository, GenericRepository);

in die ConfigureServices- Methode in der Datei StartUp.cs =))

Sohn
quelle
1

Services hinzufügen.AddSingleton (); in Ihrer ConfigureServices-Methode der Datei Startup.cs Ihres Projekts.

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

Weitere Informationen finden Sie unter folgender URL: https://www.youtube.com/watch?v=aMjiiWtfj2M

für alle Methoden (dh AddSingleton vs AddScoped vs AddTransient) Bitte besuchen Sie diese URL: https://www.youtube.com/watch?v=v6Nr7Zman_Y&list=PL6n9fhu94yhVkdrusLaQsfERmL_Jh4XmU&index=44 )

Bhanu Pratap
quelle
1

Ich hatte das gleiche Problem und stellte fest, dass mein Code die Injektion verwendete, bevor sie initialisiert wurde.

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

Ich weiß, dass es nichts mit der Frage zu tun hat, aber da ich auf diese Seite geschickt wurde, finde ich heraus, dass es für jemand anderen nützlich ist.

Sauleil
quelle
1

Das Auflösen eines Dienstes erfolgt bereits vor Erreichen des Klassencodes. Daher müssen wir unsere Abhängigkeitsinjektionen überprüfen.

In meinem Fall habe ich hinzugefügt

        services.AddScoped<IMeasurementService, MeasurementService>();

in StartupExtensions.cs

Onat Korucu
quelle
0

ich ersetzte

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

Mit

services.AddTransient<IMyLogger, MyLogger>();

Und es hat bei mir funktioniert.

satish madarapu
quelle
-1

Ich habe diesen Fehler erhalten, weil ich eine Variable (über der ConfigureServices-Methode) vom Typ deklariert habe, die mein Kontext war. Ich hatte:

CupcakeContext _ctx

Ich bin mir nicht sicher, was ich dachte. Ich weiß, dass dies legal ist, wenn Sie einen Parameter an die Configure-Methode übergeben.

Athomas
quelle
-1

Ich habe die Fehlermeldung erhalten: "Die Abhängigkeit xxxxxxxx kann nicht für alle Versionen des .net-Kerns aufgelöst werden." Ich habe alles ausprobiert, was im Internet verfügbar ist, und war tagelang festgefahren. Die einzige Lösung, die ich gefunden habe, war das Hinzufügen der Datei nuget.config im Projekt und die anschließende Verwendung der Dotnet-Wiederherstellung.

Inhalt der Datei 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
quelle