简体   繁体   中英

Castle.Windsor and dynamic injection using calling method parameters values

I have a class library:

 public class SomeBL : ISomeBL
 {
    private IUser myUser;
    public SomeBL(IUser user)
    {
      myUser = user;
    }
    public void TestMethod()
    {
       ...some code using the user...
    }
 }

I also have a factory in this code library:

public class BLFactory
{
    public static ISomeBL SomeBL
    {
        get { return ServiceLocator.Current.GetInstance<ISomeBL>(); }
    }
}

Then I have a separate wcf application with one service that looks like this:

public class MyWcfService : IMyWcfService
{
       public void TestMethod(User user)
       {
            BLFactory.SomeBL.TestMethod();
       }
}

As you can see I am in need of IoC to properly resolve the IUser property on the SomeBL constructor level. I also don't want to pass it explicitly.

I was wondering if it's possible to configure Windsor in such a way that IUser will be resolved dynamically using value from the wcf service method's parameter ?

ps Let's forget about wcf's inability to pass interfaces for a moment.

Edit#1 I solved it using Castle Project's Wcf Facility. Smooth as silk after I added it!

Based on the way you have things set up, and with your conditions I don't see how it's possible. There is no way for the container to "just know" the context by configuration.

However, I see a few options.

The first is to make your BLFactory a proper abstract factory, and pass the user to its Create method:

public class BLFactory  
{  
    public ISomeBL Create(IUser user)
    {              
        return new SomeBL(user);   
    }  
}  

You could also do this by calling Resolve<>() and passing the parameter there, or using Windsor's Typed Factory Facility. Referencing the container to directly resolve service in a factory class is generally not a good practice (see Three Calls Pattern ).

Second option would be to pass the user as a method parameter (although you said you don't want to do this):

 public class SomeBL : ISomeBL        
 {        
    public void TestMethod(IUser user)        
    {        
       ...some code using the user...        
    }        
 }   

This makes SomeBL more of a pure service (stateless), which IMHO is more along the lines of what DI and Windsor should be used for.

A final option assumes that the user represents the logged in user (if this is incorrect, ignore this option). Look at creating a service that returns the current logged-in user and inject that servce into your class. You would use some form of Ambient Context to store the user (on login or at some other point) and retrieve the user via this service.

 public class SomeBL : ISomeBL               
 {               
    private IUser _userservice;               
    public SomeBL(IUserService userservice)               
    {               
      _userservice = userservice;               
    }               
    public void TestMethod()               
    {               
       IUser currentUser = _userService.GetCurrentUser();
    }
 }

 public interface IUserService
 {
   IUser GetCurrentUser();
 }

 public class UserService : IUserService
 {
   public IUser GetCurrentUser
   {
      //pull user from Thread, HttpContext.CurrentRequest, cache, session, etc.
   }

 }

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