I'm trying to build an App with Unity and set it up so all type registrations happen only at the composition root and dependencies flow down to all children instead of using the Service Locator Anti-Pattern.
Problem I'm having is figuring out how to inject dynamic values down at the child levels that determine what sort of class is resolved from an interface, which is not known at compile time. I can't find any examples that fit my scenario well enough to be able to understand this.
For example, I'm trying to resolve the IUserProfile->UserProfile class, which depends on IUserName, IContactDetails, IAddress, IDisplayImage and IMembership to be injected through the constructor.
I want each of the country-based dependencies to be resolved from the country specified in the Address class.
var theCountry = "Australia" //<-This to be obtained from the User's Selection
_container.RegisterType<IUserName, UserName>();
//Types part of IContactDetails
_container.RegisterType<IEmailAddress, EmailAddress>();
_container.RegisterType<IPhoneNumber, AustralianPhoneNumber>("Australia");
_container.RegisterType<IPhoneNumber, NewZealandPhoneNumber>("NewZealand");
_container.RegisterType<IContactDetails, ContactDetails>(
new InjectionConstructor(new ResolvedParameter<IPhoneNumber>(theCountry),
new ResolvedParameter<IEmailAddress>()));
//Types part of IAddress
_container.RegisterType<IAddress, AustralianAddress>("Australia");
_container.RegisterType<IAddress, NewZealandAddress>("NewZealand");
//Types part of IDisplayImage
_container.RegisterType<IDisplayImage, UploadedDisplayImage>("Uploaded");
_container.RegisterType<IDisplayImage, WebLinkDisplayImage>("WebLink");
//Types part of IMemberShip
_container.RegisterType<ICurrencyType, AustralianCurrency>("Australia");
_container.RegisterType<ICurrencyType, NewZealandCurrency>("NewZealand");
_container.RegisterType<IPrice, Price>(
new InjectionConstructor(new ResolvedParameter<ICurrencyType>(theCountry)));
_container.RegisterType<IMemberShip, UltimateMemberShip>(
new InjectionConstructor(new ResolvedParameter<IPrice>(theCountry???)));
_container.RegisterType<IUserProfile, UserProfile>(new InjectionConstructor(
new ResolvedParameter<IUserName>(),
new ResolvedParameter<IContactDetails>(theCountry),
new ResolvedParameter<IAddress>(theCountry),
new ResolvedParameter<IDisplayImage>(),
new ResolvedParameter<IMemberShip>(theCountry???));
Is this how I would implement an abstract factory pattern?
public interface IAddressFactory { IAddress CreateInstance(string country); }
public class AddressFactory : IAddressFactory
{
private readonly string _streetName;
private readonly string _suburb;
private readonly string _postCode;
private readonly string _state;
protected AddressFactory(string streetName, string suburb, string postCode, string state)
{
_streetName = streetName;
_suburb = suburb;
_postCode = postCode;
_state = state;
}
public virtual IAddress CreateInstance(string country)
{
switch (country)
{
case "Australia":
return new AustralianAddress(_streetName, _suburb, _postCode, _state);
case "NewZealand":
return new NewZealandAddress(_streetName, _suburb, _postCode);
default: throw new ArgumentException();
}
}
}