如何使用异步任务正确配置简单注入器
How to Properly configure Simple Injector with Async Tasks
我的 ASP.NET MVC 应用程序中有自托管 WebAPI。我想在执行我的 API 操作之一时执行一些异步操作。
异步操作依赖于 DbContext 以及其他一些依赖项。
以下是我的简单注入器配置。
public class SimpleInjectorIntegrator
{
private static Container container;
public static Container Setup()
{
container = new Container();
container.Options.DefaultScopedLifestyle = Lifestyle.CreateHybrid(
defaultLifestyle: new WebRequestLifestyle(),
fallbackLifestyle: new AsyncScopedLifestyle());
container.Register<IBaseRepository<User>, BaseRepository<User>>(Lifestyle.Scoped);
container.Register<ComputationService>(Lifestyle.Scoped);
container.Register<ILog, Logger>(Lifestyle.Scoped);
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
}
public static T Get<T>() where T : class
{
if (container == null)
throw new InvalidOperationException("Container hasn't been initialized.");
return container.GetInstance<T>();
}
}
Global.asax.cs 看起来像这样。
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
var container = SimpleInjectorIntegrator.Setup();
GlobalConfiguration.Configure(WebApiConfig.Register);
...some other code...
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
}
}
下面是 API 控制器。
public class ExperimentUploadController : ApiController
{
private ComputationService _service = SimpleInjectorIntegrator.Get<ComputationService>();
public IHttpActionResult Started(InputModel model)
{
...Do Something...
var task = Task.Run(() =>
{
_service.Do(model.Id);
});
}
}
API 取决于 ComputationService
,后者使用存储库执行与数据库的连接。当我尝试从 ComputationService
访问数据库时,它抛出 DbContext 已被处置。
ComputationService
代码如下所示:
public class ComputationService
{
private IBaseRepository<User> _userRepo = SimpleInjectorIntegrator.Get<User>();
public void Do(int id)
{
///throws here
var user = _userRepo.Get(id);
}
}
我不确定为什么会这样。
我面临的实际问题是我不希望我的 API 等待异步操作完成,因此 DbContext 被处理,如@John 所述。但是我需要 SimpleInjector 使用 AsyncScopedLifestyle 解决依赖关系,因为我已经在我的配置中配置了它。
我使用这个 Github link 找到了答案。我所做的是将我的异步方法包装在异步范围内并解决该范围内的依赖关系并且它有效。
这是更新后的代码。
public class ComputationService
{
private IBaseRepository<User> _userRepo;
public void Do(int id)
{
using(AsyncScopedLifestyle.BeginScope(SimpleInjectorIntegrator.Container))
{
_userRepo = = SimpleInjectorIntegrator.Container.GetInstance<User>();
var user = _userRepo.Get(id); //works fine.
}
}
}
我所做的另一项更改是在我的 SimpleInjectorIntegrator
class.
中通过 属性 公开容器
我的 ASP.NET MVC 应用程序中有自托管 WebAPI。我想在执行我的 API 操作之一时执行一些异步操作。 异步操作依赖于 DbContext 以及其他一些依赖项。
以下是我的简单注入器配置。
public class SimpleInjectorIntegrator
{
private static Container container;
public static Container Setup()
{
container = new Container();
container.Options.DefaultScopedLifestyle = Lifestyle.CreateHybrid(
defaultLifestyle: new WebRequestLifestyle(),
fallbackLifestyle: new AsyncScopedLifestyle());
container.Register<IBaseRepository<User>, BaseRepository<User>>(Lifestyle.Scoped);
container.Register<ComputationService>(Lifestyle.Scoped);
container.Register<ILog, Logger>(Lifestyle.Scoped);
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
}
public static T Get<T>() where T : class
{
if (container == null)
throw new InvalidOperationException("Container hasn't been initialized.");
return container.GetInstance<T>();
}
}
Global.asax.cs 看起来像这样。
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
var container = SimpleInjectorIntegrator.Setup();
GlobalConfiguration.Configure(WebApiConfig.Register);
...some other code...
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
}
}
下面是 API 控制器。
public class ExperimentUploadController : ApiController
{
private ComputationService _service = SimpleInjectorIntegrator.Get<ComputationService>();
public IHttpActionResult Started(InputModel model)
{
...Do Something...
var task = Task.Run(() =>
{
_service.Do(model.Id);
});
}
}
API 取决于 ComputationService
,后者使用存储库执行与数据库的连接。当我尝试从 ComputationService
访问数据库时,它抛出 DbContext 已被处置。
ComputationService
代码如下所示:
public class ComputationService
{
private IBaseRepository<User> _userRepo = SimpleInjectorIntegrator.Get<User>();
public void Do(int id)
{
///throws here
var user = _userRepo.Get(id);
}
}
我不确定为什么会这样。
我面临的实际问题是我不希望我的 API 等待异步操作完成,因此 DbContext 被处理,如@John 所述。但是我需要 SimpleInjector 使用 AsyncScopedLifestyle 解决依赖关系,因为我已经在我的配置中配置了它。
我使用这个 Github link 找到了答案。我所做的是将我的异步方法包装在异步范围内并解决该范围内的依赖关系并且它有效。
这是更新后的代码。
public class ComputationService
{
private IBaseRepository<User> _userRepo;
public void Do(int id)
{
using(AsyncScopedLifestyle.BeginScope(SimpleInjectorIntegrator.Container))
{
_userRepo = = SimpleInjectorIntegrator.Container.GetInstance<User>();
var user = _userRepo.Get(id); //works fine.
}
}
}
我所做的另一项更改是在我的 SimpleInjectorIntegrator
class.