CastleWindsor LifeStyle.PerWebRequest 表现得像单例
CastleWindsor LifeStyle.PerWebRequest behaves like singleton
我正在尝试创建一个我可以注入我的 classes 的 UserService,它将保存当前登录到我的系统的用户。
我正在使用 CastleWindsor 作为我的容器。
现在我的问题是我试图让我的 UserService 成为一次性的,这样在对象被销毁时,在创建时获取用户的数据库连接也会被丢弃。
我在 Global.asax.cs 中添加了以下设置:
private static void BootstrapContainer()
{
_container = new WindsorContainer().Install(FromAssembly.This());
var controllerFactory = new WindsorControllerFactory(_container.Kernel);
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
GlobalConfiguration.Configuration.DependencyResolver = new WindsorDependencyResolver(_container.Kernel);
_container.Register(Component.For<IUserService>()
.LifestylePerWebRequest()
.ImplementedBy<UserService>());
_container.Register(Component.For<IPrincipal>()
.LifeStyle.PerWebRequest
.UsingFactoryMethod(() => HttpContext.Current.User));
}
在我的 Application_Start
.
中调用
我的UserService代码如下:
public interface IUserService
{
OrganisationBruger User { get; }
int UserId { get; }
}
public class UserService : IUserService, IDisposable
{
private readonly IPrincipal _principal;
private OrganisationBruger _user;
private readonly DatabaseDataContext _db;
public UserService(IPrincipal principal, IDatabaseDataContextFactory dataContextFactory)
{
_principal = principal;
_db = dataContextFactory.GetDataContext();
}
public OrganisationBruger User => _user ?? (_user = GetUser());
public int UserId => Convert.ToInt32(_principal.Identity.Name);
private OrganisationBruger GetUser()
{
return _db.OrganisationBrugers.Single(u => u.ID == UserId);
}
public void Dispose()
{
_db.Dispose();
}
}
当我调试我的代码时,我可以在第一个请求中看到我触发它正确地创建了 class UserService.cs
,然后在 web 请求之后处理它。现在我的问题是第二个 Web 请求似乎不再调用构造函数,因此只是重用以前创建的对象。这导致 DatabaseContext
已经被处理掉。
我认为 LifestylePerWebRequest
意味着 UserService
会根据每个请求重新创建。谁能帮我理解这个?
所以首先我忽略了文档中的 "registration of the module" 部分。您需要将以下内容添加到 web.config:
<httpModules>
<add name="PerRequestLifestyle" type="Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule, Castle.Windsor"/>
</httpModules>
其次,我不是百分百确定依赖解析器是如何工作的。问题是使用我的 UserService
作为依赖项的模块之一将其生命周期设置为 Singleton
这是默认行为,当您在容器中注册模块时未指定任何关于生命周期的信息。
我通过确保使用我的 UserService 作为依赖项的每个模块也注册了 LifestylePerWebRequest()
或 LifestyleTransient()
.
的生命周期来解决问题
你应该仔细检查你是否有任何其他接口使用 IUserService 覆盖生活方式。
在那种情况下,Castle windsor 将不会为每个请求解析 IUserService,因为 ITest 设置为单例。
例如
_container.Register(Component.For<ITest>()
.LifestyleSingleton()
.ImplementedBy<Test>());
public interface ITest
{
}
public class Test: ITest
{
private readonly IUserService _ser;
public Test(IUserService ser)
{
_ser= ser;
}
}
我有一个实现了 IHttpControllerActivator 的 WindsorHttpControllerActivator。它注册控制器以进行处置,以确保通过销毁旧控制器在每个请求上创建一个新控制器。这发生在 .LifestylePerWebRequest() 完成每个请求时。
public IHttpController Create(
HttpRequestMessage request,
HttpControllerDescriptor controllerDescriptor,
Type controllerType)
{
var controller =
(IHttpController)_container.Resolve(controllerType);
// Controller disposal ensures new controller for each request, hence DbContexts are fresh and pull fresh data from the DB.
request.RegisterForDispose(
new Release(
() => _container.Release(controller)));
return controller;
}
private class Release : IDisposable
{
private readonly Action _release;
public Release(Action release)
{
_release = release;
}
public void Dispose()
{
_release();
}
}
我正在尝试创建一个我可以注入我的 classes 的 UserService,它将保存当前登录到我的系统的用户。 我正在使用 CastleWindsor 作为我的容器。
现在我的问题是我试图让我的 UserService 成为一次性的,这样在对象被销毁时,在创建时获取用户的数据库连接也会被丢弃。
我在 Global.asax.cs 中添加了以下设置:
private static void BootstrapContainer()
{
_container = new WindsorContainer().Install(FromAssembly.This());
var controllerFactory = new WindsorControllerFactory(_container.Kernel);
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
GlobalConfiguration.Configuration.DependencyResolver = new WindsorDependencyResolver(_container.Kernel);
_container.Register(Component.For<IUserService>()
.LifestylePerWebRequest()
.ImplementedBy<UserService>());
_container.Register(Component.For<IPrincipal>()
.LifeStyle.PerWebRequest
.UsingFactoryMethod(() => HttpContext.Current.User));
}
在我的 Application_Start
.
我的UserService代码如下:
public interface IUserService
{
OrganisationBruger User { get; }
int UserId { get; }
}
public class UserService : IUserService, IDisposable
{
private readonly IPrincipal _principal;
private OrganisationBruger _user;
private readonly DatabaseDataContext _db;
public UserService(IPrincipal principal, IDatabaseDataContextFactory dataContextFactory)
{
_principal = principal;
_db = dataContextFactory.GetDataContext();
}
public OrganisationBruger User => _user ?? (_user = GetUser());
public int UserId => Convert.ToInt32(_principal.Identity.Name);
private OrganisationBruger GetUser()
{
return _db.OrganisationBrugers.Single(u => u.ID == UserId);
}
public void Dispose()
{
_db.Dispose();
}
}
当我调试我的代码时,我可以在第一个请求中看到我触发它正确地创建了 class UserService.cs
,然后在 web 请求之后处理它。现在我的问题是第二个 Web 请求似乎不再调用构造函数,因此只是重用以前创建的对象。这导致 DatabaseContext
已经被处理掉。
我认为 LifestylePerWebRequest
意味着 UserService
会根据每个请求重新创建。谁能帮我理解这个?
所以首先我忽略了文档中的 "registration of the module" 部分。您需要将以下内容添加到 web.config:
<httpModules>
<add name="PerRequestLifestyle" type="Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule, Castle.Windsor"/>
</httpModules>
其次,我不是百分百确定依赖解析器是如何工作的。问题是使用我的 UserService
作为依赖项的模块之一将其生命周期设置为 Singleton
这是默认行为,当您在容器中注册模块时未指定任何关于生命周期的信息。
我通过确保使用我的 UserService 作为依赖项的每个模块也注册了 LifestylePerWebRequest()
或 LifestyleTransient()
.
你应该仔细检查你是否有任何其他接口使用 IUserService 覆盖生活方式。 在那种情况下,Castle windsor 将不会为每个请求解析 IUserService,因为 ITest 设置为单例。
例如
_container.Register(Component.For<ITest>()
.LifestyleSingleton()
.ImplementedBy<Test>());
public interface ITest
{
}
public class Test: ITest
{
private readonly IUserService _ser;
public Test(IUserService ser)
{
_ser= ser;
}
}
我有一个实现了 IHttpControllerActivator 的 WindsorHttpControllerActivator。它注册控制器以进行处置,以确保通过销毁旧控制器在每个请求上创建一个新控制器。这发生在 .LifestylePerWebRequest() 完成每个请求时。
public IHttpController Create(
HttpRequestMessage request,
HttpControllerDescriptor controllerDescriptor,
Type controllerType)
{
var controller =
(IHttpController)_container.Resolve(controllerType);
// Controller disposal ensures new controller for each request, hence DbContexts are fresh and pull fresh data from the DB.
request.RegisterForDispose(
new Release(
() => _container.Release(controller)));
return controller;
}
private class Release : IDisposable
{
private readonly Action _release;
public Release(Action release)
{
_release = release;
}
public void Dispose()
{
_release();
}
}