CastleWindsor LifeStyle.PerWebRequest behaves like singleton

大憨熊 提交于 2020-01-03 17:04:27

问题


I am trying to create a UserService that I can inject in my classes, that will hold the user currently logged in to my system. I am using CastleWindsor as my container.

Now my problem is that I am trying to make my UserService disposable, so that the databaseconnection fetching the user on creating will also be disposed when the object is destroyed.

I added the following setup in my 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));
}

Which is called in my Application_Start.

My UserService code is as follows:

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();
    }
}

When I Debug my code I can see on the very first request I fire it correctly creates the class UserService.cs and then disposes it after the webrequest. Now my problem is the second web request does not seem to call the constructor anymore thus just reusing the formerly created object. This leads to the DatabaseContext already being disposed of.

I thought that LifestylePerWebRequest meant that the UserService would get recreated on every request. Can anyone help me understand this?


回答1:


So first of all I had overlook the "registration of the module"-part in the documentation. You need to add the following to your web.config:

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

Second of all I was not a hundred percent sure how the dependency resolver worked. The problem was that one of the modules using my UserService as a dependency had its lifecycle set to Singleton which is default behavior when you specify nothing about the lifecycle when registering your module with the container.

I fixed the problem by making sure that every module that is using my UserService as dependency is also registered with a lifecycle of LifestylePerWebRequest() or LifestyleTransient().




回答2:


You should double check if you have any other interface which use IUserService overwrites the lifestyle. In that case, Castle windsor will not resolve IUserService for each request because ITest is set to singleton.

For example

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



回答3:


I have a WindsorHttpControllerActivator that implements IHttpControllerActivator. It registers the controller for disposal which ensures a new controller gets created on each request by destroying the old one. This occurs when .LifestylePerWebRequest() completes each request.

        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();
        }
    }


来源:https://stackoverflow.com/questions/34899924/castlewindsor-lifestyle-perwebrequest-behaves-like-singleton

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!