那是因为你在
ConfigureServices
中创建了一个独立的IoC容器。
var provider = services.BuildServiceProvider();
这行代码将创建一个新的服务提供者(IoC容器)。当你从中解析服务时,它们实际上是单例的(因为它不是从作用域提供者解析的)。
除非使用第三方容器并创建它(例如使用Autofac),否则您不应在ConfigureServices
方法内调用.BuildServiceProvider()
。
无论如何,如果您由于某种原因必须在ConfigureServices
内创建提供程序,则需要更改ConfigureServices
的签名
public IServiceProvider ConfigureServices(IServiceCollection services)
{
var provider = services.BuildServiceProvider();
...
return provider;
}
这将使ASP.NET Core使用此容器代替创建自己的容器并将其传递给
Configure
方法。
虽然这可能解决您的问题,但在
ConfigureServices
内部执行此类解析并不是很规范化,因此您应该查看文档(或提出单独的问题)以了解如何正确地使用Akka.NET进行DI(很抱歉我不熟悉它,我是Microsoft Orleans的用户:))。
稍微好一点的方式(仍然不完全正确,因为它绕过了DI的思想)是推迟直到调用
Configure
方法时才实例化Actor。
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IMyService, MyService>();
}
public void Configure(IApplicationBuilder app)
{
var system = ActorSystem.Create("MyActorSystem");
directory.MyActorRef
= system.ActorOf(MyActor.Props(app.ApplicationServices.GetService<IMyService>()), "myactor");
}
或者
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IMyService, MyService>();
}
public void Configure(IApplicationBuilder app, IMyService myService)
{
var system = ActorSystem.Create("MyActorSystem");
directory.MyActorRef
= system.ActorOf(MyActor.Props(myService), "myactor");
}
这将在Configure
中初始化和解析您的服务。
关于单例、范围和Actor的注意事项
请注意,您无法从app.ApplicationServices
或服务提供程序中解析作用域服务,否则会抛出异常。当您想要使用默认注册为作用域服务的DbContext时,这可能会成为问题。
您也可以通过覆盖AddDbContext
来将其注册为作用域,但请注意"内存泄漏",随着跟踪对象数量的增加,内存消耗也会增加(跟踪的实体数量(>=10k)将显著减少您的跟踪器相关操作)。
还要记住,考虑到DbContext,EF和EF Core不是线程安全的,并且不能被线程访问(或运行多个异步操作,即启动5个查询而不等待然后使用await Task.WaitAll(...)
)。
尽管Actor保证只能由单个线程在单个时间访问,但如果对它们进行作用域限制,则服务并不是。
这是否有效取决于Akka.NET使用的任务计划程序实现(再次强调,不熟悉其内部结构-即Orleans将持久性抽象为存储提供程序)。
system.ActorOf(MyActor.Props(provider.GetService<IMyService>()), "myactor")
。它直接在函数内部运行,并且在 Web 应用程序启动之前就已经创建了。 - Neville Nazerane