15

I'm looking for a good way to achieve the following:

I have a web application (MVC 3), with a separate Class Library that contains the back-end logic of a CMS that I'm making. This CMS uses NHibernate to connect to a database. I want the user to be able to configure the connectionstring (and eventually even the flavour of the database) in their web.config file.

What I'm looking for is a good way to get the connection string from the web.config file, even though the DLL is completely separate. Is this possible? Will I have to pass my connection string to my class library somehow? Or will I be able to access it when the application runs?

If I have to create some code in my web application to pass the connection string to my Class Library, how can I make this code as portable as possible, so I won't have to write it again for my next webapp?

Thanks a lot for any ideas you have.

Steven Lemmens
  • 1,441
  • 3
  • 17
  • 30

7 Answers7

21

You can pass in the connection string to the classes in the class library from the web site.

This is a better choice than trying to get the information directly from the configuration file, as otherwise you will have a dependency on the configuration file existing with the exact right key (making testing the class somewhat harder).

See this blog post for arguments against accessing configuration directly (which is very commonly done, but is not best practice).

Oded
  • 489,969
  • 99
  • 883
  • 1,009
  • +1 for easing testing. Separate the obtaining of the configuration from the using of it – SHug Oct 04 '11 at 19:05
11

You can access System.Configuration.ConfigurationManager from your class library. That'll give you access to the AppSettings and ConnectionStrings.

Charles Lambert
  • 5,042
  • 26
  • 47
Brandon
  • 68,708
  • 30
  • 194
  • 223
  • 4
    Bad idea. Configuration is a dependency and should be passed in directly. http://www.devtrends.co.uk/blog/configuration-settings-are-a-dependency-that-should-be-injected – Oded Oct 04 '11 at 19:03
  • 4
    @Oded - implementing an interface is no less of a hassle than adding items to an app.config. It also circumvents several security features built into the .net configuration manager such as the ability to encrypt connection strings and the fact that web.config cannot be modified by the application. Not to mention that everyone using your library will also have to learn a new way to configure things instead of using an industry standard. – Charles Lambert Oct 04 '11 at 19:22
  • @CharlesLambert - The fact that this is a widely used technique doesn't make it a good habit. If you test your data access layer, it forces you to add configuration files to the test assemblies. – Oded Oct 04 '11 at 19:24
  • @Oded if you require a configuration implementation to be passed into your classes, it forces you to implement an interface. I see no difference in hassle. – Charles Lambert Oct 05 '11 at 07:36
  • 2
    @CharlesLambert - It isn't about _hassle_. It is about having a static dependency. – Oded Oct 05 '11 at 07:38
2

I have exactly the same setup with a FOSS project I'm involved with. It contains everything (even the Controllers and Global.asax.cs) in the 'Core' class library.

There's plenty of valid solutions, the one I opted for was to create a Settings class which is essentially a set of static properties, inside which you have:

public static string ConnectionString
{
        get { return ConfigurationManager.ConnectionStrings["MYAPP"].ConnectionString; }
}

Note: make sure your class library has System.Configuration added as a reference.

Inside your Application (the class derived from HttpApplication) you pass the settings across, although there is nothing to stop you tighly coupling the NH setup with the settings class:

protected void Application_Start()
{
        AreaRegistration.RegisterAllAreas();
        RegisterRoutes(RouteTable.Routes);
        SetupNHibernate();
}

public virtual void SetupNHibernate()
{
        NHibernateRepository.Current.Configure(RoadkillSettings.DatabaseType, Settings.ConnectionString, false, Settings.CachedEnabled);
}

If this is any use to you, the source is here.

Chris S
  • 64,770
  • 52
  • 221
  • 239
2

You can use the ConfigurationManager class to access items in your web.config or app.config file. However, in your class library, be sure to take in the key name of any appSettings and/or connectionString settings from the consumer (preferably in the constructor). This avoids the problem of you choosing a key name that the consumer is already using elsewhere.

Charles Lambert
  • 5,042
  • 26
  • 47
0

You can add new Existing item from another project to your class library. Then change Build Action to Embedded Resource and Copy to Output Directory to Copy if newer on the Web.config file.

enter image description here

enter image description here

Web.config in another project

<configuration>
    <appSettings>
        <add key="MyConfigValue" value="Test" />
    </appSettings>
</configuration>

Class library test file

var doc = XDocument.Load(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Web.config"));

var myConfigValue = doc.Element("configuration")
                       .Element("appSettings")
                       .Elements("add")
                       .FirstOrDefault(e => e.Attribute("key").Value == "MyConfigValue").Attribute("value").Value;
Joel Wiklund
  • 1,697
  • 2
  • 18
  • 24
0

Since you are using the class library to the MVC web application, it is accessible to the class library also. No additional settings are needed. Even though the class library when built giving a separate dll, it is referenced in the current project. So the connection string will be available to the class library also.

Prasanth
  • 3,029
  • 31
  • 44
0

I'd go with something like Autofac to give you some IoC implementation which can store a settings interface for your connection strings. This would allow you to setup the value from the web.config on application start, or to set it within tests to a different value without your Class Library ever having to be coupled to a web.config.

Druegor
  • 389
  • 1
  • 7