ComponentResolutionException after upgrade to Castle 3.0

85 views
Skip to first unread message

Fabrice

unread,
May 14, 2012, 9:04:23 AM5/14/12
to castle-pro...@googlegroups.com

Hello,

I've a problem with WcfPerOperation lifestyle after upgraded my project from Castle 2.5.2 to Castle 3.0
I've posted on StackOverflow and only after I thinked it could be better to post here...

But anyway here is the link: http://stackoverflow.com/questions/10579236/componentresolutionexception-after-upgrading-to-castle-3-0

Thank you for any help!
Fabrice

Craig Neuwirt

unread,
May 17, 2012, 11:07:50 AM5/17/12
to castle-pro...@googlegroups.com
I don't believe an OperationContext.Current is available at the point where a custom UserNamePasswordValidator is called.  This could be why no scope could be obtained.  Is it possible to choose  a different lifestyle.

-craig

--
You received this message because you are subscribed to the Google Groups "Castle Project Users" group.
To post to this group, send email to castle-pro...@googlegroups.com.
To unsubscribe from this group, send email to castle-project-u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/castle-project-users?hl=en.

Fabrice

unread,
May 17, 2012, 11:15:12 AM5/17/12
to castle-pro...@googlegroups.com
I was just replying to my own message when I see your answer :-)

Indeed I just finished a test project and it only happend if the component is resolved in the IAuthorizationPolicy (or I suppose also in the Validator). It works fine if used in the operation method.
Is it a bug ? do you want the test project ?

In fact how could I configure the container so that some specific component (the Validator) use Transient lifestyle, and all other use PerWcfOperation ? I really need to use a PerWcfOperation to avoid db lock when several component update the db. In this case, they all share the same connection, otherwise (Transient) they all have a different connection and lock each other.

Is it possible to create a custom lifestyle that try a PerWcfOperation and, if it doesn't works, fall back on the Transient lifestyle ?

Thank you for your help
Fabrice

Fabrice

unread,
May 17, 2012, 11:23:53 AM5/17/12
to castle-pro...@googlegroups.com
And I can confirm that OperationContext.Current is null

What's strange is that it works fine with Castle 2.5 ... this version may fall back on a Transient lifestyle if OperationContext.Current is null ?

Craig Neuwirt

unread,
May 17, 2012, 11:28:24 AM5/17/12
to castle-pro...@googlegroups.com
On May 17, 2012, at 10:15 AM, Fabrice wrote:

I was just replying to my own message when I see your answer :-)

Indeed I just finished a test project and it only happend if the component is resolved in the IAuthorizationPolicy (or I suppose also in the Validator). It works fine if used in the operation method.
Is it a bug ? do you want the test project ?

This is the expected behavior


In fact how could I configure the container so that some specific component (the Validator) use Transient lifestyle, and all other use PerWcfOperation ? I really need to use a PerWcfOperation to avoid db lock when several component update the db. In this case, they all share the same connection, otherwise (Transient) they all have a different connection and lock each other.

Is it possible to create a custom lifestyle that try a PerWcfOperation and, if it doesn't works, fall back on the Transient lifestyle ?

It is certainly possible to do that and off the top of my head, I believe the prior version did that.  As mentioned above, that is the wrong behavior since it would be inconsistent.
What I currently do is register the components with the general Scoped lifestyle and explicitly control the boundary of the scope.  The Container/Kernel has a BeginScope extension method which will start the scope and on disposal remove it.   I then put hooks in ASP.NET to begin the scope.     I use that option to control my data access as well.

Fabrice

unread,
May 17, 2012, 12:41:26 PM5/17/12
to castle-pro...@googlegroups.com
On Thu, May 17, 2012 at 5:28 PM, Craig Neuwirt <cneu...@gmail.com> wrote:

It is certainly possible to do that and off the top of my head, I believe the prior version did that.  As mentioned above, that is the wrong behavior since it would be inconsistent.
What I currently do is register the components with the general Scoped lifestyle and explicitly control the boundary of the scope.  The Container/Kernel has a BeginScope extension method which will start the scope and on disposal remove it.   I then put hooks in ASP.NET to begin the scope.     I use that option to control my data access as well.


I can't use BeginScope because I don't have a strong reference to castle, my application only use a IServiceProvider ... so I would like to only use registration/configuration and let the component resolution as it is now.

