Isolate the configuration file access code in a separate class. Make the configuration data (connectionstrings and whatnot) available via an interface on that class. Let the interface live in a shared assembly. Let any class that needs this interface get a reference to an instance of the configuration class via dependency injection. If you're not already using a DI framework I can highly recommend Autofac.
What have you achieved? Presentation and data access classes are now only dependent on a shared interface definition. They don't care what the implementation of that interface is, whether it reads connection strings from web.config, machine.config or some other store. Even better, you can now more easily test your classes by faking the implementation.
Update: First, to illustrate making the configuration data available via an interface. Say we have the following conffiguration service:
public interface IConfigurationService
{
string ConnectionString {get;}
}
public class ConfigurationService : IConfigurationService
{
string ConnectionString {get;}
public ConfigurationService()
{
// load configuration
}
}
My data access class could use this class directly:
public class DataAccess
{
private string _connectionString;
public DataAccess()
{
var config = new ConfigurationService();
_connectionString = config.ConnectionString;
}
}
The problem with this approach is coupling. DataAccess
is now directly dependent on the ConfigurationService
class. Any tests we write for DataAccess
will inadvertently be affected by the ConfigurationService
class. Also, should we need to switch out the implementation of ConfigurationService
it would require changes to DataAccess
(and all other classes directly dependent on this class).
To solve this, we invert the dependency hierarchy and references an interface instead of the concrete class, like this:
public class DataAccess
{
private string _connectionString;
public DataAccess(IConfigurationService configurationService)
{
_connectionString = configurationService.ConnectionString;
}
}
The data access class is now oblivious as to what the configuration service implementation is and how that instance is created.