How do I control MembershipProvider instance creation/lifetime?
Asked Answered
L

2

6

I have registered a custom MembershipProvider class in my Web.Config file. I'm using Inversion Of Control using Castle Windsor and I have registered my custom MembershipProvider class as transient (because it's using a service that's transient as well).

This means that I want the Membership provider instance recreated on every web request. Currently, it is created only once per application domain so when it tries to access the service it depends on, that service instance is reused while it is not supposed to.

Now I need to find a way of having Windsor control the lifetime of my custom MembershipProvider but I don't know how. I expected a factory sitting around somewhere in the .NET Framework, allowing me to override the instance creation and rerouting it to Windsor but I can't find anything alike.

By the way, I'm using .NET 4.0.

UPDATE: Here's some of my code so you can see what I'm doing exactly:

Web.Config:

<membership defaultProvider="MyMembershipProvider" >
  <providers>
    <clear/>
    <add name="ApplicationMembershipProvider"
         type="MyNamespace.MyMembershipProvider, MyAssembly"/>
  </providers>
</membership>

Membership Provider

public class MyMembershipProvider : MembershipProvider
{
    private IMyService myService;

    public MyMembershipProvider() : base()
    {
        // We should use constructor injection here but since we cannot control
        // the construction of this class, we're forced to create the dependency
        // ourselves.
    }

    public override bool ValidateUser(string username, string password)
    {
        if (myService == null)
        {
            // This scope is only reached once within the browser session,
            // ASP.NET keeps the instance of MyMembershipProvider in memory
            // so the myService field keeps its value across web requests.
            // This results in Castle Windsor (which I have configured the service
            // locator to use) not being able to control the lifetime of
            // the MyService instance. So, the inability of Windsor to control
            // the lifetime of MembershipProvider instances, inhibits the lifetime
            // management of MyService instances as well.
            myService = ServiceLocator.Current.GetInstance<IMyService>();
        }

        return myService.ValidateUser(username, password);
    }
}
Langevin answered 16/11, 2010 at 11:6 Comment(6)
Can you elaborate on "control the lifetime"? What (concretely) do you want to achieve?Bloc
@Mauricio: I've updated my question accordingly (inserted a paragraph after the first).Hydride
I'm not sure I understand... if you've registered the component as transient it will be recreated every time, by definition... can you post your registration code?Bloc
@Mauricio, the object my MembershipProvider depends on, is (obviously) only recreated when my MembershipProvider is recreated and the latter is the thing that doesn't happen because the creation of MembershipProvider instances is beyond my control (nor Windsor's).Hydride
I'm afraid there's not much you can do about it. But post your code and we'll see.Bloc
@Mauricio, I've added some code. I've pointed out the exact problems in the inline remarks.Hydride
B
4

I just blogged about this with a solution.

In a nutshell, this solution involves a simple, reusable MembershipProvider that calls the container to resolve your custom MembershipProviders. Unlike other solutions that use "BuildUp" container features, this one takes true control of instantiation, thus enabling constructor injection (which in turn enables immutability) and proxyability.

Bloc answered 17/11, 2010 at 21:59 Comment(4)
I have one question though: what decision drives the choice between releasing or not releasing the container in the overridden WindsorMembershipProvider class members?Hydride
@Sandor: the resolved component is released in all methods. See devlicio.us/blogs/krzysztof_kozmic/archive/2010/08/27/… for rationale.Bloc
@Sandor: all provider methods call Release(), take a good look at the code.Bloc
Ah, I missed the WithService wrapper. Thanks!Hydride
P
2

Don't worry about your MembershipProvider lifetime. Simply manage the lifetime of the IMyService within the provider. Create a property for your IMyService with a getter, and return a new instance (or however you want to manage the lifetime) each time it is requested.

Pooka answered 16/11, 2010 at 18:57 Comment(4)
Thanks for your suggestion. My point however, is that I shouldn't be managing object lifetime at all but let Castle Windsor do that instead (Inversion of Control), based on the lifetime configuration I hand over to it.Hydride
Fine. You can do that. All from within your MembershipProvider class. Just have a property that returns a IMyservice -- and this will simply return whatever is returned from your IoC container.Pooka
Yeah but that would cause the service to be created every time the MembershipProvider is called within the same web request. I can live with that to a certain extent but the goal is to let Castle Windsor manage the lifetime and not me.Hydride
@Sandor: Pedro's solution is correct, you won't get a new instance every time, that's up to the service lifetime as registered in Windsor. Only if the service is a transient would you always get a new instance. In that case you could call the property once and cache the instance for the method call.Bloc

© 2022 - 2024 — McMap. All rights reserved.