I've searched on how to create a custom lifestyle, but all sample I've found is for previous Castle version
The best will be to use a sort of Composite lifestyle that take a main lifestyle and one (or several) fallback lifestyle. It'll better to not rewrite existing stuff (like PerWcfOperation & Transient) and instead reuse it.
Do you have any tips on how to do that ?

I've tried to understand the code available in https://github.com/castleproject/Castle.Facilities.Wcf-READONLY/tree/master/src/Castle.Facilities.WcfIntegration/Lifestyles but I'm not sure it's the latest code for Castle 3 ?

Thanks for your help
Fabrice

Craig Neuwirt

unread,
May 17, 2012, 1:11:13 PM5/17/12
to castle-pro...@googlegroups.com
The current code is at g...@github.com:castleproject/Windsor.git


On May 17, 2012, at 11:41 AM, Fabrice wrote:



On Thu, May 17, 2012 at 5:28 PM, Craig Neuwirt <cneu...@gmail.com> wrote:

It is certainly possible to do that and off the top of my head, I believe the prior version did that.  As mentioned above, that is the wrong behavior since it would be inconsistent.
What I currently do is register the components with the general Scoped lifestyle and explicitly control the boundary of the scope.  The Container/Kernel has a BeginScope extension method which will start the scope and on disposal remove it.   I then put hooks in ASP.NET to begin the scope.     I use that option to control my data access as well.


I can't use BeginScope because I don't have a strong reference to castle, my application only use a IServiceProvider ... so I would like to only use registration/configuration and let the component resolution as it is now.

I've searched on how to create a custom lifestyle, but all sample I've found is for previous Castle version
The best will be to use a sort of Composite lifestyle that take a main lifestyle and one (or several) fallback lifestyle. It'll better to not rewrite existing stuff (like PerWcfOperation & Transient) and instead reuse it.
Do you have any tips on how to do that ?


You wouldn't necessarily need a new Lifestyle in this case, but a custom IScopeAccessor.  The WcfOperationScopeAccesor used OperationContext.Current to stash the scope.  You could implement your own IScopeAccessor (tiny interface) that accepts another accessor and if returns null Scope return a [ThreadStatic] DefaultifetimeScope.  Of course, this will not be properly disposed and it will return a different instance than the one when the OperationContext.Current is available


I've tried to understand the code available in https://github.com/castleproject/Castle.Facilities.Wcf-READONLY/tree/master/src/Castle.Facilities.WcfIntegration/Lifestyles but I'm not sure it's the latest code for Castle 3 ?

Thanks for your help
Fabrice

Craig Neuwirt

unread,
May 17, 2012, 1:12:33 PM5/17/12
to castle-pro...@googlegroups.com
You would then use

registration.LifeStyle.Scoped<YourScopeAccessor>();

to register your component
On May 17, 2012, at 11:41 AM, Fabrice wrote:

Fabrice

unread,
May 17, 2012, 3:23:53 PM5/17/12
to castle-pro...@googlegroups.com
Here is an implementation that works, thank you for the tips

I've one question : Is it correct to create a DefaultLifetimeScope, or there is a way to retrieve one already created ? (See my implementation below) Because you write [ThreadStatic] so I put it as a static property.

Also, I didn't find a way to make a generic scope that take a base scope (WcfOperationScopeAccessor) and a fallback scope, because when registering the component I didn't find a way to register the scope accessor with an existing object:
            return componentRegistration.LifestyleScoped<WcfOperationOrTransientScopeAccessor>();
It could be useful to register like this:
            var scopeAccessor = new GenericScopeWithFallback<WcfOperationOrTransientScopeAccessor>(new DefaultLifetimeScope());
            return componentRegistration.LifestyleScoped(scopeAccessor);
But anyway, it's not very important as it's just an easier way, and I think I could also make it something like this but I've not yet tried
            return componentRegistration.LifestyleScoped<WcfOperationOrTransientScopeAccessor<DefaultLifetimeScope>>();

