Ошибка внедрения ядра ASP.NET: невозможно разрешить службу для типа при попытке активации

198

Я создал приложение .NET Core MVC и использую Dependency Injection и Repository Pattern, чтобы внедрить репозиторий в мой контроллер. Однако я получаю сообщение об ошибке:

InvalidOperationException: невозможно разрешить службу для типа «WebApplication1.Data.BloggerRepository» при попытке активировать «WebApplication1.Controllers.BlogController».

Модель (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; }
    }
}

Репозиторий (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 (соответствующий код)

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

Контроллер (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);
        }
    }
}

Я не уверен, что я делаю неправильно. Любые идеи?

kimbaudi
источник
Я знаю, что это старый вопрос, но ... Вы не должны располагать контекстом db внутри службы. Контекст БД автоматически удаляется решателем областей. Если вы располагаете его внутри службы, он может быть удален при вызове следующей службы в том же запросе / области.
Silvermind
1
Убедитесь, что служба (отсутствующий класс) добавлена ​​с помощью ´services.AddTransient <YourClassOrInterface> (); ´
Маурисио Грасия Гутьеррес

Ответы:

293

Исключение говорит, что не может разрешить службу, WebApplication1.Data.BloggerRepositoryпотому что конструктор на вашем контроллере запрашивает конкретный класс вместо интерфейса. Так что просто измени это:

public BlogController(IBloggerRepository repository)
//                    ^
//                    Add this!
{
    _repository = repository;
}
DavidG
источник
7
Удивительно, как легко пропустить одного персонажа ... спасибо!
jleach
Какой чемпион, получивший это при использовании HttpContextAccessorкласса, оказывается, что мне нужноIHttpContextAccessor
mtbennett
Так раздражен, потому что я потратил на это более 30 минут. Наихудший VS на Mac выдает ошибку «не выйдет неожиданно». Должен работать на терминале, чтобы получить правильную ошибку, затем я наткнулся на это решение.
НолоМокгоси
57

Я столкнулся с этой проблемой, потому что в настройке внедрения зависимостей мне не хватало зависимости репозитория, которая является зависимостью контроллера:

services.AddScoped<IDependencyOne, DependencyOne>();    <-- I was missing this line!
services.AddScoped<IDependencyTwoThatIsDependentOnDependencyOne, DependencyTwoThatIsDependentOnDependencyOne>();
hsop
источник
Решил для меня, это была моя проблема
Anisanwesley
Решил мою проблему, потому что я обнаружил, что мои сервисы не были в правильном «пространстве имен».
user2982195
24

В моем случае я пытался сделать внедрение зависимости для объекта, который требовал аргументов конструктора. В этом случае во время запуска я просто предоставил аргументы из файла конфигурации, например:

var config = Configuration.GetSection("subservice").Get<SubServiceConfig>();
services.AddScoped<ISubService>(provider => new SubService(config.value1, config.value2));
riqitang
источник
18

У меня была другая проблема, и да, параметризованный конструктор для моего контроллера уже был добавлен с правильным интерфейсом. То, что я сделал, было чем-то простым. Я просто захожу в свой startup.csфайл, где я вижу вызов метода регистрации.

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

В моем случае этот Registerметод был в отдельном классе Injector. Поэтому я должен был добавить свои недавно представленные интерфейсы.

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

Если вы видите, параметр этой функции this IServiceCollection

Надеюсь это поможет.

Сибееш Вену
источник
Это тот, который я забыл добавить. Я пропустил ссылку Инжектора на сервис. Необходимо для .AddTransient <> (); Спасибо вам, ребята!
Омциг
14

Только если у кого-то такая же ситуация, как у меня, я делаю учебник EntityFramework с существующей базой данных, но когда новый контекст базы данных создается в папках моделей, нам нужно обновлять контекст при запуске, а не только в службах. AddDbContext, но AddIdentity тоже, если у вас есть аутентификация пользователей

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

services.AddIdentity<ApplicationUser, IdentityRole>()
                .AddEntityFrameworkStores<NewDBContext>()
                .AddDefaultTokenProviders();
Адриан
источник
7

Вам нужно добавить новый сервис для DBcontextпри запуске

По умолчанию

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

Добавь это

services.AddDbContext<NewDBContext>(options =>
                options.UseSqlServer(
                    Configuration.GetConnectionString("NewConnection")));
