wake-up-neo.net

ASP.NET Core Dependency Injection Fehler: Fehler beim Auflösen des Dienstes für Typ während des Aktivierungsversuchs

Ich habe eine .NET Core MVC-Anwendung erstellt und mit Dependency Injection und Repository Pattern ein Repository in meinen Controller eingefügt. Ich erhalte jedoch eine Fehlermeldung:

InvalidOperationException: Der Dienst konnte für den Typ 'WebApplication1.Data.BloggerRepository' nicht aufgelöst werden, während versucht wurde, '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 und 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 nicht sicher, was ich falsch mache. Irgendwelche Ideen?

71
kimbaudi

Die Ausnahme besagt, dass der Dienst für WebApplication1.Data.BloggerRepository nicht aufgelöst werden kann, da der Konstruktor auf Ihrem Controller die konkrete Klasse anstelle der Schnittstelle anfordert. Also einfach das ändern:

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

In meinem Fall habe ich versucht, Abhängigkeitsinjektion für ein Objekt durchzuführen, das Konstruktorargumente erfordert. In diesem Fall habe ich während des Startvorgangs 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));
13
riqitang

Nur wenn jemand die gleiche Situation wie ich hat, mache ich ein Tutorial von EntityFramework mit der vorhandenen Datenbank. Wenn jedoch der neue Datenbankkontext in den Modellordnern erstellt wird, müssen wir den Kontext beim Start aktualisieren, nicht nur in den 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();
10
Adrian

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

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

In meinem Fall befand sich diese Register-Methode in einer separaten Klasse Injector. Also musste ich meine neu eingeführten Interfaces dort 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.

4
Sibeesh Venu

Ich bin auf dieses Problem gestoßen, weil mir im Abhängigkeitsinjektionssetup eine Abhängigkeit von einem Repository fehlte, das eine Abhängigkeit von einem Controller ist:

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

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

Das Hinzufügen dieser Methode löste es:

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

ohh, danke @ kimbaudi, ich bin diesen Tuts gefolgt

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

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

services.AddScoped (IGenericRepository, GenericRepository);

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

2
Son

Sie müssen im Startup einen neuen Dienst für DBcontext hinzufügen 

Default

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

Füge das hinzu

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

Ich musste diese Zeile in den ConfigureServices hinzufügen, um funktionieren zu können.

services.AddSingleton<IOrderService, OrderService>();
2
Mike
Public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<IEventRepository, EventRepository>();           
}

Sie haben vergessen, Addscope in der Configureservices-Startmethode hinzuzufügen.

1
Prakash CS

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

Ie. du solltest schreiben:

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

anstatt

containerBuilder.RegisterType<DataService>();
1
thebfactor

Dieses Problem ist darauf zurückzuführen, dass Sie die Datenzugriffskomponente nicht mit der dafür geschriebenen Schnittstelle registriert haben. Versuchen Sie es wie folgt

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

Ich habe services.Add(new ServiceDescriptor(typeof(IMyLogger), typeof(MyLogger))) durch services.AddTransient<IMyLogger, MyLogger>() ersetzt

Und es hat bei mir funktioniert.

0
satish madarapu

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 wird, um Instanzen der DbContext-abgeleiteten Klasse IBlogContextFactory zu erstellen und die Create-Methode zu verwenden, um die Instanz von Blog Context zu instanziieren, so dass ich das unten stehende Muster zusammen mit der Abhängigkeitsinjektion verwenden und auch Mocking für Komponententests 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();
            }
        }

Aber anstelle von neuem BloggingContext () möchte ich die Factory über den Konstruktor wie in der folgenden BlogController-Klasse einfügen

    [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 in .net Core MVC-Projekt zu beheben - Ich habe unten Änderungen an der Abhängigkeitsregistrierung vorgenommen

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

Kurzum .net Core-Entwickler ist dafür verantwortlich, Factory-Funktionen zu injizieren, die im Falle von Unity und .Net Framework erledigt wurden.

0
RAJ

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

CupcakeContext _ctx

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

0
athomas