-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow services to be easily resolved from the application service provider from within EF Core #13540
Comments
@chernihiv Could you show the code for setting up the service provider(s)? |
@ajcvickers Sure, I've built from scratch, empty solution. Here is all configuration: public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IMyCustomService, MyCustomService>();
services.AddDbContext<InitContext>(item => item
.UseSqlServer(@"Data Source=.\SQLEXPRESS;Initial Catalog=Test1;Integrated Security=True;Persist Security Info=False;MultipleActiveResultSets=True")
.ReplaceService<IMigrationsSqlGenerator, CustomMigrationsSqlGenerator>());
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseDeveloperExceptionPage();
app.UseMvc();
}
}
public class InitContext : DbContext
{
public InitContext(DbContextOptions<InitContext> options) : base(options)
{
}
public DbSet<User> Users { get; set; }
}
public class User
{
public int Id { get; set; }
}
internal class CustomMigrationsSqlGenerator : SqlServerMigrationsSqlGenerator
{
public CustomMigrationsSqlGenerator(
IMyCustomService myCustomService,
MigrationsSqlGeneratorDependencies dependencies,
IMigrationsAnnotationProvider migrationsAnnotations)
: base(dependencies, migrationsAnnotations) { }
}
internal class MyCustomService : IMyCustomService
{
public string Test()
{
return "test";
}
}
public interface IMyCustomService
{
string Test();
} Here is controller for testing. Don't forget to create Init migration. [Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
private readonly InitContext _context;
private readonly IMyCustomService _myCustomService;
public ValuesController(InitContext context, IMyCustomService myCustomService)
{
_context = context;
_myCustomService = myCustomService;
}
[HttpGet("/test/users")]
public async Task<IEnumerable<User>> TestUsers()
{
return await _context.Users.ToListAsync();
}
[HttpGet("/migrate")]
public async Task Migrate()
{
await _context.Database.MigrateAsync();
}
[HttpGet("/test/service")]
public ActionResult<string> TestService()
{
return _myCustomService.Test();
}
} Without IMyCustomService in CustomMigrationsSqlGenerator you are able to Migrate and use all APIs, but with IMyCustomService service you should receive the following exception:
|
Notes for triage: there are several things going on here:
So this leaves taking over the internal service provider as the only solution, which is a bit drastic for just adding a singleton dependency to a singleton service. |
BTW, what I am going to achieve is multi tenancy. I have generated migrations for several DB providers, but it has predefined table names and related. In my case, each client (user) will have unique prefix and I'd like to append this prefix to each table dynamically. Therefore, each client (user) will have own independent tables which starts from client's prefix.
Could you assist? |
Notes from triage: we should consider allow registering an explicit bridge service in the internal service provider such that both singleton services can be registered and so that constructor injection can be used to resolve these in replaced services. @chernihiv Overriding the MigrationsSqlGenerator is not the way to do this. It would allow different databases to be created, but would not allow them to be used with the underlying EF model. Instead consider dynamically building different models based on the tenant. Controlling when the different models are used can be done with a ModelCacheKey |
@ajcvickers Sure, I do similar things in the same way, but instead schema I change table name. It works. But, what if there is new Tenant? Tenant could specify any DB Provider and Connection he wish. What I need is to apply migrations to this database and seed it with data. I have common clear migrations, it knows nothing about tenant and I should dynamically change schema or tableprefix and migrate it for new Tenant. Therefore, I need to override IMigrationsSqlGenerator for all supported db providers and change on spot schema or table name. |
See also the scenarios and suggestions in #23559 when working on this issue. |
Fixes #13540 Scoped and transient internal services can obtain application services using the `DbContext` as a service locator. Singleton services cannot do this since they do not have access to the `DbContext`. This change allows the root application service provider to be registered as an `ISingletonOption` such that singleton internal services can resolve singleton and transient application services.
Fixes #13540 Scoped and transient internal services can obtain application services using the `DbContext` as a service locator. Singleton services cannot do this since they do not have access to the `DbContext`. This change allows the root application service provider to be registered as an `ISingletonOption` such that singleton internal services can resolve singleton and transient application services.
I try to resolve CustomMigrationsSqlGenerator with IMyCustomService but it throws an exception.
I have overridden partially logic inside SqlServerMigrationsSqlGenerator, but for my goal I need to resolve extra service inside, e.g:
it throws an exception
System.InvalidOperationException: Unable to resolve service for type 'IMyCustomService' while attempting to activate 'CustomMigrationsSqlGenerator'.
IMyCustomService is registered as:
Further technical details
EF Core: Microsoft.EntityFrameworkCore 2.1.4
Database Provider: Microsoft.EntityFrameworkCore.SqlServer 2.1.4
Operating system: Windows 10 Pro 1803, 17134.285
IDE: Visual Studio 2017 15.8.6
The text was updated successfully, but these errors were encountered: