V poslední době jsem narazil na pár projektů, kde jsou konfigurační hodnoty zapsány ve formátu, kterému pracovně říkám "flat". Programátor nepoužil některou z obvyklých technik, ale místo toho v klíči elementu v appSettings zachycuje částečně strukturu objektu a třídy a poté určuje její hodnotu v atributu value.
Například tomuto zápisu:
<appSettings>
<add key="idnes.Uri" value="http://idnes.cz"/>
<add key="idnes.Name" value="idnes"/>
<add key="idnes.RetryAttempts" value="5"/>
<add key="idnes.ConnectionPoint.Limit" value="5"/>
<add key="idnes.ConnectionPoint.UseAlgorithm" value="true"/>
</appSettings>
odpovídají následující třídy:
class EndPoint
{
public string Uri { get; set; }
public string Name{ get; set; }
public int RetryAttempts { get; set; }
public ConnectionPoint ConnectionPoint{ get; set; }
}
class ConnectionPoint
{
public int Limit { get; set; }
public bool UseAlgorithm { get; set; }
}
Tyto třídy se v kódu vyplňují postupně, tedy asi nějak takto:
var endpoint = new EndPoint();
endpoint.Uri = ConfigurationManager.AppSettings.Get("idnes.Uri");
endpoint.RetryAttempts = int.Parse(ConfigurationManager.AppSettings.Get("idnes.RetryAttempts"));
a tak dále, co property, to řádek. Abych si ulehčil práci, napsal jsem si krátkou třídu, která umí podobné objekty sama naplnit. Má jen dvě metody a vypadá takto:
public class FlatConfigurationManager
{
public static T CreateAndSetInstance<T>(string appSettingKeyName, Func<string, string> getValues)
{
var instance = Activator.CreateInstance<T>();
SetInstance(instance, appSettingKeyName, getValues);
return instance;
}
public static void SetInstance(object instance, string appSettingKeyName, Func<string, string> getValues)
{
var properties = instance.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var property in properties)
{
var keyName = $"{appSettingKeyName}.{property.Name}";
dynamic value;
if (property.PropertyType.IsClass && property.PropertyType != typeof(string))
{
value = Activator.CreateInstance(property.PropertyType, null);
SetInstance(value, keyName, getValues);
}
else
value = getValues(keyName);
property.SetValue(instance, Convert.ChangeType(value, property.PropertyType), null);
}
}
}
Pro práci s ní pak stačí jen zavolat:
Func<string,string> getValue = (name) => ConfigurationManager.AppSettings.Get(name);
var endpointIdnes = FlatConfigurationManager.CreateAndSetInstance<EndPoint>("idnes", getValue);
Funkce se předává jednoduše proto, že "rodina" ConfigurationManagerů se nám rozrostla, mimo klasické třídy ConfigurationManager existuje třeba i CloudConfigurationManager. Takto se obejde nutnost definice společného interfejsu a wrapperů.
Žádné komentáře:
Okomentovat