ASP.NET Core Dependency Injection 오류 : 정품 인증을 시도하는 동안 형식에 대한 서비스를 확인할 수 없습니다
.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);
}
}
}
내가 뭘 잘못하고 있는지 잘 모르겠습니다. 어떤 아이디어?
예외는 WebApplication1.Data.BloggerRepository
컨트롤러의 생성자가 인터페이스 대신 콘크리트 클래스를 요청하기 때문에 서비스를 확인할 수 없다는 것입니다. 따라서 변경하십시오.
public BlogController(IBloggerRepository repository)
// ^
// Add this!
{
_repository = repository;
}
필자의 경우 생성자 인수가 필요한 객체에 대한 종속성 주입을 시도했습니다. 이 경우 시작하는 동안 구성 파일에서 인수를 제공했습니다. 예를 들면 다음과 같습니다.
var config = Configuration.GetSection("subservice").Get<SubServiceConfig>();
services.AddScoped<ISubService>(provider => new SubService(config.value1, config.value2));
종속성 주입 설정에서 컨트롤러의 종속성 인 저장소의 종속성이 없기 때문에이 문제가 발생했습니다.
services.AddScoped<IDependencyOne, DependencyOne>(); <-- I was missing this line!
services.AddScoped<IDependencyTwoThatIsDependentOnDependencyOne, DependencyTwoThatIsDependentOnDependencyOne>();
누구든지 나와 같은 상황이있는 경우에만 기존 데이터베이스로 EntityFramework 자습서를 수행하고 있지만 모델 데이터베이스에서 새 데이터베이스 컨텍스트를 만들 때 서비스뿐만 아니라 시작시 컨텍스트를 업데이트해야합니다. 사용자 인증이있는 경우 AddDbContext이지만 AddIdentity도
services.AddDbContext<NewDBContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<NewDBContext>()
.AddDefaultTokenProviders();
나는 다른 문제를 겪고 있었고, 컨트롤러의 매개 변수 생성자가 이미 올바른 인터페이스로 추가되었습니다. 내가 한 것은 간단한 일이었습니다. 방금 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
도움이 되었기를 바랍니다.
다소 바보 같은 실수 로이 문제가 발생했습니다. ASP.NET Core 응용 프로그램에서 컨트롤러를 자동으로 검색하기 위해 서비스 구성 절차를 연결하는 것을 잊었습니다.
이 방법을 추가하면 해결되었습니다.
// Add framework services.
services.AddMvc()
.AddControllersAsServices(); // <---- Super important
작동하려면 ConfigureServices에이 줄을 추가해야했습니다.
services.AddSingleton<IOrderService, OrderService>();
DBcontext
시작시 새 서비스를 추가해야합니다
기본
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
이거 추가 해봐
services.AddDbContext<NewDBContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("NewConnection")));
오, @kimbaudi 감사합니다, 나는이 tuts를 따라
https://dotnettutorials.net/lesson/generic-repository-pattern-csharp-mvc/
당신과 같은 오류가 발생했습니다. 그러나 코드를 읽은 후 내 솔루션이 추가되고 있음을 알았습니다.
services.AddScoped (IGenericRepository, GenericRepository);
로 ConfigureServices의 StartUp.cs 파일 METHOD =))
Public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IEventRepository, EventRepository>();
}
시작 Configureservices
방법 에 Addscope를 추가해야합니다 .
AutoFac을 사용 중이고이 오류가 발생하면 "As"문을 추가하여 구체적인 구현이 구현하는 서비스를 지정해야합니다.
즉. 당신은 작성해야합니다 :
containerBuilder.RegisterType<DataService>().As<DataService>();
대신에
containerBuilder.RegisterType<DataService>();
이 문제는 작성된 인터페이스에 데이터 액세스 구성 요소를 등록하지 않았기 때문입니다. 다음과 같이 사용해보십시오
services.AddTransient<IMyDataProvider, MyDataAccess>();`
나는 예외 아래에 가고 있었다
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; }
}
----- To Fix this in .net Core MVC project -- I did below changes on dependency registration
services
.AddDbContext<BloggingContext>()
.AddTransient<IBloggingContext, BloggingContext>()
.AddTransient<IBloggingContextFactory, BloggingContextFactory>(
sp => new BloggingContextFactory( () => sp.GetService<IBloggingContext>())
);
In short in .net core developer is responsible to inject factory function, which in case of Unity and .Net Framework was taken care of.
I replaced services.Add(new ServiceDescriptor(typeof(IMyLogger), typeof(MyLogger)))
With services.AddTransient<IMyLogger, MyLogger>()
And it worked for me.
I got this error because I declared a variable (above the ConfigureServices method) of type that was my context. I had:
CupcakeContext _ctx
Not sure what I was thinking. I know it's legal to do this if your passing in a parameter to the Configure method.
'development' 카테고리의 다른 글
RESTful 방식으로 자원에 대한 서버 측 메소드 호출 (0) | 2020.06.29 |
---|---|
AngularJS 및 ng-repeat를 사용하여 선택 초기화 (0) | 2020.06.29 |
파이썬에서의 부정 (0) | 2020.06.28 |
Docker 이미지 "레이어"란 무엇입니까? (0) | 2020.06.28 |
500 내부 서버 오류가 발생하지 않고 PHP가 오류를 표시하도록하려면 어떻게해야합니까 (0) | 2020.06.28 |