CastleWindsor LifeStyle.PerWebRequest的行为类似于单身

时间:2016-01-20 12:20:15

标签: c# asp.net-mvc dependency-injection castle-windsor

我正在尝试创建一个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();
    }
}

当我调试我的代码时,我可以在第一个请求中看到我正确启动它创建类UserService.cs然后在webrequest之后处理它。现在我的问题是第二个Web请求似乎不再调用构造函数,因此只是重用以前创建的对象。这导致DatabaseContext已被处置。

我认为LifestylePerWebRequest意味着每次请求都会重新创建UserService。任何人都可以帮我理解这个吗?

3 个答案:

答案 0 :(得分:0)

首先,我忽略了文档中的“模块注册”部分。您需要将以下内容添加到web.config:

<httpModules>
   <add name="PerRequestLifestyle" type="Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule, Castle.Windsor"/>
</httpModules>

其次,我并不百分之百确定依赖解析器是如何工作的。问题是使用我的UserService作为依赖项的模块之一的生命周期设置为Singleton,当您在使用容器注册模块时未指定生命周期时,这是默认行为。

我通过确保使用我的UserService作为依赖项的每个模块的注册生命周期为LifestylePerWebRequest()LifestyleTransient()来解决问题。

答案 1 :(得分:0)

您应该仔细检查是否有任何其他使用IUserService的界面会覆盖生活方式。 在这种情况下,Castle windsor不会为每个请求解析IUserService,因为ITest设置为singleton。

例如

 _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;
    }
}

答案 2 :(得分:0)

我有一个实现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();
        }
    }