Warit Taveekarn
источник
7
Public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<IEventRepository, EventRepository>();           
}

Вы забыли добавить «services.AddScoped» в ConfigureServicesметоде запуска .

Prakash CS
источник
5

Я получил эту проблему из-за довольно глупой ошибки. Я забыл перехватить процедуру настройки службы для автоматического обнаружения контроллеров в приложении ASP.NET Core.

Добавление этого метода решило это:

// Add framework services.
            services.AddMvc()
                    .AddControllersAsServices();      // <---- Super important
silkfire
источник
5

Мне пришлось добавить эту строку в ConfigureServices, чтобы работать.

services.AddSingleton<IOrderService, OrderService>();
Майк
источник
3

Я получал ниже исключения

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

Потому что я хотел зарегистрировать Factory для создания экземпляров класса DbContext Derived IBlogContextFactory и использовать метод Create для создания экземпляра экземпляра Blog Context, чтобы я мог использовать приведенный ниже шаблон вместе с инъекцией зависимостей, а также использовать mocking для модульного тестирования.

шаблон, который я хотел использовать,

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

Но вместо нового BloggingContext () я хочу внедрить фабрику через конструктор, как показано ниже в классе 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;
    }
}

вот мой регистрационный код сервиса

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

и ниже мои модели и фабричные классы

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

----- Исправить это в .net Core MVC проекте - я сделал ниже изменения по регистрации зависимостей

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

Короче говоря, разработчик ядра .net отвечает за внедрение фабричной функции, о которой в случае Unity и .Net Framework заботились.

Rajnikant
источник
3

Это связано с тем, что вы не зарегистрировали компонент доступа к данным с помощью интерфейса, написанного для него. Попробуйте использовать следующим образом

services.AddTransient<IMyDataProvider, MyDataAccess>();`
Шайлеш Тивари
источник
2

Если вы используете AutoFac и получаете эту ошибку, вы должны добавить оператор «As», чтобы указать сервис, который реализует конкретная реализация.

То есть. Вы должны написать:

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

вместо того

containerBuilder.RegisterType<DataService>();
thebfactor
источник
2

ооо Спасибо @kimbaudi, я следовал этим правилам

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

и получил ту же ошибку, что и ваш. Но после прочтения вашего кода я узнал, что мое решение добавляет

services.AddScoped (IGenericRepository, GenericRepository);

в метод ConfigureServices в файле StartUp.cs =))

Сын
источник
2

Разрешение службы выполняется еще до того, как будет достигнут код класса, поэтому нам нужно проверить наши внедрения зависимостей.

В моем случае я добавил

        services.AddScoped<IMeasurementService, MeasurementService>();

в StartupExtensions.cs

Онат Коруку
источник
1

Добавить services.AddSingleton (); в вашем методе ConfigureServices файла Startup.cs вашего проекта.

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

Для получения дополнительной информации, пожалуйста, посетите этот URL: https://www.youtube.com/watch?v=aMjiiWtfj2M

для всех методов (т. е. AddSingleton против AddScoped против AddTransient) Пожалуйста, посетите этот URL: https://www.youtube.com/watch?v=v6Nr7Zman_Y&list=PL6n9fhu94yhVkdrusLaQsfERmL_Jh4XmU&index=44 )

Бхану Пратап
источник
1

У меня была та же проблема, и я обнаружил, что мой код использовал инъекцию до ее инициализации.

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

Я знаю, что это не имеет никакого отношения к вопросу, но, поскольку меня отправили на эту страницу, я понял, что это может быть полезно для кого-то еще.

Sauleil
источник
0

Я заменил

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

С участием

services.AddTransient<IMyLogger, MyLogger>();

И это сработало для меня.

Сатиш Мадарапу
источник
-1

Я получил эту ошибку, потому что я объявил переменную (выше метода ConfigureServices) типа, который был моим контекстом. Я имел:

CupcakeContext _ctx

Не уверен, что я думал. Я знаю, что это допустимо, если вы передаете параметр в метод Configure.

athomas
источник
-1

Я получил ошибку: «невозможно разрешить зависимость xxxxxxxx для всех версий ядра .net». Я перепробовал все доступное в интернете и застрял на несколько дней. Единственное решение, которое я придумал, - добавить файл nuget.config в проект, а затем использовать восстановление dotnet, чтобы оно заработало.

Содержимое файла 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>
Шантану Гаутам
источник