Подтвердить что ты не робот

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

Я создал приложение .NET Core MVC и использовал Dependency Injection and 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);
        }
    }
}

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

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

Ответ 3

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

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

Ответ 4

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

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

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

Ответ 5

У меня была другая проблема, и да, параметризованный конструктор для моего контроллера уже был добавлен с правильным интерфейсом. То, что я сделал, было чем-то простым. Я просто захожу в свой файл 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

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

Ответ 6

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

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

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

Ответ 7

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

services.AddSingleton<IOrderService, OrderService>();

Ответ 8

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

По умолчанию

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

Добавь это

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

Ответ 9

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

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

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

services.AddScoped(IGenericRepository, GenericRepository);

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

Ответ 10

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

Вы забыли добавить Addscope при запуске метода Configureservices.

Ответ 11

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

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

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

вместо

containerBuilder.RegisterType<DataService>();

Ответ 12

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

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

Ответ 13

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

        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 заботились.

Ответ 14

Я заменил services.Add(new ServiceDescriptor(typeof(IMyLogger), typeof(MyLogger))) services.AddTransient<IMyLogger, MyLogger>()

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

Ответ 15

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

CupcakeContext _ctx

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