ASP.NET Core Dependency Injection 오류 : 정품 인증을 시도하는 동안 형식에 대한 서비스를 확인할 수 없습니다


198

.NET Core MVC 응용 프로그램을 만들고 Dependency Injection 및 Repository Pattern을 사용하여 리포지토리를 컨트롤러에 주입합니다. 그러나 오류가 발생합니다.

InvalidOperationException : 'WebApplication1.Controllers.BlogController'를 활성화하는 중 'WebApplication1.Data.BloggerRepository'유형의 서비스를 분석 할 수 없습니다.

모델 (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을> ()를 사용하여 추가됩니다 '
마우 그라시아 구티에레즈

답변:


292

예외는 WebApplication1.Data.BloggerRepository컨트롤러의 생성자가 인터페이스 대신 콘크리트 클래스를 요청하기 때문에 서비스를 확인할 수 없다는 것입니다. 따라서 변경하십시오.

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

7
하나의 캐릭터를 간과하는 것이 얼마나 쉬운 지 ... 감사합니다!
jleach

HttpContextAccessor클래스 를 사용하면서 이것을받은 챔피언 은 IHttpContextAccessor
mtbennett

Mac에서 최악의 VS를 사용하면 "예기치 않게 종료"오류가 발생합니다. 올바른 오류를 얻으려면 터미널에서 실행해야 하며이 솔루션에 부딪 쳤습니다.
NoloMokgosi

57

종속성 주입 설정에서 컨트롤러의 종속성 인 저장소의 종속성이 없기 때문에이 문제가 발생했습니다.

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

나를 위해 해결, 이것은 내 문제였다
anisanwesley

내 서비스가 올바른 "네임 스페이스"에 있지 않기 때문에 문제를 해결했습니다.
user2982195

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 <> ();에 필요 감사합니다!
Omzig

14

누구든지 나와 같은 상황이있는 경우에만 기존 데이터베이스로 EntityFramework 자습서를 수행하고 있지만 모델 폴더에서 새 데이터베이스 컨텍스트를 만들 때 서비스뿐만 아니라 시작시 컨텍스트를 업데이트해야합니다. 사용자 인증이있는 경우 AddDbContext이지만 AddIdentity도

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

시작 ConfigureServices방법 에 "services.AddScoped"를 추가하는 것을 잊었습니다 .


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

팩토리를 등록하여 DbContext 파생 클래스 IBlogContextFactory의 인스턴스를 작성하고 Create 메소드를 사용하여 블로그 컨텍스트의 인스턴스를 인스턴스화하여 종속성 인젝션과 함께 아래 패턴을 사용할 수 있고 단위 테스트를 위해 조롱을 사용할 수도 있습니다.

내가 사용하고 싶었던 패턴은

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 (); 프로젝트의 Startup.cs 파일의 ConfigureServices 메소드에서

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

질문과 관련이 없다는 것을 알고 있지만이 페이지로 보내진 이후 다른 사람에게 유용하다고 생각합니다.


0

나는 바꿨다

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

services.AddTransient<IMyLogger, MyLogger>();

그리고 그것은 나를 위해 일했습니다.


-1

내 컨텍스트 인 유형의 변수 (ConfigureServices 메소드 위)를 선언했기 때문에이 오류가 발생했습니다. 나는했다 :

CupcakeContext _ctx

내가 무슨 생각을했는지 모르겠다. 매개 변수를 Configure 메서드에 전달하는 경우이 작업을 수행하는 것이 합법적이라는 것을 알고 있습니다.


-1

"모든 버전의 .net 코어에 대한 종속성 xxxxxxxx를 (를) 확인할 수 없습니다"라는 오류가 발생했습니다. 나는 인터넷에서 사용 가능한 모든 것을 시도했고 며칠 동안 붙어있었습니다. 내가 찾은 유일한 해결책은 프로젝트에 nuget.config 파일을 추가 한 다음 dotnet restore를 사용하여 작동시키는 것입니다.

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>
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.