views:

2394

answers:

8

In our web applications, we seperate our Data Access Layers out into their own projects.

This creates some problems related to settings.

Because the DAL will eventually need to be consumed from perhaps more than one application, web.config does not seem like a good place to keep the connection strings and some of the other DAL-related settings.

To solve this, on some of our recent projects we introduced a third project just for settings. We put the setting in a system of .Setting files... With a simple wrapper, the ability to have different settings for various enviroments (Dev, QA, Staging, Production, etc) was easy to achieve.

The only problem there is that the settings project (including the .Settings class) compiles into an assembly, so you can't change it without doing a build/deployment, and some of our customers want to be able to configure their projects without Visual Studio.

So, is there a best practice for this? I have that sense that I'm reinventing the wheel.

Some solutions such as storing settings in a fixed directory on the server in, say, our own XML format occurred to us. But again, I would rather avoid having to re-create encryption for sensitive values and so on. And I would rather keep the solution self-contained if possible.

EDIT: The original question did not contain the really penetrating reason that we can't (I think) use web.config ... That puts a few (very good) answers out of context, my bad.

+3  A: 

System.Configuration.ConfigurationManager.ConnectionStrings and System.Configuration.ConfigurationManager.AppSettings Contain settings from the executing application so in your DAL you can get the settings stored in your web.config file.

For your system you can create a custom configuration section that will sit in your web.config file or your DAL's consumer*.config file In these config files you can specify that they load from a separate config file of your design and location. Referencing external config files from Web.Config How to: Create Custom Configuration Sections Using ConfigurationSection

Alternativly you can manualy load your DAL configuration data from any file using ConfigurationManager.OpenExeConfiguration

Aaron Fischer
A: 

You could have a Interface that mapped you settings that is used on your DAL. Then on the App you could just use IoC to feed the settings to the DAL.

Bruno Shine
+2  A: 

You can add the equivalent to a web.config file called app.config that compiles into a file named for the dll or exe project of your code behind. This is completely changeable without having to recompile. You can use the standard settings for connection strings and various app settings that can be defined in a key/value pair - or with a little more work you can define your own custom config settings class and section. You can even reference settings in your app config - so you could have 3 settings stored in your app (DEV, QA, PROD) and then only reference the one you want at runtime in your app.config file. Here is an example of one that was created for a webs service setting.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <section name="{Project}.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
    </sectionGroup>
    <section name="microsoft.web.services3" type="Microsoft.Web.Services3.Configuration.WebServicesConfiguration, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
  </configSections>
  <applicationSettings>
    <{Project}.Properties.Settings>
      <setting name="{SettingName}" serializeAs="String">
        <value>{SettingValue}</value>
      </setting>
    </{Project}.Properties.Settings>
  </applicationSettings>
  <microsoft.web.services3>
    <security>
      <securityTokenManager>
        <add type="Microsoft.Web.Services3.Security.Tokens.UsernameTokenManager, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" namespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd&amp;quot; localName="UsernameToken" />
      </securityTokenManager>
    </security>
  </microsoft.web.services3>
</configuration>

silverbugg
+1  A: 

A completely different approach would be to use SQLite and store all your application settings in there. You can password protect the database in question, if that is of importance to the application, and you can create some simple property/value tables to store the data.

Using the SQLite ADO adapter would only require 1 additional DLL into the projects to access the settings and the SQLite DB itself would be accessible to those folks that don't want to use Visual Studio. There is even a plugin for Firefox to interact with SQLite databases.

Dillie-O
+1  A: 

Split it up. Use the fixed-XML storage file solution for the database connection, encrypted with .NET's built-in encryptor functions (do not roll your own). Then, using the resultant database connection, look up your 'settings table' in the database. This way you can modify your settings without a redeploy. If your customers need to be able to change the database connection string without visual studio, just write a small Windows Forms app that is capable of generating the encrypted connection string and saving the fixed-XML storage file, and, if necessary, also can connect to DB (via that same file) and modify the Settings table as the user needs.

GWLlosa
I've been doing it this way for awhile now and it's great. In Web.Config, I just store a connectionstring and a variable called 'enviroment' that contains a value like Production, Staging, Development. And then there's a table called Settings in the database that contains all the settings for all the different environments. And I use RedGate's SQL Data Compare to keep the all in sync.
Brian MacKay
A: 

If you're using a DI framework (like Unity) you can specify constructor arguments. So, hypothetically, your DAL provider could have a constructor that takes its connection string.

I know you can't enforce constructors in interfaces, but that's something we have to deal with. I know the framework has a few places where there are unspoken dependencies on constructor signatures...

Will
+2  A: 

It sounds like you do not understand how web.config/app.config work, if I'm reading you correctly. Let's say you have a structure like the following:

DAL Project

References:

  • Some core libraries
  • Miscellaneous references

Classes:

  • DatabaseHelper
  • ObjectClass1
  • ObjectClass2
  • etc...

Web Project

References:

  • Some core libraries
  • DAL Project
  • Miscellaneous references

Pages:

  • Default.aspx
  • SomePage1.aspx
  • etc...
  • Web.config

In your DatabaseHelper class, you might reference the connection string like so:

string connString = ConfigurationManager
  .ConnectionStrings["myConnString"]
  .ConnectionString;

When this happens at runtime, your DatabaseHelper class will be running under the same app domain as your web page, and thus, any calls to ConfigurationManager will load the request from the web.config file provided by the web project.

Therefore, you only need the one config file in your web/console/winforms/etc... project, and do not need to worry about having one at design time in each of your class library projects.

If you actually run your DAL as a service or a separate console application or something, then and only then would you need to give the DAL project it's own app.config / web.config file.

Chris
The missing piece here is in my edit. The DAL needs to be usable from a different app domain, which is to say it will eventually also be consumed somewhere other than the initial web site we're building.
Brian MacKay
Then the web.config / app.config for each different consumer application should reference a separate config section xml file as explained here: http://forums.subsonicproject.com/forums/t/3944.aspx
Chris
And here: http://weblogs.asp.net/fmarguerie/archive/2007/04/26/using-configsource-to-split-configuration-files.aspx
Chris
Interesting, not sure if this directly answers the question, but it's good info. Thanks.
Brian MacKay
+1  A: 

You could store the settings in any old Xml file and use the XmlSerializer to take your class and convert it to < - > from Xml. In another answer I wrote some code that did just that. The linked answer serializes a list of simple objects, but it also works to serialize one large configuration object.

Because the XmlSerializer serializes to/from public properties, if you don't want to allow values to change, you might need make the class itself immutable (popsicle style) or have a read-only facade that sits in front of the deserialized one.

It's a handy trick. You can set it up via ConfigurationManager.AppSettings[] with it's own config section and external file references, or you can alternatively just hardcode a specifc xml filename per configuration class.

Robert Paulson