Помилка введення базової залежності ASP.NET: Неможливо вирішити службу для типу під час спроби активації


198

Я створив додаток .NET Core MVC і використовую шаблон введення залежностей та сховища для введення сховища в свій контролер. Однак я отримую помилку:

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

Я не впевнений, що роблю не так. Будь-які ідеї?


Я знаю, що це старе питання, але ... Ви не повинні розміщувати контекст db всередині служби. Контекст db автоматично розміщується розв'язувачем області. Якщо ви розпоряджаєтесь всередині сервісу, він може бути утилізований під час виклику наступної служби в межах того ж запиту / обсягу.
Silvermind

1
Переконайтеся, що послуга (відсутній клас) додана за допомогою ´services.AddTransient <YourClassOrInterface> (); ´
Mauricio Gracia Gutierrez

Відповіді:


292

Виняток говорить, що він не може вирішити службу, WebApplication1.Data.BloggerRepositoryоскільки конструктор на вашому контролері запитує конкретний клас замість інтерфейсу. Тому просто змініть це:

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

7
Дивно, як легко не помітити одного персонажа ... дякую!
jleach

Який чемпіон, отримавши це під час використання HttpContextAccessorкласу, виявляється, мені потрібенIHttpContextAccessor
mtbennett

Настільки роздратований, тому що я пережив більше 30 хвилин на цьому. Західний VS на Mac надає помилку "донет кинути несподівано". Доводиться працювати на терміналі, щоб отримати правильну помилку, тоді я наткнувся на це рішення.
NoloMokgosi

57

Я зіткнувся з цим питанням, тому що в налаштуваннях ін'єкцій залежностей мені не вистачало залежності сховища, яке є залежністю контролера:

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

Для мене вирішили цю проблему
anisanwesley

Вирішили свою проблему, оскільки я визнав, що мої служби не знаходяться у правильному "просторі імен".
користувач2982195

24

У моєму випадку я намагався зробити ін'єкцію залежності для об'єкта, який вимагав конструкторських аргументів. У цьому випадку під час запуску я просто наводив аргументи з конфігураційного файлу, наприклад:

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

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")));


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

Ви забули додати "services.AddScoped" у ConfigureServicesспосіб запуску .


5

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

Додавання цього методу вирішило його:

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

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, щоб створити екземпляри класу IBbContextFactory, отриманого з DbContext, і використовувати метод Create, щоб інстанціювати екземпляр Blog Context, щоб я міг використовувати нижче шаблон разом із залежністю Injection, а також можу використовувати глузування для тестування одиниць.

шаблон, який я хотів використовувати

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 було подбано.


3

Ця проблема пов'язана з тим, що ви не зареєстрували компонент доступу до даних в інтерфейсі, написаному для нього. Спробуйте використовувати наступне

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

2

Якщо ви використовуєте AutoFac і отримуєте цю помилку, вам слід додати оператор "As", щоб вказати послугу, яку реалізує конкретна реалізація.

Тобто ви повинні написати:

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

замість

containerBuilder.RegisterType<DataService>();


2

Вирішення послуги проводиться ще до того, як буде досягнуто код класу, тому нам потрібно перевірити нашу ін'єкцію залежності.

У моєму випадку я додав

        services.AddScoped<IMeasurementService, MeasurementService>();

в StartupExtensions.cs


1

Додати послуги.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 vs AddScoped vs 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>();

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



-1

Я отримав цю помилку, оскільки я оголосив змінну (вище методу ConfigureServices) типу, що була моїм контекстом. Я мав:

CupcakeContext _ctx

Не впевнений, що я думав. Я знаю, що це законно робити, якщо ви передаєте параметр методу Налаштування.


-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>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.