I am a newbie to OOP and IOC container. I need to understand how to use depency injection. My app's simple structure is as below.
The code below belongs to CacheService:
using Akavache;
public class CacheService : ICacheService
{
protected IBlobCache Cache;
public CacheService(IBlobCache blobCache, string applicationName)
{
Cache = blobCache;
BlobCache.ApplicationName = applicationName;
}
}
I have registered this service as below in App.cs Because I need to use the same service with 2 different types.
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterSingleton<IMockApiService, MockApiService>();
containerRegistry.RegisterSingleton<IEssentialsService, EssentialsService>();
containerRegistry.RegisterInstance<CacheService>(new CacheService(BlobCache.LocalMachine, "MyAppName"), "LocalMachineCache");
containerRegistry.RegisterInstance<CacheService>(new CacheService(BlobCache.UserAccount, "MyAppName"), "UserAccountCache");
}
My ViewModel code is as below:
public class SettingsPageViewModel : BindableBase
{
protected ICacheService CacheService { get; private set; }
public SettingsPageViewModel(ICacheService cacheService)
{
CacheService = cacheService;
}
}
Is above usage possible or not? If it is possible how should I modify my structure? Thank you in advance.
As far as I can tell, this usage is not possible because your IoC container would not know how to resolve ICacheService
, since you registered the instances as CacheService
. When DryIoc tries to resolve SettingsPageViewModel
it would encounter ICacheService
and find the type not being registered. At least this is how the Unity container behaves.
Anyway, even if you registered "LocalMachineCache"
and "UserAccountCache"
as ICacheService
I doubt that it'd work, since there would be no way to know for DryIoc which one shall be used with SettingsPageViewModel
, hence you'd have to define which one to resolve.
According to its documentation, Prism resolves dependencies by the respective parameter name (unless I did not misunderstand this, see here). Assuming that you need the local machine cache in your settings, you could register it as "localMachineCache"
(renamed it to stick with common C# coding conventions in the constructor of SettingsPageViewModel
) and give the parameter that very name
containerRegistry.RegisterInstance<ICacheService>(new CacheService(BlobCache.LocalMachine, "MyAppName"), "localMachineCache");
containerRegistry.RegisterInstance<ICacheService>(new CacheService(BlobCache.UserAccount, "MyAppName"), "userAccountCache");
public SettingsPageViewModel(ICacheService localMachineCache)
{
CacheService = localMachineCache;
}
And accordingly if you need both
public SettingsPageViewModel(ICacheService localMachineCache, ICacheService userAccountCache)
{
MachineCacheService = localMachineCache;
UserAccountCacheService = userAccountCache;
}
Although it is written in the docs, named services don't seem to work the way the documentation states. However, depending on the choice of IoC container it's still possible injecting services by their names.
With the made
parameter of IContainer.Register
you can specify a factory function to create instances of a specified type. Since Prism puts an IoC abstraction over the framework used, you'll first have to obtain the DryIoc IContainer
instance
var container = ((DryIocContainerExtension)containerRegistry).Instance;
now you can specify how to create instances of SettingsPageViewModel
with
container.Register(Made.Of(
() => new SettingsPageViewModel(Arg.Of<ICacheService>("LocalMachineCache"))));
The string passed to Arg.Of
is the service key, the service has been registered with and tells DryIoc
which ICacheService
to resolve (please note that I've used your original name).
With unity there are at least two ways to achieve this. The first one is to obtain an instance via UnityContainerExtension
(similar to the DryIoc version) and use RegisterFactory
unityContainer.RegisterFactory<SettingsPageViewModel>(
container => new SettingsPageViewModel(container.Resolve<ICacheService>("LocalMachineCache")));
The other option is to add the DependencyAttribute
to the constructor parameters of the viewmodel
public SettingsPageViewModel([Unity.Dependency("LocalMachineCache")] ICacheService localMachineCache)
{
CacheService = localMachineCache;
}