Is there any way to inject custom service into startup class constructor in ASP.NET Core 3.0? I can use IWebHostBuilder鈥檚 ConfigureServices method in ASP.NET Core 2.2. In 3.0 it was broken.
ASP.NET Core 2.2 Example
ClassToInject instance injected into Startup ctor
AspNetCore2.csproj
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
</Project>
Program.cs
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
namespace AspNetCore2
{
public class ClassToInject
{
public ClassToInject(string value) { Value = value; }
public string Value { get; }
}
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureServices((builder, services) =>
{
services.AddSingleton<ClassToInject>(new ClassToInject("Hello, I'm your dep!"));
})
.UseStartup<Startup>();
}
public class Startup
{
private readonly string _text;
public Startup(ClassToInject injection)
{
_text = injection.Value;
}
public void Configure(IApplicationBuilder app)
{
app.Run(async (context) =>
{
await context.Response.WriteAsync(_text);
});
}
}
}
ASP .NET Core 3.0 Example
Application throws an exception 'Unable to resolve service for type 'AspNetCore3.ClassToInject' while attempting to activate 'AspNetCore3.Startup'.'
AspNetCore3.csproj
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
</PropertyGroup>
</Project>
Program.cs
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace AspNetCore3
{
public class ClassToInject
{
public ClassToInject(string value) { Value = value; }
public string Value { get; }
}
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices((builder, services) =>
{
services.AddSingleton<ClassToInject>(new ClassToInject("Hello, I'm your dep!"));
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder
.UseStartup<Startup>()
.ConfigureServices((builder, services) =>
{
services.AddSingleton<ClassToInject>(new ClassToInject("Hello, I'm your dep!"));
});
});
}
public class Startup
{
private readonly string _text;
public Startup(ClassToInject injection)
{
_text = injection.Value;
}
public void Configure(IApplicationBuilder app)
{
app.Run(async (context) =>
{
await context.Response.WriteAsync(_text);
});
}
}
}
No there isn't. This is one of the breaking changes made in 3.0. The issue being that we now have a single dependency injection container so it's impossible to use a container to resolve the Startup class (which itself has ConfigureServices). We now only allow injecting a few known services (IHostEnvironment, IConfiguration) but not user defined services.
@davidfowl I find that feature was very useful, because I can add some checks to options that I would like to use inside Startup. As example, I can check that connection strings that passed to my application is valid, or some option that mapped to enum is not out of it's defined values. So my app did not start if someone pass incorrect configuration to it, and can tell what options is incorrect. So maybe ASP.NET Core team can add additional "Host" container that will contains some services that can be injected into Startup ctor?
No this is an intentional breaking change. Adding 2 containers causes other problems like duplicate singletons being declared. The model has been simplified and this is one of the new constraints.
Argh, @davidfowl that's a bad news.
I've some poco classes that contains configuration informations (can't put them into application settings configuration for several reasons and they come from external packages as embedded resources).
These configuration information are needed to configure other services (connection strings, authority urls, and so on).
Looking what you wrote, the migration from 2.2 to 3.0 will be bigger than expected.
Looking what you wrote, the migration from 2.2 to 3.0 will be bigger than expected.
Keep using the WebHostBuilder as part of the migration then. We intentionally didn't deprecate it because we knew some of these would be a problem and this gives us time to evaluate the scenarios to come up with something reasonable (like passing the startup instance directly).
@davidfowl thanks for the quick reply.
It is very helpful, hope you will keep this scenario open also with generic host
Just want to add a current scenario where injecting into Startup is necessary. In Service Fabric the way to use reliable collections inside AspNetCore controllers is to inject the service context into startup. Maybe the best solution would be to allow passing a Func
Most helpful comment
@davidfowl thanks for the quick reply.
It is very helpful, hope you will keep this scenario open also with generic host