The following code is for demo purposes only.
Lets say i have 2 components (businessService, and dataService), and a UI class.
UI class needs a business service, businessService needs a dataService, and dataService relies on a connectionString.
Form the UI class i need to resolve the business service, so i am writing the below code:
var service = container.Resolve<BusinessService>(new { dependancy = "con string 123" }));
notice that dependancy is the connectionString constructor parameter.
But the above code is not working, saying that dataService expecting dependancy which was not satisified.
Can't create component 'dataService' as it has dependencies to be satisfied. dataService is waiting for the following dependencies:
Keys (components with specific keys) - dependancy which was not registered.
So as a workaround i am doing this:
var service = container.Resolve<BusinessService>(new { dataService = container.Resolve<IDataService>(new { dependancy = "123" }) });
But from design, coding style and many perspectives this is not a good way of doing it.
So please if you can advise why its not working in the simple way or you have a better workaround please share.
The behavior you see is by design.
There are a couple of ways to approach the problem, depending on how dynamic the value you want to pass down is.
The documentation does a pretty good job detailing it, so I won't reiterate that here.
Update
To clarity - Windsor does not pass inline arguments down the resolution pipeline. The reason for that is simple - doing so would break an abstraction. Calling code would have to implicitly know that your BusinessService
depends on DataService
which depends on connection string.
If you absolutely have to do it, than do make this explicit. That is do pretty much what you're doing - resolve the DataService
with its dependency on connection string explicitly, and explicitly resolve BusinessService
passing the DataService
as dependency.
To make things really explicit (and nicer to use as well) I'd suggest using Typed Factory for that instead of directly calling the container
public interface IFactory
{
IDataService ResolveDataService(string connectionString);
IBussinessService ResolveBussinessService(IDataService dataService);
// possibly release method for IBussinessService as well
}
I have needed to do this when creating transient components that require a context object. The solution I used was to override the DefaultDependencyResolver
class so that it does pass inline arguments down the resolution pipeline.
public class ArgumentPassingDependencyResolver : DefaultDependencyResolver
{
protected override CreationContext RebuildContextForParameter(
CreationContext current, Type parameterType)
{
if (parameterType.ContainsGenericParameters)
{
// this behaviour copied from base class
return current;
}
// the difference in the following line is that "true" is passed
// instead of "false" as the third parameter
return new CreationContext(parameterType, current, true);
}
}
An instance of this class needs to be passed in when the container is created (other classes also need to be passed in because there's no convenient constructor that only takes a dependency resolver):
var container = new WindsorContainer(
new DefaultKernel(
new ArgumentPassingDependencyResolver(),
new NotSupportedProxyFactory()),
new DefaultComponentInstaller());
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With