I have an IAppSettingsLoader
interface that abstracts away the file IO for loading my app.config
file.
public interface IAppSettingsLoader
{
IEnumerable<KeyValuePair<string, string>> LoadAppSettings();
}
I have a class that loads the actual file:
public class FileAppSettignsLoader : IAppSettingsLoader
{
public IEnumerable<KeyValuePair<string, string>> LoadAppSettings()
{
// Perform actual loading through ConfigurationManager.AppSettings
}
}
Then I have a caching decorator that tries to monitor file changes to app.config
public class CachedAppSettingsLoader : IAppSettingsLoader
{
private readonly ObjectCache _cache;
private readonly string _cacheKey;
private readonly CacheItemPolicy _cacheItemPolicy;
private readonly IAppSettingsLoader _innerAppSettingsLoader;
public CachedAppSettingsLoader(ObjectCache cache,
string cacheKey,
CacheItemPolicy cacheItemPolicy,
IAppSettingsLoader innerAppSettingsLoader)
{
_cacheKey = cacheKey;
_cacheItemPolicy = cacheItemPolicy;
_cache = cache;
_innerAppSettingsLoader = innerAppSettingsLoader;
}
public IEnumerable<KeyValuePair<string, string>> LoadAppSettings()
{
object cached = _cache[_cacheKey];
if (cached != null)
{
return (IEnumerable<KeyValuePair<string, string>>)cached;
}
var keyValuePairs = _innerAppSettingsLoader.LoadAppSettings();
// _cacheItemPolicy will contain a HostFileChangeMonitor
_cache.Add(_cacheKey, keyValuePairs, _cacheItemPolicy);
return keyValuePairs;
}
}
I was trying to register this caching decorator with Simple Injector without success. This is what I tried:
private void RegisterDependencies(Container container)
{
container.RegisterSingleton(() =>
ResolveCachedAppSettingsLoader(container));
container.Register<IAppSettingsLoader, FileAppSettingsLoader>(
Lifestyle.Singleton);
container.RegisterDecorator<IAppSettingsLoader, CachedAppSettingsLoader>(
Lifestyle.Singleton);
}
private CachedAppSettingsLoader ResolveCachedAppSettingsLoader(Container container)
{
var cacheItemPolicy = new CacheItemPolicy();
cacheItemPolicy.ChangeMonitors.Add(new HostFileChangeMonitor(new[] { "app.config" }));
var innerAppSettingsLoader = container.GetInstance<IAppSettingsLoader>();
return new CachedAppSettingsLoader(
"AuthorizationRecords",
cacheItemPolicy,
MemoryCache.Default,
innerAppSettingsLoader);
}
This fails because Simple Injector fails to recognise my custom ResolveCachedAppSettingsLoader
as an instance factory to CachedAppSettingsLoader
.
The constructor of type CachedAppSettingsLoader contains parameter 'cacheKey' of type String which can not be used for constructor injection. Parameter name: decoratorType
My question is how can I supply a custom Func<CachedAppSettingsLoader>
to construct this caching decorator (with dependencies) in Simple Injector?
Simple Injector does not easily allow registering decorators that contain primitive configuration values. There are multiple ways to extend Simple Injector to enable such behavior, but I would say that there are easier solutions.
Except for extending Simple Injector, you've basically got two options here. Either you fall back to manual construction of this part of the object graph, or you extract the group of primitive configuration values into its own configuration object, which you can register as singleton in the container.
You can manually construct the decorator and its decoratee as follows:
The other option is to extract the configuration values into its own class, which might be good idea anyway:
After this refactoring, you can register your types as follows: