简体   繁体   中英

Castle Windsor scoped life style fails to register per scope

I am using a framework that allow me to intercept in some entry points.
The framework scope is not Web Request, not thread and not transient, its something like thread based, but i saw a lot of places with thread reuse.
So i need a custom scope, where i say where to start and where to end the scope.
Since I have a lot of dependencies, most of them are defined in static contractor, because they are stateless.
I have one dependency that actually need to be injected on every framework interception.

This is the interception method, and how I do the injection (I am not calling this method, the framework does). So what i need here is to inject the AppContext and make sure that Castle always resolve me the correct context (within the scope)

public void Execute(AppContext context)
{

    using (var s = CastleContainer.Container.BeginScope())
    {
        CastleContainer.Container.Register(Component.For<AppContext>().LifestyleScoped().Instance(context));
        var logic = CastleContainer.Container.Resolve<ICustomerLogic>();
        // begin invocation
    }
}

ICustomerLogic has dependency in ICustomreDal and ICustomreDal has dependency in AppContext .

So when I resolve Resolve<ICustomerLogic>() I want to be sure that ICustomreDal has the current AppContext .

ICustomerLogic and registered as singleton, and ICustomreDal registered as transient.

The first execution works fine, the second execution I get the error:

AppContext could not be registered. There is already a component with that name. Did you want to modify the existing component instead? If not, make sure you specify a unique name.

Isn't castle suppose to do the scope segmentation so each scope has its own dependencies?
What am I doing wrong?

Please note that we are talking about 50 executions in a second.

The BeginScope is not about registration, it is only about component resolving. It will make sure that any component that is created within the using statment, with lifestyle Scoped gets released (disposed if necessary) when the using statements end. It does not unregister components that are registered in the block. In general it is a bad idea to register your components in multiple places. Only register components at the startup of your application.

I've been struggling a lot with something similair and finally used this workaround with I was not totally happy with but if there is anyone with a better solution I would love to hear. Adapted to your situation it would look something like this:

in your registration code use:

Component.For<ICustomerLogic>().ImplementedBy<CustomerLogic>().LifestyleScoped
Component.For<AppContext >().UsingFactoryMethod(() => (AppContext)Thread.GetNamedDataSlot("context")).LifestyleTransient() // or scoped

adapt your Execute function to:

public void Execute(AppContext context)
{
    using (var s = CastleContainer.Container.BeginScope())
    {
        Thread.SetData(Thread.GetNamedDataSlot("context"), context);
        var logic = CastleContainer.Container.Resolve<ICustomerLogic>();
        Thread.SetData(Thread.GetNamedDataSlot("context"), null);
        // begin invocation
    }
} 

Goodluck,

Marwijn.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM