I am following this great article on how to create a Provider framework in .NET
Basically, this article explains greatly how to end up with a configuration file like the following:
<configuration>
<configSections>
<section name="data" type="DataProviderConfigurationSection" />
</configSections>
<data defaultProvider="MyDataProvider">
<providers>
<add name="MydataProvider" type="MyDataProvider" />
</providers>
</data>
</configuration>
Where the <add/>
element allows you to define a provider.
However, I would like to know how to extend the add
entry with custom attributes.
For example:
<providers>
<add name="MydataProvider" type="MyDataProvider" myProperty="myValue" myProperty2="myValue2" ... />
</providers>
Any help will be greatly appreciated.
Here is what I finally found. This is a very specific question about extending the element with more attributes and how to handle them when implementing a Provider Framework. All the answers about custom configuration sections are OK but not addressing the original question.
If you need to implement a custom Provider, like the MembershipProvider
, but for your own purpose, you need to definitely read this article: Creating Your Own Provider Framework
It is excellent reading. Now if you need to extend the element with your own attributes, here is what you need to change...
1) Next is the code discussed in the article (There might be some adaptations):
using System;
using System.Configuration;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration.Provider;
using System.Collections.Specialized;
public abstract class DataProvider : ProviderBase
{
// Define the methods to be used by the provider. These are custom methods to your own provider.
public abstract void Get();
public abstract void Delete();
}
public class DataProviderCollection : ProviderCollection { }
//The name is typically the same as the abstract class, minus the Provider part. Sticking to our (fake) example. we'd have a static class called Data.
public static class Data
{
private static bool _isInitialized = false;
private static DataProvider _provider;
public static DataProvider Provider
{
get
{
Initialize();
return _provider;
}
}
private static DataProviderCollection _providers;
public static DataProviderCollection Providers
{
get
{
Initialize();
return _providers;
}
}
private static void Initialize()
{
DataProviderConfigurationSection dataConfig = null;
if (!_isInitialized)
{
// get the configuration section for the feature
dataConfig = (DataProviderConfigurationSection)ConfigurationManager.GetSection("data");
if (dataConfig == null)
{
throw new ConfigurationErrorsException("Data is not configured to be used with this application");
}
_providers = new DataProviderCollection();
// use the ProvidersHelper class to call Initialize() on each provider
ProvidersHelper.InstantiateProviders(dataConfig.Providers, _providers, typeof(DataProvider));
// set a reference to the default provider
_provider = _providers[dataConfig.DefaultProvider] as DataProvider;
_isInitialized = true;
}
}
public static void Get()
{
Initialize();
if (_provider != null)
{
_provider.Get();
}
}
public static void Delete()
{
Initialize();
if (_provider != null)
{
_provider.Delete();
}
}
}
public class MyDataProvider : DataProvider
{
public override void Get()
{
// Get Code
}
public override void Delete()
{
// Delete Code
}
}
public class DataProviderConfigurationSection : ConfigurationSection
{
public DataProviderConfigurationSection()
{
_defaultProvider = new ConfigurationProperty("defaultProvider", typeof(string), null);
_providers = new ConfigurationProperty("providers", typeof(ProviderSettingsCollection), null);
_properties = new ConfigurationPropertyCollection();
_properties.Add(_providers);
_properties.Add(_defaultProvider);
}
private readonly ConfigurationProperty _defaultProvider;
[ConfigurationProperty("defaultProvider")]
public string DefaultProvider
{
get { return (string)base[_defaultProvider]; }
set { base[_defaultProvider] = value; }
}
private readonly ConfigurationProperty _providers;
[ConfigurationProperty("providers")]
public ProviderSettingsCollection Providers
{
get { return (ProviderSettingsCollection)base[_providers]; }
}
private ConfigurationPropertyCollection _properties;
protected override ConfigurationPropertyCollection Properties
{
get { return _properties; }
}
}
public static class ProvidersHelper
{
private static Type providerBaseType = typeof(ProviderBase);
/// <summary>
/// Instantiates the provider.
/// </summary>
/// <param name="providerSettings">The settings.</param>
/// <param name="providerType">Type of the provider to be instantiated.</param>
/// <returns></returns>
public static ProviderBase InstantiateProvider(ProviderSettings providerSettings, Type providerType)
{
ProviderBase base2 = null;
try
{
string str = (providerSettings.Type == null) ? null : providerSettings.Type.Trim();
if (string.IsNullOrEmpty(str))
{
throw new ArgumentException("Provider type name is invalid");
}
Type c = Type.GetType(str, true, true);
if (!providerType.IsAssignableFrom(c))
{
throw new ArgumentException(String.Format("Provider must implement type {0}.", providerType.ToString()));
}
base2 = (ProviderBase)Activator.CreateInstance(c);
NameValueCollection parameters = providerSettings.Parameters;
NameValueCollection config = new NameValueCollection(parameters.Count, StringComparer.Ordinal);
foreach (string str2 in parameters)
{
config[str2] = parameters[str2];
}
base2.Initialize(providerSettings.Name, config);
}
catch (Exception exception)
{
if (exception is ConfigurationException)
{
throw;
}
throw new ConfigurationErrorsException(exception.Message,
providerSettings.ElementInformation.Properties["type"].Source,
providerSettings.ElementInformation.Properties["type"].LineNumber);
}
return base2;
}
public static void InstantiateProviders(ProviderSettingsCollection providerSettings, ProviderCollection providers, Type type)
{
foreach (ProviderSettings settings in providerSettings)
{
providers.Add(ProvidersHelper.InstantiateProvider(settings, type));
}
}
}
2) This is the config file that you use for the above code:
<configuration>
<configSections>
<section name="data" type="DataProviderConfigurationSection" />
</configSections>
<data defaultProvider="MyDataProvider">
<providers>
<add name="MydataProvider" type="MyDataProvider" />
</providers>
</data>
</configuration>
3) Now, here is what you need to modify in order to use read the attributes in the <add>
element in the configuration file.
public abstract class DataProvider : ProviderBase
{
public string MyAttribute1 { get; set; }
public string MyAttribute2 { get; set; }
public string MyAttribute3 { get; set; }
// Define the methods to be used by the provider. These are custom methods to your own provider.
public abstract void Get();
public abstract void Delete();
public override void Initialize(string name, NameValueCollection config)
{
MyAttribute1 = config["MyAttribute1"];
MyAttribute2 = config["MyAttribute2"];
MyAttribute3 = config["MyAttribute3"];
base.Initialize(name, config);
}
}
4) The configuration file looks like this:
<configuration>
<configSections>
<section name="data" type="DataProviderConfigurationSection" />
</configSections>
<data defaultProvider="MyDataProvider">
<providers>
<add name="MydataProvider" type="MyDataProvider" MyAttribute1="MyValue1" MyAttribute2="MyValue2" />
</providers>
</data>
</configuration>
And as a bonus, here is a Unit test to validate it works:
[TestMethod]
public void RunMyDataProviderTest()
{
DataProvider dataProvider = Data.Provider;
Assert.IsInstanceOfType(dataProvider, typeof(MyDataProvider));
Assert.AreEqual(dataProvider.MyAttribute1, "MyValue1");
Assert.AreEqual(dataProvider.MyAttribute2, "MyValue2");
}