13
votes

I'm writing a basic little forums web app (for fun and to sharpen the ole' saw), and I'm having a bit of trouble with AppSettings.

My plan is to have these settings in their own file (Settings.config), to which I will grant modify permissions to the web process user account, and store all editable settings in this file (e.g. forum title, description, etc).

This is my code:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(FormCollection collection)
{
    try
    {
        var config = WebConfigurationManager.OpenWebConfiguration("~/Web.config");

        config.AppSettings.Settings["SiteTitle"].Value = collection["SiteTitle"];
        config.AppSettings.Settings["SiteDescription"].Value = collection["SiteDescription"];

        config.Save(ConfigurationSaveMode.Minimal, false);
        ConfigurationManager.RefreshSection("appSettings");

        return RedirectToAction("Index");
    }
    catch (Exception ex)
    {
        ModelState.AddModelError("_FORM", ex.Message);
        return View("Index");
    }
}

...but running it returns the following error:

A configuration file cannot be created for the requested Configuration object.

I've tried granting full permission to all users to the settings file, with no effect (I'm currently just running under Cassini, so the process user is me who has ownership of the file in any case).

Any ideas?

3

3 Answers

21
votes

Change your first line to this:

var config = WebConfigurationManager.OpenWebConfiguration("~");

Confusing as it may be, OpenWebConfiguration expects the virtual path where the Web.config resides, excluding the file name. I guess the logic is that there will only be one Web.config in any given directory so including the name is unnecessary.

The MSDN documentation ultimately clues us in here - if you look at the examples they all use explicit relative paths, and when hosting under IIS allow you to specify config files from other locations, for example:

OpenWebConfiguration("/siteName", "Default Web Site", null, "myServer");

Addendum:

So why does OpenWebConfiguration("~/Web.config") work at all? I'm not sure I can definitively explain it, but try this for kicks: change it to ("~/Foo.bar"). The same result! You can read - your same Web.config file - but cannot write! (now try adding the foo.bar directory to your site, then put a Web.config inside it...)

Since OpenWebConfiguration expects a directory (and apparently allows non-existent ones, as long as it finds a Web.config within the parent), I think this is why mistakenly specifying ~/Web.config as a "path" allows us to load the root config, but not save it.

1
votes

Try this:

var configFile = HttpContext.Current.Server.MapPath("~/Web.config");
var config = WebConfigurationManager.OpenWebConfiguration(configFile);

However, I think it is a bad idea to store this kind of information in the Web.Config, especially if it is intended to be changed dynamically.

Even if you plan to use a separate config file, I would rather store this in another way, and I wouldn't bother to get my own configuration through System.Configuration's classes. They are mostly meant to read ASP.NET apps' Web.Config and Windows apps' App.Config, and making them work with something else is really pointless.

I recommend the following:

Add a separate XML file to your project. (preferably to the App_Data folder, where it can't be accessed from the web, and where your application already has read and write permissions.)

You can then store this sort of settings in that XML, and easily read and write it using System.Xml or LINQ to XML.

0
votes

If you are running this from another project then you'll be using the config from that folder which wont have a config file hence the error that it cannot be created.

You may want to use server.mappath or something like that to get to the web folders config file.