Web.config save problem - c#

I want to expose some of the web.config settings to a user via the front end of the web app. I can retrieve the settings without a problem, but when I save I either get an error or the changes are not persisted to the web.config file. I am debugging in VS.
If I run this:
private void SaveWebConfig()
{
Configuration webConfig = WebConfigurationManager.OpenWebConfiguration("~//Web.config");
webConfig.AppSettings.Settings["DocumentPath"].Value = this.txtDocumentsDirectory.Text;
webConfig.Save();
}
I get the following error:
A configuration file cannot be created for the requested Configuration object.
If I run this code, nothing happens:
private void SaveWebConfig()
{
Configuration webConfig = WebConfigurationManager.OpenWebConfiguration("~//Web.config");
webConfig.AppSettings.Settings["DocumentPath"].Value = this.txtDocumentsDirectory.Text;
webConfig.SaveAs("~//Web.config");
}

To my knowledge the web.config should not be altered by the consuming web application. ASP.NET and IIS are built to restart the whole application every time the web.config is updated.
Instead of exposing it expose settings from the database and persist these settings in the db, your front end should not change much only the way you load and save data does.

It can be done, and it is rather easy. Whether it works depends on the privileges of the user account that your App runs under.
You are using double forward slashes, and the SaveAs is wrong too. Try:
private void SaveWebConfig()
{
Configuration webConfig = WebConfigurationManager.OpenWebConfiguration("~");
webConfig.AppSettings.Settings["DocumentPath"].Value =
this.txtDocumentsDirectory.Text;
webConfig.Save();
}
But you probably should avoid changing the (root) web.config as much as possible. I've only seen this in special pages for the SiteManager to make config changes.

Related

Modify appSettings section of web.config file programatically [duplicate]

