I just create an interface for my data source and then implement it for each data source type I need to use. Normally they look something like this:
public interface IMyProjectDataSource
{
IEnumerable<string> GetUserNames();
void AddUser(string userName);
}
public class SqlServerMyProjectDataSource : IMyProjectDataSource
{
public SqlServerMyProjectDataSource(string connectionString)
{
//...
}
public IEnumerable<string> GetUserNames()
{
//...
}
public void AddUser(string userName)
{
//...
}
}
public class PostgreSqlMyProjectDataSource : IMyProjectDataSource
{
public IEnumerable<string> GetUserNames()
{
//...
}
public void AddUser(string userName)
{
//...
}
}
public class HttpCacheSqlMyProjectDataSource : IMyProjectDataSource
{
public HttpCacheSqlMyProjectDataSource(IMyProjectDataSource parentMyProjectDataSource)
{
}
public IEnumerable<string> GetUserNames()
{
//...
}
public void AddUser(string userName)
{
//...
}
}
I also like this because it allows you to "chain" them together. For instance you can do all of your data source caching like this:
public class HttpCacheSqlMyProjectDataSource : IMyProjectDataSource
{
public HttpCacheSqlMyProjectDataSource(IMyProjectDataSource parentMyProjectDataSource)
{
//...
}
public IEnumerable<string> GetUserNames()
{
//...
}
public void AddUser(string userName)
{
//...
}
}
The hardest part is deciding how to create it, especially if you're planning to chain more than one together. For that I generally store it in my Global.asax.cs as a singleton and create it from a type name in the .config file. You can use Type.GetType() and then Activator.CreateInstance() to do that and most of the chaining I have will be done no matter what the data source in the .config is so I don't have to worry about creating some sort of "constructor" type or a complicated .config.
Hopefully that makes sense. This may not be the best for all situations but I have had a lot of luck with it.