Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 628 Vote(s) - 3.5 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Cannot resolve scoped service from root provider .Net Core 2

#1
When I try to run my app I get the error

InvalidOperationException: Cannot resolve 'API.Domain.Data.Repositories.IEmailRepository' from root provider because it requires scoped service 'API.Domain.Data.EmailRouterContext'.

What's odd is that this EmailRepository and interface is set up exactly the same as far as I can tell as all of my other repositories yet no error is thrown for them. The error only occurs if I try to use the app.UseEmailingExceptionHandling(); line. Here's some of my Startup.cs file.


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

Here is the 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;
}
}
}

And finally the exception handling middleware

public class ExceptionHandlingMiddleware
{
private const string ErrorEmailAddress = "[email protected]";
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>();
}
}

Update:
I found this link

[To see links please register here]

which led me to change my Program.cs file's BuildWebHost method from this

public static IWebHost BuildWebHost(string[] args)
{
return WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
}

to this

public static IWebHost BuildWebHost(string[] args)
{
return WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseDefaultServiceProvider(options =>
options.ValidateScopes = false)
.Build();
}

I don't know what exactly is going on but it seems to work now.
Reply

#2
Middleware is always a singleton so you can't have scoped dependencies as constructor dependencies in the constructor of your middleware.

Middleware supports method injection on the Invoke method,so you can just add the IEmailRepository emailRepository as a parameter to that method and it will be injected there and will be fine as scoped.

public async Task Invoke(HttpContext context, IEmailRepository emailRepository)
{

....
}
Reply

#3
You registered the `IEmailRepository` as a scoped service, in the `Startup` class.
This means that you can not inject it as a constructor parameter in `Middleware` because only `Singleton` services can be resolved by constructor injection in `Middleware`. You should move the dependency to the `Invoke` method like this:


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

Reply

#4
Your `middleware` and the `service` has to be compatible with each other in order to inject the `service` via the `constructor` of your `middleware`. Here, your `middleware` has been created as a `convention-based middleware` which means it acts as a `singleton service` and you have created your service as `scoped-service`. So, you cannot inject a `scoped-service` into the constructor of a `singleton-service` because it forces the `scoped-service` to act as a `singleton` one. However, here are your options.

1. Inject your service as a parameter to the `InvokeAsync` method.
2. Make your service a singleton one, if possible.
3. Transform your `middleware` to a `factory-based` one.

A `Factory-based middleware` is able to act as a `scoped-service`. So, you can inject another `scoped-service` via the constructor of that middleware. Below, I have shown you how to create a `factory-based` middleware.

This is only for demonstration. So, I have removed all the other code.

public class Startup
{
public Startup()
{
}

public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<TestMiddleware>();
services.AddScoped<TestService>();
}

public void Configure(IApplicationBuilder app)
{
app.UseMiddleware<TestMiddleware>();
}
}

The `TestMiddleware`:

public class TestMiddleware : IMiddleware
{
public TestMiddleware(TestService testService)
{
}

public Task InvokeAsync(HttpContext context, RequestDelegate next)
{
return next.Invoke(context);
}
}

The `TestService`:

public class TestService
{
}
Reply

#5
Another way to get the instance of scoped dependency is to inject service provider (`IServiceProvider`) into the middleware constructor, create `scope` in `Invoke` method and then get the required service from the scope:

using (var scope = _serviceProvider.CreateScope()) {
var _emailRepository = scope.ServiceProvider.GetRequiredService<IEmailRepository>();

//do your stuff....
}

Check out **Resolving Services in a Method Body** in [asp.net core dependency injection best practices tips tricks][1] for more details.


[1]:

[To see links please register here]

Reply

#6
In .NET Core 6, the below settings worked for me.



using (var scope = app.Services.CreateScope())
{
var services = scope.ServiceProvider.GetRequiredService<IDbInitilizer>;
services.Invoke().Initialize();
}






















































































































[![DBInitilizer][1]][1]


[1]:
Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through