I am confused on how to modify the web.config appSettings values at runtime. For example, I have this appSettings section:
<appSettings>
<add key="productspagedesc" value="TODO: Edit this default message" />
<add key="servicespagedesc" value="TODO: Edit this default message" />
<add key="contactspagedesc" value="TODO: Edit this default message" />
<add key="aboutpagedesc" value="TODO: Edit this default message" />
<add key="homepagedesc" value="TODO: Edit this default message" />
</appSettings>
Let's say, I want to modify the "homepagedesc" key at runtime. I tried ConfigurationManager and WebConfigurationManager static classes, but the settings are "read-only". How do I modify appSettings values at runtime?
UPDATE:
Ok, so here I am 5 years later. I would like to point out that experience has told me, we should not put any configuration that intentionally is editable at runtime in the web.config file but instead we should put it in a separate XML file as what one of the users commented below. This will not require any of edit of web.config file to restart the App which will result with angry users calling you.
You need to use WebConfigurationManager.OpenWebConfiguration():
For Example:
Dim myConfiguration As Configuration = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~")
myConfiguration.ConnectionStrings.ConnectionStrings("myDatabaseName").ConnectionString = txtConnectionString.Text
myConfiguration.AppSettings.Settings.Item("myKey").Value = txtmyKey.Text
myConfiguration.Save()
I think you might also need to set AllowLocation in machine.config. This is a boolean value that indicates whether individual pages can be configured using the element. If the "allowLocation" is false, it cannot be configured in individual elements.
Finally, it makes a difference if you run your application in IIS and run your test sample from Visual Studio. The ASP.NET process identity is the IIS account, ASPNET or NETWORK SERVICES (depending on IIS version).
Might need to grant ASPNET or NETWORK SERVICES Modify access on the folder where web.config resides.
Changing the web.config generally causes an application restart.
If you really need your application to edit its own settings, then you should consider a different approach such as databasing the settings or creating an xml file with the editable settings.
And if you want to avoid the restart of the application, you can move out the appSettings section:
<appSettings configSource="Config\appSettings.config"/>
to a separate file. And in combination with ConfigurationSaveMode.Minimal
var config = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~");
config.Save(ConfigurationSaveMode.Minimal);
you can continue to use the appSettings section as the store for various settings without causing application restarts and without the need to use a file with a different format than the normal appSettings section.
2012
This is a better solution for this scenario (tested With Visual Studio 2008):
Configuration config = WebConfigurationManager.OpenWebConfiguration(HttpContext.Current.Request.ApplicationPath);
config.AppSettings.Settings.Remove("MyVariable");
config.AppSettings.Settings.Add("MyVariable", "MyValue");
config.Save();
Update 2018 =>
Tested in vs 2015 - Asp.net MVC5
var config = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~");
config.AppSettings.Settings["MyVariable"].Value = "MyValue";
config.Save();
if u need to checking element exist, use this code:
var config = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~");
if (config.AppSettings.Settings["MyVariable"] != null)
{
config.AppSettings.Settings["MyVariable"].Value = "MyValue";
}
else { config.AppSettings.Settings.Add("MyVariable", "MyValue"); }
config.Save();
I know this question is old, but I wanted to post an answer based on the current state of affairs in the ASP.NET\IIS world combined with my real world experience.
I recently spearheaded a project at my company where I wanted to consolidate and manage all of the appSettings & connectionStrings settings in our web.config files in one central place. I wanted to pursue an approach where our config settings were stored in ZooKeeper due to that projects maturity & stability. Not to mention that fact that ZooKeeper is by design a configuration & cluster managing application.
The project goals were very simple;
get ASP.NET to communicate with ZooKeeper
in Global.asax, Application_Start - pull web.config settings from ZooKeeper.
Upon getting passed the technical piece of getting ASP.NET to talk to ZooKeeper, I quickly found and hit a wall with the following code;
ConfigurationManager.AppSettings.Add(key_name, data_value)
That statement made the most logical sense since I wanted to ADD new settings to the appSettings collection. However, as the original poster (and many others) mentioned, this code call returns an Error stating that the collection is Read-Only.
After doing a bit of research and seeing all the different crazy ways people worked around this problem, I was very discouraged. Instead of giving up or settling for what appeared to be a less than ideal scenario, I decided to dig in and see if I was missing something.
With a little trial and error, I found the following code would do exactly what I wanted;
ConfigurationManager.AppSettings.Set(key_name, data_value)
Using this line of code, I am now able to load all 85 appSettings keys from ZooKeeper in my Application_Start.
In regards to general statements about changes to web.config triggering IIS recycles, I edited the following appPool settings to monitor the situation behind the scenes;
appPool-->Advanced Settings-->Recycling-->Disable Recycling for Configuration Changes = False
appPool-->Advanced Settings-->Recycling-->Generate Recycle Event Log Entry-->[For Each Setting] = True
With that combination of settings, if this process were to cause an appPool recycle, an Event Log entry should have be recorded, which it was not.
This leads me to conclude that it is possible, and indeed safe, to load an applications settings from a centralized storage medium.
I should mention that I am using IIS7.5 on Windows 7. The code will be getting deployed to IIS8 on Win2012. Should anything regarding this answer change, I will update this answer accordingly.
Who likes directly to the point,
In your Config
<appSettings>
<add key="Conf_id" value="71" />
</appSettings>
in your code(c#)
///SET
ConfigurationManager.AppSettings.Set("Conf_id", "whateveryourvalue");
///GET
string conf = ConfigurationManager.AppSettings.Get("Conf_id").ToString();
Try This:
using System;
using System.Configuration;
using System.Web.Configuration;
namespace SampleApplication.WebConfig
{
public partial class webConfigFile : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
//Helps to open the Root level web.config file.
Configuration webConfigApp = WebConfigurationManager.OpenWebConfiguration("~");
//Modifying the AppKey from AppValue to AppValue1
webConfigApp.AppSettings.Settings["ConnectionString"].Value = "ConnectionString";
//Save the Modified settings of AppSettings.
webConfigApp.Save();
}
}
}

Environment Variables in web.config

Working on a webapp on VS2017 using MVC framework on .NET 4.5. In my local dev environment, I use the web.config file something like this:
<appSettings>
<add key="GOOGLE_APPLICATION_CREDENTIALS"
value="C:\\Work\\Services-abcd.json" />
</appSettings>
But when I run the webapp I still get the error that GOOGLE_APPLICATION_CREDENTIALS is undefined.
So my question specifically is:
Where am I going wrong? Do I need to define it somewhere else?
When I deploy this to staging/production, on my azure web service, how will I share the json file and how will the web.config file need to change for that?
I know this question answers how to get the variables in web.config, but somehow I am not able to set it there.
Edit 1: Since I was asked, here is where I am getting the error of missing environment variable-
using Google.Cloud.Translation.V2;
TranslationClient client = TranslationClient.Create();
I am unable to declare TranslationClient.
Where am I going wrong? Do I need to define it somewhere else?
According to your codes and description, I found you have defined the app setting not the environment variables. Notice: app setting isn't as same as environment variables.
If you want to set environment variables in the azure web app, I suggest you could set it in your web application codes and upload the application to the app service as below:
Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", Server.MapPath("test/test.txt"));
When I deploy this to staging/production, on my azure web service, how will I share the json file and how will the web.config file need to change for that?
I suggest you could create a folder to store the json file in your web application, then you could use Server.MapPath to get the right path of your json file.
Since I don't have the google cloud app credentials json file, so I add a txt file in my test demo to test the code could work well.
More details about my test demo, you could refer to below codes.
protected void Page_Load(object sender, EventArgs e)
{
Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", Server.MapPath("test/test.txt"));
}
protected void Button1_Click(object sender, EventArgs e)
{
string path = Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS");
Response.Write(path + "\n");
string[] lines = System.IO.File.ReadAllLines(path);
foreach (string line in lines)
{
Response.Write(line);
}
}
Result(111 is the txt file content):

