Setup
Lets create a quick and simple CSLA Customer class that implements a simple ICustomer interface:
If we want Unity to resolve a new Customer then we can simply do the following:
And the hard coded name "New Andreas" should appear in your console/output window.
Passing parameters to the static factory methods
This is fairly simple if your factories do not accept any parameters but is a bit trickier otherwise. Customer has also got a GetCustomer method which accepts an Id integer. One way of getting around this is to create a dedicated factory which we could call directly or inject into our container. In general though this adds an extra class (and potentially interface), which would be nice to avoid. So instead, we will add a delegate factory to our Customer class:
The delegate will serve a dual purpose here. First, it will be the factory that will be injected into the container and secondly, it will be responsible for either creating a new or fetching an existing customer, depending on weather the id parameter is empty or not. Back to our container setup:
And yep, you guessed it right. The output is:
Id:-1, Name:New Andreas
Id:3, Name:Old Andreas
Can I have a more real world example please?
That would be a bit too far fetched, but lets see how we could use this in conjunction with a ViewModelBase
To start off with, we add the constructor and properties:
Instead of calling the DoRefresh method on the ViewModel base class, we will assume control of loading the Model. This is done in the OnContextChanged handler (which is very similar to the implementation of BeginRefresh in the base class):
So now, when resolving a ViewModel:
And you can see the result on the console is what we expected it to be.
There are some parts of this solution which are not elegant. The DynamicInvoke call is a bit fragile and the fact we do not use DoRefresh or BeginRefresh is a shame. But this solution does provide some benefits as far as testability is concerned.
Thanks for doing the research on this. Have you taken a look at the ParameterOverride and ParameterOverrides implementation yet? I was interested in seeing if they could be used in conjunction with the name to handle Csla.
ReplyDeleteExample:
var businessObject = container.Resolve("Get", new ParameterOverrides { { "container", container }, { "id", 2312 } });
It seems to be a slightly more manageable solution, but I can't seem to get the parameter overrides to work with InjectionFactory.
Cheers
Sorry... forgot:
ReplyDeletecontainer.RegisterType("New", new InjectionFactory(c => TestBusinessObject.New(c)));
container.RegisterType("Get", new InjectionFactory(c => TestBusinessObject.Get(c)));
Then:
var businessObject = container.Resolve("Get", new ParameterOverrides { { "container", container }, { "id", 2312 } });
I just took a quick look and indeed I cannot seem to get it to work. Saying that I did spot a slight improvement that removes the need for DynamicInvoke.
ReplyDeleteInstead of:
var oldCustomer = container.Resolve>().DynamicInvoke(new object[] { 3 }) as ICustomer;
we can write:
var oldCustomer = container.Resolve>().Invoke(3) as ICustomer;
Not ideal but 1 step closer to... improvement :-)
Also, you might want to take a look at the last post on this thread:
http://unity.codeplex.com/Thread/View.aspx?ThreadId=68584
Of course this is not usable with CSLA (since we want to type-safe the static factory method signatures) but I will take a look if this can be used.
HTH
Hey, were you able to develop anything new beyond your last post? I am still trying to get the multiple factory methods to work, and still about in the same place.
ReplyDeleteHi, unfortunately I have moved on and am not working on a CSLA project at the moment, hence my blog inactiveness :-(
ReplyDeleteI think this still remains an unsolved issue and do not have high hopes of tackling it the way I would like to (same issue with MEF - see other blog post).
Hopefully new posts will arrive soon!