0

目标

我正在尝试迁移到 .net 标准,因此需要将 RealProxy 迁移到 Dispatch Proxy。

当前设置

我正在使用 Autofac 进行依赖注入。

配置绑定到实现 ISettings 的“设置”类。

我使用构造函数注入将设置注入我的类并检索设置的值,如下所示:

        private readonly IDatabaseSettings _databaseSettings;

        public MyService(IDatabaseSettings databaseSettings)
        {
            _databaseSettings = databaseSettings;
        }

        public string GetConnectionString() {
            return _databaseSettings.ConnectionString;
        }

通过从 MySettingsProxy 实例注册透明代理,向 Autofac 注册设置:

private static void RegisterConfiguration(ContainerBuilder builder)
{
    foreach (var settingsContainer in MyConfigurationManager.GetSettings())
    {
        builder.Register(r => new MySettingsProxy(settingsContainer.Key).Build())
            .As(settingsContainer.Key);
    }
}

MySettingsProxy 是 RealProxy 的一个实现。

public class MySettingsProxy : RealProxy
{
    private readonly Type settings;

    public MySettingsProxy(Type settingsType)
        : base(settingsType)
    {
        settings = settingsType;
    }

    public object Build()
    {
        return GetTransparentProxy();
    }

    public override IMessage Invoke(IMessage msg)
    {
        var methodCall = (IMethodCallMessage)msg;
        string prop = methodCall.MethodName;

        return new ReturnMessage(settings.GetProperty(prop.Split('_')[1])
            .GetValue(MyCachedSettings.CachedSettings[settings]), null, 0, null, null);
    }
}
public static class MyCachedSettings
{
    public static Dictionary<Type, ISettings> CachedSettings { get; set; } = new Dictionary<Type, ISettings>();
}

IConfiguration _configuration 中的部分绑定到 ISettings 类。

public static class MyConfigurationManager
{
    private static IConfiguration _configuration = null;
    private static IConfigurationRefresher _configurationRefresher = null;
    private static Dictionary<Type, ISettings> _settings = new Dictionary<Type, ISettings>();
    private static string _environment;
    private static bool _isStagingSlot;
    private static string _overwrittenLocalhostConfigKey = null;

    public static async Task<bool> RefreshConfiguration()
    {
        var success = await _configurationRefresher.TryRefreshAsync();
        BindAndCacheConfiguration();

        return success;
    }

    public static void BuildConfiguration()
    {
        var configStore = ConfigureEnvironment();
        ConnectToAppConfigService(configStore);
        BindAndCacheConfiguration();
    }

    internal static Dictionary<Type, ISettings> GetSettings()
    {
        return _settings;
    }

    internal static ISettings GetSettings(Type settingsInterface)
    {
        return _settings[settingsInterface];
    }

    internal static void BindAndCacheConfiguration()
    {
        BindConfiguration();
        CacheConfiguration();
    }

    private static void BindConfiguration()
    {
        _settings.Clear();

        var settings = Assembly.GetAssembly(typeof(ISettings)).GetTypes()
            .Where(x => typeof(ISettings).IsAssignableFrom(x)
            && !x.IsAbstract
            && !x.IsInterface);

        List<string> missingSettings = new List<string>();

        foreach (var settingsContainer in settings)
        {
            try
            {
                var settingsInterface = settingsContainer.GetInterface("I" + settingsContainer.Name);
                var settingsPrefix = SettingsPrefixes.Prefixes[settingsInterface];
                var configurationSection = _configuration.GetSection(settingsPrefix);
                var boundSettingsContainer = (ISettings)configurationSection.Get(settingsContainer);

                if (boundSettingsContainer is null)
                {
                    throw new MissingConfigurationException($"{settingsInterface} was null, likely because no matching configs were found for that section. Environment: {_environment}");
                }

                var individualSettings = boundSettingsContainer.GetType().GetProperties()
                    .Where(x => x.CanRead && x.CanWrite)
                    .Select(x => new { Name = x.Name, Value = x.GetValue(boundSettingsContainer) });

                foreach (var setting in individualSettings)
                {
                    if (setting.Value == null || string.IsNullOrEmpty(setting.Value.ToString()) || !configurationSection.AsEnumerable().Any(x => x.Key == $"{settingsPrefix}:{setting.Name}"))
                    {
                        missingSettings.Add($"{settingsPrefix}:{setting.Name}");
                    }
                }

                _settings.Add(settingsInterface, boundSettingsContainer);
            }
            catch (KeyNotFoundException)
            {
                throw new MissingConfigurationException($"The prefix for {settingsContainer.Name} has not been configured in {nameof(SettingsPrefixes)}");
            }
        }

        if (missingSettings.Count != 0)
        {
            throw new MissingConfigurationException($"The following settings are missing from the Azure App Configuration Service for {_environment}: {string.Join(",", missingSettings)}");
        }

    }

    private static void CacheConfiguration()
    {
        MyCachedSettings.CachedSettings = _settings;
    }
}

现在,当我在应用程序运行时更改 _configuration 的内容并将 _configuration 的部分重新绑定到 ISettings 类时,它反映了从构造函数注入访问设置时的新值。

迁移到 Dispatch Proxy 后的更改

我的 SettingsProxy 现在看起来像这样:

public class MySettingsProxy
{
    private readonly object _target;
    private readonly MethodInfo _methodInfo;
    private readonly ISettings _settingsInterface;
    private readonly Type _type;

    public MySettingsProxy(Type type, ISettings settingsInterface)
    {
        _type = type;
        _settingsInterface = settingsInterface;
        var proxyType = typeof(MySettingsProxy<>).MakeGenericType(_type);
        _target = Activator.CreateInstance(proxyType);
        var methodName = nameof(MySettingsProxy<ISettings>.Decorate);
        _methodInfo = proxyType.GetMethod(methodName);
    }

    public object Build()
    {
        return _methodInfo.Invoke(_target, new object[] { _settingsInterface });
    }
}

public class MySettingsProxy<T> : DispatchProxy
    where T : ISettings
{
    public T Target { get; private set; }

    public MySettingsProxy() : base()
    {
    }

    public static object Decorate(T target)
    {
        var proxy = Create<T, MySettingsProxy<T>>()
                    as MySettingsProxy<T>;

        proxy.Target = target;

        return proxy;
    }

    protected override object Invoke(MethodInfo targetMethod, object[] args)
    {
        try
        {
            var result = targetMethod.Invoke(Target, args);
            return result;
        }
        catch (TargetInvocationException exc)
        {
            throw exc.InnerException;
        }
    }
}

并且代理注册到 Autofac 容器,如下所示:

private static void RegisterConfiguration(ContainerBuilder builder)
{
    var settings = RevokeConfigurationManager.GetSettings();
    foreach (var setting in settings)
    {
        var settingsProxy = new MySettingsProxy(setting.Key, setting.Value);
        var builtSettingsProxy = MySettingsProxy.Build();

        builder.Register(r => builtMySettingsProxy)
            .As(setting.Key);
    }
}

其他一切仍然相同,但是在访问构造函数注入设置时,它们没有来自 _configuration 的新值

我的 Dispatch Proxy 设置有什么不同的想法吗?

4

0 回答 0