Why doesn't ASP.NET TempData work when modifying Web.config?

I have a function in my Global.asax.cs file that applies a couple changes to the Web.config file, if needed. The file is saved with:
config.Save(ConfigurationSaveMode.Modified);
I recently discovered that TempData wasn't working for my app: it appeared to be empty on the next request. My MCVE:
public ActionResult Foo()
{
TempData["error"] = "testing error passing";
return RedirectToAction("Bar");
}
public ActionResult Bar()
{
throw new Exception(TempData["error"] as string);
}
I added that to my HomeController, and visiting /Home/Foo would redirect to /Home/Bar. However, with the above config.Save line active, I get:
Server Error in '/' Application.
Exception of type 'System.Exception' was thrown.
But if I comment out that line, I get:
Server Error in '/' Application.
test error passing
as I was expecting originally.
(I had a couple instances where I got the inverse result, but it was usually on the first request after I commented or un-commented the line, so probably I should blame caching.)
Why does this happen, and how can I fix it?
Based from this question:
What happens when I edit web.config?
Imagine each ASP.NET application (as defined in IIS) is a program on
the desktop. Saving web.config will do something similar to closing
the program and reopening it. - Dan Goldstein
IIS default behavior automatically reset entire session state and recycles existing AppDomain when any changes applied to web.config file at runtime, thus all values stored on TempData array are lost, leaving null values instead.
When config.Save line left uncommented, the line:
throw new Exception(TempData["error"] as string);
will contain null value from TempData["error"]:
throw new Exception(null);
Since as operator returns null if the object doesn't exist, it throws new Exception instance with null string, causing default exception message to show instead of custom one.
If config.Save line commented, the configuration changes doesn't applied into web.config file, thus existing AppDomain remains running and TempData values are still in place.
The default behavior can be changed by these steps:
Open IIS Manager.
Select Application Pools => [your application pool name] => Advanced Settings.
On Recycling area, find Disable Recycling for Configuration Changes (DisallowRotationOnConfigChange) section and set it to True.
Related problem: How to prevent an ASP.NET application restarting when the web.config is modified?
TempData stores the values in session and it seems your default session store is InProc which stores the data in server memory which is mainly running under the AppDomain for the Application Pool
By Default, when there is any change in the files under virtual directory, IIS detects that using a File Watcher and recycle the application pool, this will de-allocate all the memory assigned to this web application.
To avoid that, you can change session mode to be either Database or State Server.
But the best thing is to avoid changing the web.config at all, if you have any configuration that is user defined or need to be changed at run time, then you have to store it somewhere else and cache to avoid any performance hits

Reload configuration settings from an external config file during run-time

