Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Ninject 2.0, how do I have both a general binding and a binding for a specific case?

I have a situation where I want to dependency inject my user object, but also place the current user in the IoC container. I want the following lines to work:

kernel.Get<User>(); // Should return a new User()
kernel.Get<User>("Current"); // Should return the current user

One might think bindings like this would work:

Bind<User>().ToSelf();
Bind<User>().ToMethod(LoadCurrentUser).InRequestScope().Named("Current");

Of course, that gives:

Ninject.ActivationException: Error activating User
More than one matching bindings are available.
Activation path:
1) Request for User

Suggestions:
1) Ensure that you have defined a binding for User only once.

I understand the error since a Named binding does not restrict the application of that binding, so both bindings apply. It seems clear that I need to use the contextual bind with the .When*() methods but I can't come up with any way to do that. I feel like there should be when methods that detect whether a named instance is applied. Something like:

// Not valid Ninject syntax
Bind<User>().ToSelf().WhenUnnamedRequested();
Bind<User>().ToMethod(LoadCurrentUser).WhenNamedRequested().InRequestScope().Named("Current");

I can't find any place on the IRequest interface or it's properties that tells me the name requested. How do I do this?

like image 837
Jeff Walker Code Ranger Avatar asked Sep 09 '10 14:09

Jeff Walker Code Ranger


1 Answers

This question was answerd on the mailing list: http://groups.google.com/group/ninject/browse_thread/thread/cd95847dc4dcfc9d?hl=en


If you are accessing the user by calling Get on the kernel (which I hope you do not) then give the first binding a name as well and access User always by name. Actually, there is a way to get an instance from the binding without a name. But because I heartily recommend not to do this, I do not show how to to this here. If you still want to do it this way I'll tell you later how this would work.

If you are doing it the better and prefered way and inject the user to the objects that require it as dependency there are two options:

  1. The easier one: Give the first binding a name and add a named attribute to the parameters e.g. ctor([Named("NewUser") IUser newUser, [Named("Current")] IUser currentUser)
  2. Or the prefered way to keep the implementation classes free of the IoC framework: Specify custom attributes and add them to the parameters e.g. ctor([NewUser] IUser newUser, [CurrentUser]IUser currentUser). Change the Bindings to:

    Bind<User>().ToSelf()
                .WhenTargetHas<NewUserAttribute>();
    Bind<User>().ToMethod(LoadCurrentUser)
                .InRequestScope()
                .WhenTargetHas<CurrentUserAttribute>();
    
like image 160
Remo Gloor Avatar answered Sep 22 '22 01:09

Remo Gloor