ASP.NET Core Dependency Injection error: Tidak dapat menyelesaikan layanan untuk tipe saat mencoba untuk mengaktifkan

198

Saya membuat aplikasi .NET Core MVC dan menggunakan Dependency Injection dan Repository Pattern untuk menyuntikkan repositori ke controller saya. Namun, saya mendapatkan kesalahan:

InvalidOperationException: Tidak dapat menyelesaikan layanan untuk tipe 'WebApplication1.Data.BloggerRepository' saat mencoba mengaktifkan 'WebApplication1.Controllers.BlogController'.

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

Repositori (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 (kode yang relevan)

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

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

Saya tidak yakin apa yang saya lakukan salah. Ada ide?

kimbaudi
sumber
Saya tahu ini adalah pertanyaan lama, tapi ... Anda tidak boleh membuang konteks db di dalam layanan. Konteks db secara otomatis dibuang oleh resolver lingkup. Jika Anda membuangnya di dalam layanan, itu mungkin dibuang saat memanggil layanan berikutnya dalam permintaan / ruang lingkup yang sama.
Silvermind
1
Pastikan layanan (kelas yang hilang) ditambahkan menggunakan ´services.AddTransient <YourClassOrInterface> (); ´
Mauricio Gracia Gutierrez

Jawaban:

293

Pengecualian mengatakan itu tidak dapat menyelesaikan layanan WebApplication1.Data.BloggerRepositorykarena konstruktor pada pengontrol Anda meminta kelas konkret bukan antarmuka. Jadi ubah saja:

public BlogController(IBloggerRepository repository)
//                    ^
//                    Add this!
{
    _repository = repository;
}
DavidG
sumber
7
Luar biasa betapa mudahnya untuk mengabaikan satu karakter ... terima kasih!
jleach
Apa yang menjadi juara, menerima ini saat menggunakan HttpContextAccessorkelas, ternyata saya membutuhkanIHttpContextAccessor
mtbennett
Sangat kesal karena saya menunggu lebih dari 30 menit untuk kesalahan ini. VS VS di Mac memberi Anda kesalahan "donet berhenti tiba-tiba". Harus berjalan di terminal untuk mendapatkan kesalahan yang benar, maka saya menabrak solusi ini.
NoloMokgosi
57

Saya mengalami masalah ini karena dalam pengaturan injeksi dependensi saya kehilangan dependensi dari repositori yang merupakan ketergantungan dari controller:

services.AddScoped<IDependencyOne, DependencyOne>();    <-- I was missing this line!
services.AddScoped<IDependencyTwoThatIsDependentOnDependencyOne, DependencyTwoThatIsDependentOnDependencyOne>();
hsop
sumber
Dipecahkan untuk saya, ini adalah masalah saya
anisanwesley
Memecahkan masalah saya, karena saya tahu layanan saya tidak berada di "namespace" yang benar.
user2982195
24

Dalam kasus saya, saya mencoba melakukan injeksi ketergantungan untuk objek yang memerlukan argumen konstruktor. Dalam hal ini, selama Startup saya hanya memberikan argumen dari file konfigurasi, misalnya:

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

Saya mengalami masalah yang berbeda, dan yeah konstruktor parameter untuk controller saya sudah ditambahkan dengan antarmuka yang benar. Apa yang saya lakukan adalah sesuatu yang langsung. Saya hanya pergi ke startup.csfile saya , di mana saya bisa melihat metode panggilan untuk mendaftar.

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

Dalam kasus saya, Registermetode ini berada di kelas yang terpisah Injector. Jadi saya harus menambahkan Antarmuka baru saya yang diperkenalkan di sana.

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

Jika Anda melihat, parameter untuk fungsi ini adalah this IServiceCollection

Semoga ini membantu.

Sibeesh Venu
sumber
Ini yang saya lupa tambahkan. Saya melewatkan referensi Injector ke layanan. Diperlukan untuk .AddTransient <> (); Terima kasih kawan!
Omzig
14

Hanya jika ada orang yang memiliki situasi yang sama seperti saya, saya melakukan tutorial EntityFramework dengan database yang ada, tetapi ketika konteks database baru dibuat pada folder model, kita perlu memperbarui konteks di startup, tetapi tidak hanya dalam layanan. AddDbContext tetapi AddIdentity juga jika Anda memiliki otentikasi pengguna

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

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

Anda perlu menambahkan layanan baru DBcontextdi startup

Default

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

Tambahkan ini

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

Anda lupa menambahkan "services.AddScoped" dalam ConfigureServicesmetode startup .

Prakash CS
sumber
5

Saya mendapatkan masalah ini karena kesalahan yang agak konyol. Saya lupa mengaitkan prosedur konfigurasi layanan untuk menemukan pengontrol secara otomatis di aplikasi Core ASP.NET.

Menambahkan metode ini menyelesaikannya:

// Add framework services.
            services.AddMvc()
                    .AddControllersAsServices();      // <---- Super important
ulat sutra
sumber
5

Saya harus menambahkan baris ini di ConfigureServices agar dapat berfungsi.

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

Saya mendapatkan di bawah pengecualian

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

Karena saya ingin mendaftar Pabrik untuk membuat turunan DbContext Berasal dari kelas IBlogContextFactory dan menggunakan metode Buat untuk instantiate instance dari Blog Context sehingga saya dapat menggunakan pola di bawah ini bersama dengan dependensi Injeksi dan juga dapat menggunakan mengejek untuk pengujian unit.

pola yang ingin saya gunakan adalah

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

Tapi Alih-alih BloggingContext baru () Saya ingin Menyuntikkan pabrik melalui konstruktor seperti di bawah kelas 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;
    }
}

