내 앱을 실행하려고하면 오류가 발생합니다.
InvalidOperationException: Cannot resolve 'API.Domain.Data.Repositories.IEmailRepository' from root provider because it requires scoped service 'API.Domain.Data.EmailRouterContext'.
이상한 점은이 EmailRepository와 인터페이스가 다른 모든 저장소와 동일하게 설정되어 있지만 오류가 발생하지 않는다는 것입니다. 이 오류는 app.UseEmailingExceptionHandling ();을 사용하려고 할 때만 발생합니다. 선. 다음은 내 Startup.cs 파일 중 일부입니다.
public class Startup
{
public IConfiguration Configuration { get; protected set; }
private APIEnvironment _environment { get; set; }
public Startup(IConfiguration configuration, IHostingEnvironment env)
{
Configuration = configuration;
_environment = APIEnvironment.Development;
if (env.IsProduction()) _environment = APIEnvironment.Production;
if (env.IsStaging()) _environment = APIEnvironment.Staging;
}
public void ConfigureServices(IServiceCollection services)
{
var dataConnect = new DataConnect(_environment);
services.AddDbContext<GeneralInfoContext>(opt => opt.UseSqlServer(dataConnect.GetConnectString(Database.GeneralInfo)));
services.AddDbContext<EmailRouterContext>(opt => opt.UseSqlServer(dataConnect.GetConnectString(Database.EmailRouter)));
services.AddWebEncoders();
services.AddMvc();
services.AddScoped<IGenInfoNoteRepository, GenInfoNoteRepository>();
services.AddScoped<IEventLogRepository, EventLogRepository>();
services.AddScoped<IStateRepository, StateRepository>();
services.AddScoped<IEmailRepository, EmailRepository>();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole();
app.UseAuthentication();
app.UseStatusCodePages();
app.UseEmailingExceptionHandling();
app.UseMvcWithDefaultRoute();
}
}
다음은 EmailRepository입니다.
public interface IEmailRepository
{
void SendEmail(Email email);
}
public class EmailRepository : IEmailRepository, IDisposable
{
private bool disposed;
private readonly EmailRouterContext edc;
public EmailRepository(EmailRouterContext emailRouterContext)
{
edc = emailRouterContext;
}
public void SendEmail(Email email)
{
edc.EmailMessages.Add(new EmailMessages
{
DateAdded = DateTime.Now,
FromAddress = email.FromAddress,
MailFormat = email.Format,
MessageBody = email.Body,
SubjectLine = email.Subject,
ToAddress = email.ToAddress
});
edc.SaveChanges();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
edc.Dispose();
disposed = true;
}
}
}
마지막으로 예외 처리 미들웨어
public class ExceptionHandlingMiddleware
{
private const string ErrorEmailAddress = "errors@ourdomain.com";
private readonly IEmailRepository _emailRepository;
private readonly RequestDelegate _next;
public ExceptionHandlingMiddleware(RequestDelegate next, IEmailRepository emailRepository)
{
_next = next;
_emailRepository = emailRepository;
}
public async Task Invoke(HttpContext context)
{
try
{
await _next.Invoke(context);
}
catch (Exception ex)
{
await HandleExceptionAsync(context, ex, _emailRepository);
}
}
private static Task HandleExceptionAsync(HttpContext context, Exception exception,
IEmailRepository emailRepository)
{
var code = HttpStatusCode.InternalServerError; // 500 if unexpected
var email = new Email
{
Body = exception.Message,
FromAddress = ErrorEmailAddress,
Subject = "API Error",
ToAddress = ErrorEmailAddress
};
emailRepository.SendEmail(email);
context.Response.ContentType = "application/json";
context.Response.StatusCode = (int) code;
return context.Response.WriteAsync("An error occured.");
}
}
public static class AppErrorHandlingExtensions
{
public static IApplicationBuilder UseEmailingExceptionHandling(this IApplicationBuilder app)
{
if (app == null)
throw new ArgumentNullException(nameof(app));
return app.UseMiddleware<ExceptionHandlingMiddleware>();
}
}
업데이트 :이 링크 https://github.com/aspnet/DependencyInjection/issues/578 을 발견하여 Program.cs 파일의 BuildWebHost 메서드를 변경했습니다.
public static IWebHost BuildWebHost(string[] args)
{
return WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
}
이에
public static IWebHost BuildWebHost(string[] args)
{
return WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseDefaultServiceProvider(options =>
options.ValidateScopes = false)
.Build();
}
정확히 무슨 일이 일어나고 있는지 모르겠지만 지금은 작동하는 것 같습니다.
답변
클래스 IEmailRepository
에서 범위 서비스로을 등록했습니다 Startup
. 즉, .NET에서 생성자 삽입으로 서비스 Middleware
만 Singleton
해결할 수 있으므로 에서 생성자 매개 변수로 삽입 할 수 없습니다 Middleware
. 종속성을 다음 Invoke
과 같이 메서드 로 이동해야 합니다.
public ExceptionHandlingMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context, IEmailRepository emailRepository)
{
try
{
await _next.Invoke(context);
}
catch (Exception ex)
{
await HandleExceptionAsync(context, ex, emailRepository);
}
}
답변
범위의 의존성의 인스턴스를 얻는 또 다른 방법은 서비스 제공자 (주입하는 IServiceProvider
미들웨어 생성자) 생성 scope
에 Invoke
있어서 다음 범위에서 필요한 서비스를받을 :
using (var scope = _serviceProvider.CreateScope()) {
var _emailRepository = scope.ServiceProvider.GetRequiredService<IEmailRepository>();
//do your stuff....
}
자세한 내용 은 asp.net 핵심 종속성 주입 모범 사례 팁 트릭 에서 메서드 본문의 서비스 해결을 확인 하십시오.
답변
미들웨어는 항상 싱글 톤이므로 미들웨어 생성자에서 생성자 종속성으로 범위 종속성을 가질 수 없습니다.
미들웨어는 Invoke 메서드에 대한 메서드 삽입을 지원하므로 IEmailRepository emailRepository를 해당 메서드에 매개 변수로 추가하기 만하면 해당 메서드에 삽입되고 범위가 지정됩니다.
public async Task Invoke(HttpContext context, IEmailRepository emailRepository)
{
....
}
답변
당신 middleware
과는 service
를 주입하기 위해 서로 호환되어야합니다 service
를 통해 constructor
당신의 middleware
. 여기에서 귀하 middleware
는으로 생성되었으며 convention-based middleware
이는으로 작동하고 singleton service
서비스를 scoped-service
. 그래서, 당신은을 주입 할 수 scoped-service
a의 생성자 singleton-service
는이 강제 때문에 scoped-service
A와 역할을 singleton
하나. 그러나 여기에 옵션이 있습니다.
- 서비스를 매개 변수로
InvokeAsync
메소드에 삽입하십시오 . - 가능하면 서비스를 싱글 톤으로 만드십시오.
- 당신
middleware
을factory-based
하나로 바꾸십시오 .
A Factory-based middleware
는 scoped-service
. 따라서 scoped-service
해당 미들웨어의 생성자를 통해 다른 것을 주입 할 수 있습니다 . 아래에서 factory-based
미들웨어 를 만드는 방법을 보여 드렸습니다.
이것은 데모 용입니다. 그래서 다른 모든 코드를 제거했습니다.
public class Startup
{
public Startup()
{
}
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<TestMiddleware>();
services.AddScoped<TestService>();
}
public void Configure(IApplicationBuilder app)
{
app.UseMiddleware<TestMiddleware>();
}
}
TestMiddleware
:
public class TestMiddleware : IMiddleware
{
public TestMiddleware(TestService testService)
{
}
public Task InvokeAsync(HttpContext context, RequestDelegate next)
{
return next.Invoke(context);
}
}
TestService
:
public class TestService
{
}