ASP.NET Temel Bağımlılık Enjeksiyonu hatası: Etkinleştirmeye çalışırken tür için hizmet çözümlenemiyor


198

Bir .NET Core MVC uygulaması oluşturdum ve denetleyicime bir havuz enjekte etmek için Bağımlılık Enjeksiyonu ve Depo Kalıbı kullanıyorum. Ancak, bir hata alıyorum:

InvalidOperationException: 'WebApplication1.Controllers.BlogController' etkinleştirilmeye çalışılırken 'WebApplication1.Data.BloggerRepository' türü için hizmet çözülemedi.

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

Depo (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 (ilgili kod)

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

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

Neyi yanlış yaptığımdan emin değilim. Herhangi bir fikir?


Bu eski bir soru olduğunu biliyorum, ama ... db bağlamı bir hizmet içine atmamalısınız. Db bağlamı, kapsam çözücü tarafından otomatik olarak atılır. Bir hizmetin içine atarsanız, aynı istek / kapsam dahilinde bir sonraki hizmeti çağırırken imha edilebilir.
Silvermind

1
Hizmetin (eksik sınıf) ervservices.AddTransient <YourClassOrInterface> (); ´
Mauricio Gracia Gutierrez

Yanıtlar:


293

İstisna WebApplication1.Data.BloggerRepository, denetleyicinizdeki kurucu arabirim yerine somut sınıfı istediği için hizmeti çözemeyeceğini söylüyor . Sadece şunu değiştirin:

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

7
Tek bir karakteri gözden kaçırmanın ne kadar kolay olduğu şaşırtıcı ... teşekkürler!
jleach

Ne şampiyon, HttpContextAccessorsınıf kullanırken bunu aldı, ortaya çıktıIHttpContextAccessor
mtbennett

Bu yüzden 30 dakikadan fazla bekledi çünkü rahatsız. Mac üzerinde kötü VS size "donet beklenmedik biçimde çıkma" hatası verir. Doğru hatayı almak için terminalde çalıştırılmalı, sonra bu çözüme çarptım.
NoloMokgosi

57

Bağımlılık enjeksiyon kurulumunda bir denetleyicinin bağımlılığı olan bir havuz bağımlılığını eksik olduğu için bu sorunla karşılaştım:

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

Benim için çözüldü, bu benim sorunum
anisanwesley

Sorunlarımı çözdüm, çünkü hizmetlerimin doğru "ad alanında" olmadığını fark ettim.
user2982195

24

Benim durumumda yapıcı argümanları gerektiren bir nesne için bağımlılık enjeksiyonu yapmaya çalışıyordum. Bu durumda, Başlangıç ​​sırasında yapılandırma dosyasından sadece argümanlar sağladım, örneğin:

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

18

Farklı bir sorun yaşıyordum ve evet denetleyicim için parametrelenmiş kurucu zaten doğru arayüzle eklenmişti. Yaptığım şey basit bir şeydi. Ben sadece startup.cskayıt için bir çağrı yöntemi görebiliyordu benim dosya gidin .

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

Benim durumumda, bu Registeryöntem ayrı bir sınıftaydı Injector. Bu yüzden yeni tanıtılan arayüzlerimi buraya eklemek zorunda kaldım.

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

Görüyorsanız, bu işlevin parametresi this IServiceCollection

Bu yardımcı olur umarım.


Eklemeyi unuttuğum bu. Enjektör servisine referansını kaçırdım. .AddTransient <> (); Sağolun beyler!
Omzig

14

Sadece biri benim gibi aynı duruma sahipse, ben var olan veritabanı ile EntityFramework öğretici yapıyorum, ancak modeller klasörlerinde yeni veritabanı bağlamı oluşturulduğunda, biz sadece hizmetlerde değil, başlangıçta içeriği güncellemek gerekir. Kullanıcı kimlik doğrulamanız varsa AddDbContext ancak AddIdentity de

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

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


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

Başlangıç ConfigureServicesyöntemine "services.AddScoped" eklemeyi unuttunuz .


5

Bu sorunu oldukça aptalca bir hata yüzünden aldım. ASP.NET Core uygulamasında denetleyicileri otomatik olarak bulmak için hizmet yapılandırma yordamımı bağlamayı unuttum.

Bu yöntemi eklemek sorunu çözdü:

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

5

Çalışmak için ConfigureServices bu satırı eklemek zorunda kaldı.

services.AddSingleton<IOrderService, OrderService>();

3

İstisnasın altına giriyordum

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

DbContext Derived sınıf IBlogContextFactory örnekleri oluşturmak için Fabrika tescil etmek istedim ve bağımlılık Enjeksiyon ile birlikte aşağıdaki desen kullanabilirsiniz ve ayrıca birim sınama için alay kullanabilirsiniz, böylece Blog Bağlam örneğini örnek oluşturmak için Create yöntemi kullanın.

kullanmak istediğim desen

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

Ama yerine yeni BloggingContext () yerine aşağıdaki BlogController sınıfında olduğu gibi yapıcı üzerinden fabrika enjekte etmek istiyorum

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

işte servis kayıt kodum

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

ve benim modellerim ve fabrika sınıflarım

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

----- Bunu .net Core MVC projesinde düzeltmek için - Bağımlılık kaydında aşağıdaki değişiklikleri yaptım

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

Kısacası .net çekirdek geliştiricisi Unity ve .Net Framework durumunda fabrika işlevini enjekte etmekten sorumludur.


3

Bu sorun, veri erişim bileşenini kendisi için yazılmış arabirime kaydetmemenizdir. Aşağıdaki gibi kullanmayı deneyin

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

2

AutoFac kullanıyorsanız ve bu hatayı alıyorsanız, somut uygulamanın uyguladığı hizmeti belirtmek için bir "As" ifadesi eklemeniz gerekir.

Yani. yazmalısın:

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

onun yerine

containerBuilder.RegisterType<DataService>();


2

Bir hizmeti çözümlemek, sınıf koduna ulaşılmadan önce bile yapılır, bu nedenle bağımlılık enjeksiyonlarımızı kontrol etmemiz gerekir.

Benim durumumda ekledim

        services.AddScoped<IMeasurementService, MeasurementService>();

StartupExtensions.cs içinde


1

Services.AddSingleton () ekleyin ; projenizin Startup.cs dosyasının ConfigureServices yönteminde.

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

Daha fazla ayrıntı için lütfen bu URL'yi ziyaret edin: https://www.youtube.com/watch?v=aMjiiWtfj2M

Tüm yöntemler için (yani AddSingleton vs AddScoped vs AddTransient) Lütfen bu URL'yi ziyaret edin: https://www.youtube.com/watch?v=v6Nr7Zman_Y&list=PL6n9fhu94yhVkdrusLaQsfERmL_Jh4XmU&index=44 )


1

Ben de aynı sorunu vardı ve benim kod başlamadan önce enjeksiyon kullandığını öğrendim.

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

Bunun soru ile ilgisi olmadığını biliyorum, ancak bu sayfaya gönderildiğimden, başka birine faydalı olduğumu anladım.


0

Ben değiştirdim

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

İle

services.AddTransient<IMyLogger, MyLogger>();

Ve benim için çalıştı.


-1

Bağlamım olan bir değişkenin (ConfigureServices yönteminin üstünde) bildirildiğinden bu hatayı aldım. Sahiptim:

CupcakeContext _ctx

Ne düşündüğümden emin değilim. Configure yöntemine bir parametre aktarmanız durumunda bunu yapmanın yasal olduğunu biliyorum.


-1

Şu hatayı aldım: ".net core'un tüm sürümleri için xxxxxxxx bağımlılığını çözemiyorum". İnternette mevcut her şeyi denedim ve günlerce sıkışmış. Geldiğim tek çözüm, projeye nuget.config dosyası eklemek ve ardından çalışmasını sağlamak için dotnet geri yüklemesini kullanmaktı.

Nuget.config dosyasının içeriği:

<?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>
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.