Lỗi ASP.NET Dependency Injection: Không thể giải quyết dịch vụ cho loại trong khi cố gắng kích hoạt


192

Tôi đã tạo một ứng dụng .NET Core MVC và sử dụng Dependency Injection và Rep Storage Pattern để tiêm một kho lưu trữ vào bộ điều khiển của tôi. Tuy nhiên, tôi đang gặp lỗi:

UnlimitedOperationException: Không thể giải quyết dịch vụ cho loại 'WebApplication1.Data.BloggerRep repository' trong khi cố gắng kích hoạt 'WebApplication1.Controllers.BlogControll'.

Mô hình (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; }
    }
}

Kho lưu trữ (IBloggerRep repository.cs & BloggerRep repository.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 (mã có liên quan)

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

Trình điều khiển (BlogControll.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);
        }
    }
}

Tôi không chắc mình đang làm gì sai. Có ý kiến ​​gì không?


Tôi biết đây là một câu hỏi cũ, nhưng ... Bạn không nên loại bỏ bối cảnh db bên trong một dịch vụ. Bối cảnh db được tự động xử lý bởi bộ giải quyết phạm vi. Nếu bạn loại bỏ nó trong một dịch vụ, nó có thể bị loại bỏ khi gọi một dịch vụ tiếp theo trong cùng một yêu cầu / phạm vi.
Silvermind

1
Hãy chắc chắn rằng dịch vụ (thiếu lớp) được thêm vào sử dụng'services.AddTransient <YourClassOrInterface> (); '
Mauricio Gracia Gutierrez

Câu trả lời:


287

Ngoại lệ nói rằng nó không thể giải quyết dịch vụ WebApplication1.Data.BloggerRepositoryvì hàm tạo trên bộ điều khiển của bạn đang yêu cầu lớp cụ thể thay vì giao diện. Vì vậy, chỉ cần thay đổi rằng:

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

6
Thật ngạc nhiên khi dễ dàng bỏ qua một nhân vật duy nhất ... cảm ơn!
jleach

Thật là một nhà vô địch, nhận được điều này trong khi sử dụng HttpContextAccessorlớp học, hóa ra tôi cầnIHttpContextAccessor
mtbennett

Thật khó chịu vì tôi đã thắt lưng hơn 30 phút về việc này. VS trên Mac mang đến cho bạn lỗi "donet bỏ bất ngờ". Phải chạy trên thiết bị đầu cuối để nhận được lỗi chính xác, sau đó tôi đã va vào giải pháp này.
NoloMokgosi

54

Tôi gặp phải vấn đề này bởi vì trong thiết lập tiêm phụ thuộc, tôi đã thiếu một phụ thuộc của kho lưu trữ là phụ thuộc của bộ điều khiển:

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

Giải quyết cho tôi, đây là vấn đề của tôi
anisanwesley

Đã giải quyết vấn đề của tôi, vì tôi nhận ra các dịch vụ của mình không nằm trong "không gian tên" chính xác.
dùng2982195

24

Trong trường hợp của tôi, tôi đã cố gắng thực hiện phép nội xạ phụ thuộc cho một đối tượng cần các đối số của hàm tạo. Trong trường hợp này, trong khi khởi động, tôi chỉ cung cấp các đối số từ tệp cấu hình, ví dụ:

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

18

Tôi đã gặp một vấn đề khác và vâng, hàm tạo được tham số hóa cho bộ điều khiển của tôi đã được thêm vào với giao diện chính xác. Những gì tôi đã làm là một cái gì đó đơn giản. Tôi chỉ cần đi đến startup.cstập tin của tôi , nơi tôi có thể thấy một cuộc gọi để đăng ký phương thức.

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

Trong trường hợp của tôi, Registerphương pháp này là trong một lớp riêng biệt Injector. Vì vậy, tôi đã phải thêm Giao diện mới được giới thiệu của mình ở đó.

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

Nếu bạn thấy, tham số cho chức năng này là this IServiceCollection

Hi vọng điêu nay co ich.


Đây là một trong những tôi quên thêm. Tôi đã bỏ lỡ tham chiếu In phun cho dịch vụ. Cần thiết .AddTransient <> (); Cảm ơn các bạn!
Omzig

14

Chỉ khi bất kỳ ai có cùng hoàn cảnh như tôi, tôi đang thực hiện một hướng dẫn về EntityFramework với cơ sở dữ liệu hiện có, nhưng khi bối cảnh cơ sở dữ liệu mới được tạo trên các thư mục mô hình, chúng tôi cần cập nhật ngữ cảnh khi khởi động, nhưng không chỉ trong các dịch vụ. AddDbContext nhưng AddIdentity cũng vậy nếu bạn có xác thực người dùng

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

Bạn đã quên thêm "services.AddScoped" trong ConfigureServicesphương thức khởi động .


