Reputation: 1015
Been doing some sample code with ASP.NET Core to try to understand how it fits together and I am stumped as to why I am unable to successfully resolve a service.
The configure services method has the call to add ISeedDataService
public void ConfigureServices(IServiceCollection services)
{
services.AddOptions();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddDbContext<CustomerDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddScoped<ICustomerDbContext, CustomerDbContext>();
services.AddScoped<ICustomerRepository, CustomerRepository>();
services.AddScoped<ISeedDataService, SeedDataService>();
}
In Configure I am calling AddSeedData() as below
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.AddSeedData();
}
which is calling the extension method below
public static async void AddSeedData(this IApplicationBuilder app)
{
var seedDataService = app.ApplicationServices.GetRequiredService<ISeedDataService>();
await seedDataService.EnsureSeedData();
}
and the SeedDataService is below
public class SeedDataService : ISeedDataService
{
private ICustomerDbContext _context;
public SeedDataService(ICustomerDbContext context)
{
_context = context;
}
public async Task EnsureSeedData()
{
_context.Database.EnsureCreated();
_context.Customers.RemoveRange(_context.Customers);
_context.SaveChanges();
Customer customer = new Customer();
customer.FirstName = "Chuck";
customer.LastName = "Norris";
customer.Age = 30;
customer.Id = Guid.NewGuid();
_context.Add(customer);
Customer customer2 = new Customer();
customer2.FirstName = "Fabian";
customer2.LastName = "Gosebrink";
customer2.Age = 31;
customer2.Id = Guid.NewGuid();
_context.Add(customer2);
await _context.SaveChangesAsync();
}
}
Totally unsure as to what I am doing wrong, the error is System.InvalidOperationException: 'Cannot resolve scoped service 'secondapp.Services.ISeedDataService' from root provider.'
Upvotes: 1
Views: 610
Reputation: 4553
The Configure()
method allows parameter dependency injection so you can do the following.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ISeedDataService seedService)
{
seedService.EnsureSeedData().Wait(); // Configure() is not async so you have to wait
}
Upvotes: -1
Reputation: 46651
You are (and should be) adding the ISeedDataService
as scoped service. However, you are attempting to resolve it from the root service provider (e.g. app.ApplicationServices
) which is not scoped. This means that scoped services resolved from it effectively are turned into a singleton service and are not disposed until the application shuts down or it will result in an error.
The solution here is to create a scope yourself:
public void Configure(IApplicationBuilder app)
{
using (var scope = app.ApplicationServices.CreateScope())
{
var seedDataService = scope.ServiceProvider.GetRequiredService<ISeedDataService>();
// Use seedDataService here
}
}
Please take a look at the documentation regarding dependency injection scopes.
On a second note: your AddSeedData
extension method is async void
and you are not waiting for the result. You should return a task (async Task
) call AddSeedData().GetAwaiter().GetResult()
to make sure you block until the seeding is complete.
Upvotes: 3