My implementation:
    public class WcfOperationOrTransientScopeAccessor : IScopeAccessor
    {
        #region Declarations
        private static DefaultLifetimeScope _defaultLifetimeScope;
        private WcfOperationScopeAccessor _wcfOperationScopeAccessor; 
        #endregion
 
        #region Properties
        protected static DefaultLifetimeScope DefaultLifetimeScope
        {
            get
            {
                if (_defaultLifetimeScope == null)
                    _defaultLifetimeScope = new DefaultLifetimeScope();
                return _defaultLifetimeScope;
            }
        }
 
        protected WcfOperationScopeAccessor WcfOperationScope
        {
            get
            {
                if (this._wcfOperationScopeAccessor == null)
                    this._wcfOperationScopeAccessor = new WcfOperationScopeAccessor();
                return this._wcfOperationScopeAccessor;
            }
        } 
        #endregion
 
        #region IScopeAccessor implementation
        public ILifetimeScope GetScope(CreationContext context)
        {
            var wcfScope = this.WcfOperationScope.GetScope(context);
            if (wcfScope != null)
                return wcfScope;
            return DefaultLifetimeScope;
        }
 
        public void Dispose()
        {
            this.WcfOperationScope.Dispose();
        } 
        #endregion
    }

Craig Neuwirt

unread,
May 17, 2012, 3:42:56 PM5/17/12
to castle-pro...@googlegroups.com
On May 17, 2012, at 2:23 PM, Fabrice wrote:

Here is an implementation that works, thank you for the tips

I've one question : Is it correct to create a DefaultLifetimeScope, or there is a way to retrieve one already created ? (See my implementation below) Because you write [ThreadStatic] so I put it as a static property.

Since in that scenario, their is no well defined scope boundary, I just picked thread static since your data access component cannot be shared on a thread.  You can obtain the scope any way you like.  Again, the problem is that scope will never be disposed so if you component has lifecycle concerns (disposable), they wont be called


Also, I didn't find a way to make a generic scope that take a base scope (WcfOperationScopeAccessor) and a fallback scope, because when registering the component I didn't find a way to register the scope accessor with an existing object:
            return componentRegistration.LifestyleScoped<WcfOperationOrTransientScopeAccessor>();
It could be useful to register like this:
            var scopeAccessor = new GenericScopeWithFallback<WcfOperationOrTransientScopeAccessor>(new DefaultLifetimeScope());
            return componentRegistration.LifestyleScoped(scopeAccessor);
But anyway, it's not very important as it's just an easier way, and I think I could also make it something like this but I've not yet tried
            return componentRegistration.LifestyleScoped<WcfOperationOrTransientScopeAccessor<DefaultLifetimeScope>>();
you could add extension methods to do just that.   I suspect what is needed is an extension method that takes an accessor instance.
looks ok

good luck

Fabrice

unread,
May 17, 2012, 5:29:50 PM5/17/12
to castle-pro...@googlegroups.com

Since in that scenario, their is no well defined scope boundary, I just picked thread static since your data access component cannot be shared on a thread.  You can obtain the scope any way you like.  Again, the problem is that scope will never be disposed so if you component has lifecycle concerns (disposable), they wont be called 

But when using Transient, the component is correctly disposed ? If I correctly understood the Transient lifestyle, Castle doesn't keep a reference to the created object so this object is disposed when GC run, isn't ?
There is no way to achieve the same behaviour here ?

Craig Neuwirt

unread,
May 18, 2012, 7:36:49 AM5/18/12
to castle-pro...@googlegroups.com
On May 17, 2012, at 4:29 PM, Fabrice wrote:


Since in that scenario, their is no well defined scope boundary, I just picked thread static since your data access component cannot be shared on a thread.  You can obtain the scope any way you like.  Again, the problem is that scope will never be disposed so if you component has lifecycle concerns (disposable), they wont be called 

But when using Transient, the component is correctly disposed ? If I correctly understood the Transient lifestyle, Castle doesn't keep a reference to the created object so this object is disposed when GC run, isn't ?

Not quite, if you're a Transient and have lifecycle concerns (IDisposable) the container will track you so when you call Release it can execute those concerns.   Since you don't have access to container in your component, you will not be able to call Release so it will be a leak.


There is no way to achieve the same behaviour here ?

Fabrice

unread,
May 19, 2012, 9:25:10 AM5/19/12
to castle-pro...@googlegroups.com
Just for info, I've found a nice project "Castle contrib" that contains several "hybrid" scope accessor (and is actively maintained and updated for Castle 3)

https://github.com/castleprojectcontrib/Castle.Windsor.Lifestyles/tree/master/Castle.Windsor.Lifestyles
Reply all
Reply to author
Forward
0 new messages