I'm writing a game server in C# and would like to reload or refresh settings from a config file while the server is running.
Ideally I would like to save the settings in an XML file, have the ability to edit
the file while the game server is running and then send the server the command to reload
the settings from the file.
I know I can use a database to do this as well, but the game server is fairly small and I think it would be more practical to just save settings in a flat-file. I will have file-level access to the machine the server will run on.
What should I use?
Use http://msdn.microsoft.com/en-us/library/system.configuration.configurationmanager.aspx
Use a Custom Configuration Section, hookup the sections from the app.config to external config file(s) by setting the location attrib of the section. All xml loading and serialization is done by those custom classes
Code provided by CarelZA:
First of all, ConfigurationManager caches the application's configuration by config section, and you can call ConfigurationManager.RefreshSection() to invalidate the cache for a specific section.
In app.config I added:
<configSections>
<section name="gameSettings"
type="System.Configuration.NameValueSectionHandler,system , Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, Custom=null"/>
</configSections>
<gameSettings configSource="game.config"/>
I created a file called "game.config" and set "Copy to Output Directory" to "Copy always".
In game.config:
<gameSettings>
<add key="SettingName" value="SettingValue" />
</gameSettings>
Then in code, in order to access any setting:
settings = (NameValueCollection) ConfigurationManager.GetSection("gameSettings");
return settings["SettingName"];
And to reload the game config at any time when the reload command is sent to the server:
ConfigurationManager.RefreshSection("gameSettings");
As per request posting my comment as an answer:
You can set it up so the server auto-loads the file settings with FileSystemWatcher. If you use a custom Settings class, you can simply lock the class, reload it from a file and unlock it (if you are using multiple threads).
Reading/writing from/to file or serialization is so trivial in .NET that that is probably not what you need help with and there are many options how to do it.
Sounds like a job for XML Serialization! Instead of manually parsing and editing XML, you can easily achieve this same effect by creating a settings object, serializing it to XML, and de/serializing it when you need to make modifications. This way, you could hot swap configuration files.
using System.Xml.Serialization;
For instance, you could have the object
public class Settings
{
public string SomeProperty {get; set;}
public string SomeProperty2 {get; set;}
}
Save it to your disk as,
var settings = new Settings {SomeProperty="Hello", SomeProperty2="Joe"};
var fs = new FileStream("settings.xml");
var xs = new XmlSerializer(settings.GetType());
xs.Serialize(fs,settings);
Read it back in as,
var fs = new FileStream("settings.xml");
var settings = (Settings)fs.Deserialize(fs);
Check out the MemoryCache in System.Runtime.Caching (.NET 4.0). You could write yourself a simple class which performs the following steps:
Load the XML file
Parse its contents into whatever representation you want them in
Store the output in the cache with a HostFileChangeMonitor watching it - this will cause it to be removed from the cache automatically when the file is changed
Before performing any of the above, you'd check the cache to see if a previously-cached copy of the settings exists and only proceed if it doesn't.
The advantage of rolling your own approach like this is that you do not trigger restarts of the application as is the case with AppSettings stored in your web.config or app.config files. (It should be said that this is not the only way of achieving this)

What is preferred method for modifying connection string settings in DAL class library when deploying asp.net web app?

I deployed my asp.net web app project that has a reference to my DAL class library. How can I change the connection string in my DAL library once deployed? The DAL code was ignoring my web.config connection string and trying to use the app.config value.
I thought I would be able to edit a config file that is associated with the class library, but I can't find one. Temporarily I edited the connection string and re-compiled and re-deployed the library.
Is there an option or way to setup the project files where it changes the values of the connection string based on being compiled in debug mode versus doing a release compile.
What is the recommended way of dealing with connection strings in web apps which reference class libraries?
Clarification:
the DAL library connection strings are also utilized by some datasets and L2S classes (.dbml) and I am not sure how to change those to reference a web.config file that sits outside the library in the web app project.
Currently Using this code to get around my L2S class problem:
public partial class MyDataContext
{
partial void OnCreated()
{
ConnectionStringSettings cs = ConfigurationManager.ConnectionStrings["PrimaryConnectionString"];
if (cs != null)
{
this.Connection.ConnectionString = cs.ConnectionString;
}
}
}
Generally, I let the top-level project define this, via either web.config or app.config; either by specifying that the application should include a connection-string named "FOO", or (much better) allowing the calling application to pass (one of) the connection key, the connection string, or the connection to the dll.
Then you mainly just edit web.config like normal...
I usually place the string in the web.config file and let a class (possibly a global class used to reference settings in the web.config) reference it, with the following line:
class Globals
{
static string ConnectionString =
ConfigurationManager.ConnectionStrings["dbConnection"].ConnectionString;
}
and use it elsewhere like:
IApartmentRepository apartmentRepository = new
ApartmentRepository(Globals.ConnectionString);
This was also Saif Khan's suggestion in his answer.
As for changing the connection strings based on compile mode, Visual Studio 2010 has support for this, see Web Deployment: Web.Config Transformation from the Visual Web Developer team blog. I do not think Visual Studio 2008 can do this out of the box, however maybe it can be done with some kind of build script.
I don't believe there is a recommended way, but a prefered way. Some store connection strings in the web.config file, while some store in the registry or machine.config, while some go to the extreme and store it remotely...yes I've seen that.
The most common storage I see and use myself is storing in the web.config. In my DAL objects I make a call to the web.config file for the connectionstring
string connStr = ConfigurationManager.ConnectionStrings["myString"].ConnectionString
as for auto changing of the connectionstring based on the app compiled mode, I've never seen that. You might have to put that check in the DAL itself to check if debug mode is turned "on" or "off". That would require 2 connectionstring entries in the web.config file.

Categories

Resources