Unity and Constructor Parameters - always default instance

Mar 5, 2009 at 4:14 PM
My understanding of unity is that there is currently no way to define constructor parameters at runtime if you are using unity.

Meaning, doing this:

Resolve<UserManager>();  //this gives me a default UserManager class

Or when I register the UserManager type, I can define hardcoded design time parameters for the constructor, like this:

RegisterType<IUserManager, UserManager>( new InjectionConstructor( userSecurity ));

However, if the userSecurity instance parameter must change for each method call, then there is no way to pass it in the constructor using unity.  Is this correct?

What patterns exist as alternatives?  Here is my example:

public void DoSomeWork(UserSecurity userSecurity)
{
       IUserManager u = new UserManager( userSecurity );
       u.DoSomeWork();
}

I could put the userSecurity as a param to all methods since all UserManager methods would require the userSecurity, but I figured that made it a good candidate for the constructor.

thoughts?


Mar 9, 2009 at 2:59 PM
bump?
Mar 10, 2009 at 4:58 PM
The following code will work: 

            IUnityContainer c = new UnityContainer();

            c.RegisterInstance<UserSecurity>(new UserSecurity());

            UserManager u = c.Resolve<UserManager>();

            u.DoSomeWork();


The container resolves userSecurity parameter in UserManager constructor without any additional configuring.

 

 

 

 

Mar 10, 2009 at 5:09 PM
Thanks for your reply.  That is an interesting approach I hadn't tried.

I am wondering, though, about thread safety.  We initialize our container at application start, whereas the UserSecurity instance would apply only to the current user for the current request.

I haven't tested this, but I assume that calling RegisterInstance would be global in the container so other threads (user requests) running at the same time would pull this users UserSecurity instance out of the container as well, or, would overwrite my instance with their own when they in turn called RegisterInstance?

Is that right or am I missing something?
Mar 10, 2009 at 5:17 PM

That will be global.

You can spin up a child container for every request if you need separate UserSecurity instances:

            // create root container once

            IUnityContainer c = new UnityContainer();

 

            // create a child container and shove up UserSecurity instance per each call

            IUnityContainer child = c.CreateChildContainer();

            child.RegisterInstance<UserSecurity>(new UserSecurity());

            UserManager u = child.Resolve<UserManager>();

            u.DoSomeWork();

 

 

 
Mar 10, 2009 at 5:34 PM
hmm, interesting.  I guess I would have to keep track of the child container somehow... with a name or a userId, in order to be able to resolve an instance from the correct child container.  And if I had 100 users on the site at once, I would have 100 child containers.

Perhaps passing it to each method is the best approach after all.  My initial thought was something like this.

WCF Service Method accepts UserSecurity object as method param, then stores it some global location
Business Manager in business layer pulls the UserSecurity object out of global storage when/if needed
DAL pulls UserSecurity object out of global storage when/if needed.

I was only thinking global storage to clean up the method signatures and remove the UserSecurity parameter.  Why pass a param if it is needed in every method?  However, the possible answer to that is because, the UserSecurity parameter is different for every user (but the same for a given thread/request until the request completes).

Mar 10, 2009 at 5:45 PM
Edited Mar 10, 2009 at 5:52 PM
I do not think you have to keep track of the child containers at all - they are not needed after UserSecurity parameter is resolved and they (child containers) will be garbage collected after they come out of the scope.

Of course it only makes sense if  UserSecurity is different for different users - otherwise you should be just fine with registering single instnce in the root container. It would be a "global storage" holding the UserSecurity instance for all user requests.