di sini adalah kode registrasi layanan saya

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

dan di bawah ini adalah model dan kelas pabrik saya

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

----- Untuk Memperbaiki ini dalam proyek .net Core MVC - Saya melakukan perubahan di bawah ini pada pendaftaran ketergantungan

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

Singkatnya. Pengembang inti internet bertanggung jawab untuk menyuntikkan fungsi pabrik, yang dalam kasus Unity dan .Net Framework diurus.

Rajnikant
sumber
3

Masalah ini karena Anda tidak mendaftarkan komponen akses data dengan antarmuka yang ditulis untuk itu. Coba gunakan sebagai berikut

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

Jika Anda menggunakan AutoFac dan mendapatkan kesalahan ini, Anda harus menambahkan pernyataan "As" untuk menentukan layanan yang diterapkan oleh implementasi konkret.

Yaitu. Anda harus menulis:

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

dari pada

containerBuilder.RegisterType<DataService>();
faktor
sumber
2

Menyelesaikan layanan dilakukan bahkan sebelum kode kelas tercapai, jadi kita perlu memeriksa injeksi ketergantungan kita.

Dalam kasus saya, saya menambahkan

        services.AddScoped<IMeasurementService, MeasurementService>();

di StartupExtensions.cs

Onat Korucu
sumber
1

Tambahkan layanan. Tambahkan Singleton (); dalam metode ConfigureServices Anda dari file Startup.cs proyek Anda.

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

Untuk perincian lebih lanjut, silakan kunjungi URL ini: https://www.youtube.com/watch?v=aMjiiWtfj2M

untuk Semua metode (yaitu AddSingleton vs AddScoped vs AddTransient) Silakan kunjungi URL ini: https://www.youtube.com/watch?v=v6Nr7Zman_Y&list=PL6n9fhu94yhVkdrusLaQsfERmL_Jh4XmU&index=44 )

Bhanu Pratap
sumber
1

Saya memiliki masalah yang sama dan menemukan bahwa kode saya menggunakan injeksi sebelum diinisialisasi.

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

Saya tahu itu tidak ada hubungannya dengan pertanyaan itu, tetapi karena saya dikirim ke halaman ini, saya pikir itu berguna bagi orang lain.

Sauleil
sumber
0

Saya diganti

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

Dengan

services.AddTransient<IMyLogger, MyLogger>();

Dan itu berhasil untuk saya.

satish madarapu
sumber
-1

Saya mendapatkan kesalahan ini karena saya mendeklarasikan variabel (di atas metode ConfigureServices) dari tipe yang merupakan konteks saya. Saya punya:

CupcakeContext _ctx

Tidak yakin apa yang saya pikirkan. Saya tahu adalah sah untuk melakukan ini jika Anda mengirimkan parameter ke metode Konfigurasi.

athoma
sumber
-1

Saya menerima kesalahan: "tidak dapat menyelesaikan dependensi xxxxxxxx untuk semua versi .net core". Saya mencoba semua yang tersedia di internet dan macet selama berhari-hari. Satu-satunya solusi yang saya buat adalah menambahkan file nuget.config di proyek dan kemudian menggunakan pengembalian dotnet untuk membuatnya bekerja.

Konten 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>
Shantanu Gautam
sumber