ASP.NET核心AddHostedService和AddSingleton关系
ASP.NET Core AddHostedService and AddSingleton relationship
我同时使用 AddSingleton 和 AddHostedService 在后端有一个很长的 运行 服务 (BackgroundService),而控制器访问相同的服务来获取数据。
以下是我的发现:
- 如果同时使用AddSingleton 和AddHostedService,BackgroundService 将被初始化两次(不是Singleton)。控制器只能访问在 AddSingleton 中创建的控制器。
调试输出(构造函数调用两次,看秒数的区别)
BGService constructor service addGame:games count is 1
BGService constructor service addGame:games count is 1
ExecuteAsync 1 :games
count is 1:[ "CONSTRUCTOR GAME AT 10/29/2021 10:37:25 AM(0)" ]
......
ExecuteAsync 7 :games count is 1:[ "CONSTRUCTOR GAME AT 10/29/2021
10:37:25 AM(0)" ]
service addGame:games count is 2 After AddGame: [
"CONSTRUCTOR GAME AT 10/29/2021 10:37:24 AM(0)", "GAME 0(1)" ]
如果只使用 AddSingleton 就成功了。
如果仅使用 AddHostedService,则 BackgroundService 为 运行,但 DI 无法在控制器中工作(异常)。
**> 失败:
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware1
An unhandled exception has occurred while executing the request. System.InvalidOperationException: Unable to resolve service for type
'CoreServiceSignalRSample.service.IBGService' while attempting to
activate
'CoreServiceSignalRSample.Controllers.WeatherForecastController'.
at
Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider
sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired)
at lambda_method(Closure , IServiceProvider , Object[] )**
我的问题是,DI 一个 BackgroundService 的正确方法是什么,为什么推荐使用 AddHostedService?
示例代码可以在 https://github.com/huangpat/CoreServiceSignalRSample 找到。
Startup.cs 配置服务
services.AddSingleton<IBGService>(new BGService());
services.AddHostedService<BGService>();
BGSercie.cs
private List<string> games;
public BGService()
{
Console.WriteLine("BGService constructor");
this.games = new List<string>();
this.addGame("Constructor Game at " + DateTime.Now.ToString());
}
public async Task<bool> addGame(string fGame)
{
if (this.games.Count <= 20)
{
this.games.Add(fGame.ToUpper() + "(" + Convert.ToString(this.games.Count) + ")");
Console.WriteLine("service addGame:games count is " + Convert.ToString(this.games.Count));
return true;
}
else
{
return false;
}
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
int i = 0;
while (true)
{
i++;
if (games.Count == 0)
{
this.addGame("ExecuteAsync Game at " + DateTime.Now.ToString());
}
JsonSerializer js = new JsonSerializer();
Console.WriteLine("ExecuteAsync {1} :games count is {0}:{2}", this.games.Count, i, JsonConvert.SerializeObject(this.games, Formatting.Indented));
await Task.Delay(1000 * 2 * 5);
}
//throw new NotImplementedException();
/
/ 使用线程池开始集合中的每个游戏
}
每个注册都会使用自己的解析规则创建自己的类型描述符(即默认情况下它将使用相应的构造函数)。您可以使用向实施工厂注册来解决它:
services.AddSingleton<BGService>();
services.AddSingleton<IBGService>(provider => provider.GetRequiredService<BGService>());
services.AddHostedService<BGService>(provider => provider.GetRequiredService<BGService>())
我同时使用 AddSingleton 和 AddHostedService 在后端有一个很长的 运行 服务 (BackgroundService),而控制器访问相同的服务来获取数据。 以下是我的发现:
- 如果同时使用AddSingleton 和AddHostedService,BackgroundService 将被初始化两次(不是Singleton)。控制器只能访问在 AddSingleton 中创建的控制器。
调试输出(构造函数调用两次,看秒数的区别)
BGService constructor service addGame:games count is 1 BGService constructor service addGame:games count is 1 ExecuteAsync 1 :games count is 1:[ "CONSTRUCTOR GAME AT 10/29/2021 10:37:25 AM(0)" ] ...... ExecuteAsync 7 :games count is 1:[ "CONSTRUCTOR GAME AT 10/29/2021 10:37:25 AM(0)" ] service addGame:games count is 2 After AddGame: [
"CONSTRUCTOR GAME AT 10/29/2021 10:37:24 AM(0)", "GAME 0(1)" ]
如果只使用 AddSingleton 就成功了。
如果仅使用 AddHostedService,则 BackgroundService 为 运行,但 DI 无法在控制器中工作(异常)。
**> 失败:
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware1 An unhandled exception has occurred while executing the request. System.InvalidOperationException: Unable to resolve service for type 'CoreServiceSignalRSample.service.IBGService' while attempting to activate 'CoreServiceSignalRSample.Controllers.WeatherForecastController'.
at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired)
at lambda_method(Closure , IServiceProvider , Object[] )**
我的问题是,DI 一个 BackgroundService 的正确方法是什么,为什么推荐使用 AddHostedService?
示例代码可以在 https://github.com/huangpat/CoreServiceSignalRSample 找到。
Startup.cs 配置服务
services.AddSingleton<IBGService>(new BGService());
services.AddHostedService<BGService>();
BGSercie.cs
private List<string> games;
public BGService()
{
Console.WriteLine("BGService constructor");
this.games = new List<string>();
this.addGame("Constructor Game at " + DateTime.Now.ToString());
}
public async Task<bool> addGame(string fGame)
{
if (this.games.Count <= 20)
{
this.games.Add(fGame.ToUpper() + "(" + Convert.ToString(this.games.Count) + ")");
Console.WriteLine("service addGame:games count is " + Convert.ToString(this.games.Count));
return true;
}
else
{
return false;
}
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
int i = 0;
while (true)
{
i++;
if (games.Count == 0)
{
this.addGame("ExecuteAsync Game at " + DateTime.Now.ToString());
}
JsonSerializer js = new JsonSerializer();
Console.WriteLine("ExecuteAsync {1} :games count is {0}:{2}", this.games.Count, i, JsonConvert.SerializeObject(this.games, Formatting.Indented));
await Task.Delay(1000 * 2 * 5);
}
//throw new NotImplementedException();
/
/ 使用线程池开始集合中的每个游戏 }
每个注册都会使用自己的解析规则创建自己的类型描述符(即默认情况下它将使用相应的构造函数)。您可以使用向实施工厂注册来解决它:
services.AddSingleton<BGService>();
services.AddSingleton<IBGService>(provider => provider.GetRequiredService<BGService>());
services.AddHostedService<BGService>(provider => provider.GetRequiredService<BGService>())