在 Simple Injector 中注册具有原始配置依赖项的装饰器

rex*_*ghk 4 .net c# dependency-injection simple-injector

我有一个IAppSettingsLoader接口,可以抽象出用于加载我的app.config文件的文件 IO 。

public interface IAppSettingsLoader
{
    IEnumerable<KeyValuePair<string, string>> LoadAppSettings();
}
Run Code Online (Sandbox Code Playgroud)

我有一个加载实际文件的类:

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

然后我有一个缓存装饰器,试图监视文件更改 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

我试图用 Simple Injector 注册这个缓存装饰器,但没有成功。这是我尝试过的:

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);
}
Run Code Online (Sandbox Code Playgroud)

这失败了,因为 Simple Injector 无法将我的自定义识别ResolveCachedAppSettingsLoaderCachedAppSettingsLoader.

CachedAppSettingsLoader 类型的构造函数包含不能用于构造函数注入的 String 类型的参数“cacheKey”。参数名称:decoratorType

我的问题是如何Func<CachedAppSettingsLoader>在 Simple Injector 中提供自定义来构造这个缓存装饰器(带有依赖项)?

Ste*_*ven 5

Simple Injector 不允许注册包含原始配置值的装饰器。有多种方法可以扩展 Simple Injector 以启用此类行为,但我想说有更简单的解决方案。

除了扩展 Simple Injector 之外,您在这里基本上有两个选择。您要么退回到对象图的这一部分的手动构建,要么将原始配置值组提取到其自己的配置对象中,您可以将其注册为容器中的单例。

您可以手动构建装饰器及其被装饰者,如下所示:

container.RegisterSingleton<IAppSettingsLoader>(
    new CachedAppSettingsLoader(
        "AuthorizationRecords", 
        cacheItemPolicy, 
        MemoryCache.Default, 
        new FileAppSettingsLoader()));
Run Code Online (Sandbox Code Playgroud)

另一种选择是将配置值提取到它自己的类中,无论如何这可能是个好主意:

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)
    {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

在此重构之后,您可以按如下方式注册您的类型:

container.Register<IAppSettingsLoader, FileAppSettingsLoader>(Lifestyle.Singleton);
container.RegisterDecorator<IAppSettingsLoader, CachedAppSettingsLoader>(
    Lifestyle.Singleton);
container.RegisterInstance(new CachedAppSettingsLoaderSettings
{
    Cache = MemoryCache.Default,
    Policy = new CacheItemPolicy { ... },
    CacheKey = "AuthorizationRecords" 
});
Run Code Online (Sandbox Code Playgroud)