5

Tôi gặp vấn đề này vì một sai lầm khá ngớ ngẩn. Tôi đã quên móc thủ tục cấu hình dịch vụ của mình để tự động phát hiện các bộ điều khiển trong ứng dụng ASP.NET Core.

Thêm phương pháp này đã giải quyết nó:

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

5

Tôi đã phải thêm dòng này trong ConfigureService để hoạt động.

services.AddSingleton<IOrderService, OrderService>();

3

Vấn đề này là do bạn đã không đăng ký thành phần truy cập dữ liệu với giao diện được viết cho nó. Hãy thử sử dụng như sau

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

2

Nếu bạn đang sử dụng AutoFac và gặp lỗi này, bạn nên thêm câu lệnh "As" để chỉ định dịch vụ triển khai cụ thể.

I E. bạn nên viết:

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

thay vì

containerBuilder.RegisterType<DataService>();

2

Tôi đã nhận được dưới đây ngoại lệ

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

Bởi vì tôi muốn đăng ký Factory để tạo các thể hiện của lớp DlogContext IBlogContextFactory và sử dụng phương thức Tạo để khởi tạo thể hiện của Ngữ cảnh Blog để tôi có thể sử dụng mẫu bên dưới cùng với Tiêm phụ thuộc và cũng có thể sử dụng mô phỏng để kiểm tra đơn vị.

mẫu tôi muốn sử dụng là

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

Nhưng thay vì BloggingContext () mới, tôi muốn Tiêm nhà máy thông qua hàm tạo như bên dưới lớp BlogControll

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

đây là mã đăng ký dịch vụ của tôi

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

và dưới đây là các mô hình và các lớp học của tôi

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

----- Để khắc phục điều này trong dự án .net Core MVC - Tôi đã thực hiện các thay đổi dưới đây về đăng ký phụ thuộc

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

Nói tóm lại, nhà phát triển lõi .net chịu trách nhiệm tiêm chức năng của nhà máy, trong trường hợp Unity và .Net Framework đã được xử lý.


2

ohh, cảm ơn @kimbaudi, tôi đã theo dõi tuts này

https://dotnettutorials.net/lesson/generic-reposeective-potype-csharp-mvc/

và nhận được lỗi tương tự như của bạn. Nhưng sau khi đọc mã của bạn, tôi phát hiện ra giải pháp của mình đã được thêm vào

services.AddScoped (IGenericRep repository, GenericRep repository);

vào phương thức ConfigureService trong tệp StartUp.cs =))


1

Thêm dịch vụ.AddSingleton (); trong phương thức ConfigureService của tệp Startup.cs của dự án của bạn.

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

Để biết thêm chi tiết, vui lòng truy cập URL này: https://www.youtube.com/watch?v=aMjiiWtfj2M

cho tất cả các phương pháp (ví dụ AddSingleton vs AddScoped vs AddTransient) Vui lòng truy cập URL này: https://www.youtube.com/watch?v=v6Nr7Zman_Y&list=PL6n9fhu94yhVkdrusLaQsfERmL_Jh4XmU&index=44 )


1

Tôi có cùng một vấn đề và phát hiện ra rằng mã của tôi đang sử dụng phép tiêm trước khi nó được khởi tạo.

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

Tôi biết nó không liên quan gì đến câu hỏi, nhưng vì tôi đã được gửi đến trang này, tôi nhận ra rằng nó có ích với người khác.


1

Việc giải quyết một dịch vụ được thực hiện ngay cả trước khi đạt được mã lớp, vì vậy chúng tôi cần kiểm tra việc tiêm phụ thuộc.

Trong trường hợp của tôi, tôi đã thêm

        services.AddScoped<IMeasurementService, MeasurementService>();

trong StartupExtensions.cs


0

tôi đã thay thế

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

Với

services.AddTransient<IMyLogger, MyLogger>();

Và nó đã làm việc cho tôi.


-1

Tôi đã gặp lỗi này vì tôi đã khai báo một biến (phía trên phương thức ConfigureService) thuộc loại đó là ngữ cảnh của tôi. Tôi đã có:

CupcakeContext _ctx

Không chắc tôi đang nghĩ gì. Tôi biết đó là hợp pháp để làm điều này nếu bạn chuyển một tham số cho phương thức Cấu hình.


-1

Tôi đã nhận được lỗi: "không thể giải quyết phụ thuộc xxxxxxxx cho tất cả các phiên bản lõi .net". Tôi đã thử mọi thứ có sẵn trên internet và bị mắc kẹt trong nhiều ngày. Giải pháp duy nhất tôi nghĩ ra là thêm tệp nuget.config trong dự án và sau đó sử dụng khôi phục dotnet để làm cho nó hoạt động.

Nội dung của tệp 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>
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.