-
I am starting with a vanilla aspnet core 3.1 web api project. Full code below. I am attempting to substitute the default Here is a complete code sample showing the issue, the two Debug.Asserts()'s are being hit and I would expect them not to be: public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
.UseServiceProviderFactory(new TestServiceProviderFactory());
}
public class TestServiceProviderFactory : IServiceProviderFactory<IServiceCollection>
{
public IServiceCollection CreateBuilder(IServiceCollection services)
{
return services;
}
public IServiceProvider CreateServiceProvider(IServiceCollection containerBuilder)
{
// decorate the built-in ServiceProvider.
var inner = containerBuilder.BuildServiceProvider();
return new TestServiceProvider<ServiceProvider>(inner);
}
}
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
var sp = app.ApplicationServices;
Debug.Assert(sp.GetType() == typeof(TestServiceProvider<ServiceProvider>)); // fails
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
public class TestServiceProvider<TInnerProvider> : IServiceProvider
where TInnerProvider : IServiceProvider, IDisposable
{
private readonly IServiceProvider inner;
public TestServiceProvider(IServiceProvider inner)
{
this.inner = inner;
}
public object GetService(Type serviceType)
{
if (serviceType == typeof(IServiceProvider))
{
return this;
}
return inner.GetService(serviceType);
}
}
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
private readonly IServiceProvider sp;
public WeatherForecastController(ILogger<WeatherForecastController> logger, IServiceProvider sp)
{
_logger = logger;
Debug.Assert(sp.GetType() == typeof(TestServiceProvider<ServiceProvider>)); // fails
}
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
}
public class WeatherForecast
{
public DateTime Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
public string Summary { get; set; }
} Am I missing some other key step to replacing the in-built service provider here? |
Beta Was this translation helpful? Give feedback.
Replies: 6 comments
-
It seems the |
Beta Was this translation helpful? Give feedback.
-
I believe that trying to decorate the native ServiceProvider is not possible. When the native ServiceProvider is built, if any services have I'd like for all services registered for DI and with |
Beta Was this translation helpful? Give feedback.
-
I have the same issue and can confirm the sample code has the described effect. |
Beta Was this translation helpful? Give feedback.
-
I've worked around this issue, as I assume there will be no movement on it. The framework has a bit of a pain area, stemming from:
Background context: in my scenario I am dealing with a multitenant application, and each tenant has its own IServiceProvider. I am looking to be able to restart a tenant without impacting others, by disposing and rebuilding that tenabr service provider - for example to load that tenants updated plugins, without impacting other tenants by stopping the entire application. I have a working POC now, but this is an active pain point. |
Beta Was this translation helpful? Give feedback.
-
No this isn't possible. You need to implement a real container to get the transitive graph to work. I would use another container that supports these kinds of hooks. |
Beta Was this translation helpful? Give feedback.
-
@davidfowl OK thanks |
Beta Was this translation helpful? Give feedback.
No this isn't possible. You need to implement a real container to get the transitive graph to work. I would use another container that supports these kinds of hooks.