2017-02-23 43 views
3

У меня есть интерфейс IAppSettingsLoader, который абстрагирует файл IO для загрузки моего файла app.config.Регистрация декораторов с примитивными конфигурационными зависимостями в Simple Injector

public interface IAppSettingsLoader 
{ 
    IEnumerable<KeyValuePair<string, string>> LoadAppSettings(); 
} 

У меня есть класс, который загружает сам файл:

public class FileAppSettignsLoader : IAppSettingsLoader 
{ 
    public IEnumerable<KeyValuePair<string, string>> LoadAppSettings() 
    { 
     // Perform actual loading through ConfigurationManager.AppSettings 
    } 
} 

Тогда у меня есть декоратор кэширования, который пытается отслеживать изменения файлов в 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; 
    } 
} 

Я пытался зарегистрировать этот кеширующий декоратор с простым инжектором без успеха. Это то, что я пробовал:

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); 
} 

Это терпит неудачу, потому что просто Injector не распознает мой обычай ResolveCachedAppSettingsLoader как экземпляр фабрики к CachedAppSettingsLoader.

Конструктор типа CachedAppSettingsLoader содержит параметр «» cacheKey строчного типа, который не может быть использован для конструктора инъекции. Имя параметра: decoratorType

Мой вопрос, как я могу поставить пользовательский Func<CachedAppSettingsLoader> для создания этого кэширования декоратора (с зависимостями) в простом Injector?

ответ

2

Простой инжектор нелегко разрешить регистрацию декораторов, содержащих примитивные значения конфигурации. Существует несколько способов расширения Simple Injector для обеспечения такого поведения, но я бы сказал, что есть более простые решения.

За исключением расширения простого инжектора, в принципе у вас есть два варианта. Либо вы вернетесь к ручной конструкции этой части графического объекта, либо вы извлечете группу примитивных значений конфигурации в свой собственный объект конфигурации, который вы можете зарегистрировать в качестве одиночного элемента в контейнере.

Вы можете вручную построить декоратора и его decoratee следующим образом:

container.RegisterSingleton<IAppSettingsLoader>(
    new CachedAppSettingsLoader(
     "AuthorizationRecords", 
     cacheItemPolicy, 
     MemoryCache.Default, 
     new FileAppSettingsLoader())); 

Другой вариант для извлечения значения конфигурации в свой собственный класс, который может быть хорошей идеей в любом случае:

public class CachedAppSettingsLoaderSettings 
{ 
    public ObjectCache Cache; 
    public CacheItemPolicy Policy; 
    public string CacheKey; 
} 

public class CachedAppSettingsLoader : IAppSettingsLoader 
{ 
    private readonly CachedAppSettingsLoaderSettings settings; 
    private readonly IAppSettingsLoader decoratee; 

    public CachedAppSettingsLoader(
     CachedAppSettingsLoaderSettings settings, IAppSettingsLoader decoratee) 
    { 
     ... 
    } 
} 

После этого рефакторинг вы можете зарегистрировать свои типы следующим образом:

container.Register<IAppSettingsLoader, FileAppSettingsLoader>(Lifestyle.Singleton); 
container.RegisterDecorator<IAppSettingsLoader, CachedAppSettingsLoader>(Lifestyle.Singleton); 
container.RegisterSingleton(new CachedAppSettingsLoaderSettings 
{ 
    Cache = MemoryCache.Default, 
    Policy = new CacheItemPolicy { ... }, 
    CacheKey = "AuthorizationRecords" 
}); 
+0

Я был b так же, как и ваше первое решение :), но ваше второе решение имеет больше смысла для меня, попробуй это – rexcfnghk

+0

, кстати, если я использую ваш первый вариант, экземпляр 'HostFileChangeMonitor' будет автоматически удален, когда он погаснет объема? – rexcfnghk

+0

В любом случае он не будет удален простым инжектором. Он ничего об этом не знает. – Steven