Has anyone got this working in a web application?
No matter what I do it seems that my appSettings section (redirected from web.config using appSettings file=".\Site\site.config") does not get reloaded.
Am I doomed to the case of having to just restart the application? I was hoping this method would lead me to a more performant solution.
Update:
By 'reloading' I mean refreshing ConfigurationManager.AppSettings without having to completely restart my ASP.NET application and having to incur the usual startup latency.
Make sure you are passing the correct case sensitive value to RefreshSection, i.e.
ConfigurationManager.RefreshSection("appSettings");
This seems to be a flaw (maybe a bug) when using an external config file for your appSettings. I've tried it using the configSource attribute and RefreshSection simply never works, I'm assuming this is the same when using the file attribute.
If you move your appSettings back inside your web.config RefreshSection will work perfectly but otherwise I'm afraid you're doomed.
For some reason ConfigurationManager.RefreshSection("appSettings") wasn't working for me. Reloading the Web.Config into a Configuration object seems to work correctly. The following code assumes the Web.Config file is one directory below the executing (bin) folder.
ExeConfigurationFileMap configMap = new ExeConfigurationFileMap();
Uri uriAssemblyFolder = new Uri(System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase));
string appPath = uriAssemblyFolder.LocalPath;
configMap.ExeConfigFilename = appPath + #"\..\" + "Web.config";
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(configMap, ConfigurationUserLevel.None);
And is used like:
string webConfigVariable = config.AppSettings.Settings["webConfigVariable"].Value;
.RefreshSection() does not work when the appSettings is external.
You can however use the following to change a value:
ConfigurationManager.AppSettings.Set(key, value)
This will NOT change the setting on file, only the loaded value in memory.
So instead of using RefreshSection I did the following:
string configFile="path to your config file";
XmlDocument xml = new XmlDocument();
xml.Load(configFile);
foreach (XmlNode node in xml.SelectNodes("/appSettings/add"))
{
string key = node.Attributes["key"].Value;
string value= node.Attributes["value"].Value;
ConfigurationManager.AppSettings.Set(key, value);
}
Any subsequent calls to AppSettings.Get will contain the updated value.
The appSettings will then be updated without needing to restart the application.
As an alternative you could write your own ConfigSection and set restartOnExternalChanges="false".
Then, when reading the section with ConfigurationManager.GetSection("yourSection") the settings will be auto-refreshed without an application restart.
And you could implement your settings strongly typed or as NameValueCollection.
Yes. you are stuck with iis restarting.
There is a feature with asp.net 4.0 and iis 7.5 where the initial startup is removed.
I am not sure if this is possible in a web app, but it works in a desktop app. Try using ConfigurationSettings rather than ConfigurationManager (it will yell at you for using outdated classes...), then reading all the data into a class. When you wish to refresh, simply create a new instance and drop all references to the old instance. My theory for why this works (might be wrong): when you don't directly access the app.config file the entire time you are running, the file lock is dropped by the application. Then, edits can be made when you are not accessing the file.
The App.Config settings are cached in memory when the application starts. For this reason, I don't think you'll be able to change those settings without restarting your application. One alternative that should be pretty straight forward would be to create a separate, simple XML configuration file, and handle loading/caching/reloading it yourself.
To write, call it this way:
Dim config As System.Configuration.Configuration = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~")
Return AddOrUpdateAppSetting(config, "YourSettingKey", "YourValueForTheKey")
To read and be sure you get the values in file, instead of those in cache, read it this way:
Dim config As System.Configuration.Configuration = WebConfigurationManager.OpenWebConfiguration("~")
Return config.AppSettings.Settings("TheKeyYouWantTheValue").Value
Full example:
Protected Shared Function AddOrUpdateAppSetting( _
ByVal Config As System.Configuration.Configuration _
, ByVal TheKey As String _
, ByVal TheValue As String _
) As Boolean</p>
Dim retval As Boolean = True
Dim Itm As System.Configuration.KeyValueConfigurationElement = _
Config.AppSettings.Settings.Item(TheKey)
If Itm Is Nothing Then
If Config.AppSettings.Settings.IsReadOnly Then
retval = False
Else
Config.AppSettings.Settings.Add(TheKey, TheValue)
End If
Else
' config.AppSettings.Settings(thekey).Value = thevalue
If Itm.IsReadOnly Then
retval = False
Else
Itm.Value = TheValue
End If
End If
If retval Then
Try
Config.Save(ConfigurationSaveMode.Modified)
Catch ex As Exception
retval = False
End Try
End If
Return retval
End Function
Have you tried storing your AppSettings in its own external file?
From app.config/web.config:
<appSettings configSource="appSettings.config"></appSettings>
appSettings.config:
<?xml version="1.0"?>
<appSettings>
<add key="SomeKey" value="SomeValue" />
</appSettings>
Changes made to appSettings.config should be reflected instantly.
More info:
http://msdn.microsoft.com/en-us/library/system.configuration.sectioninformation.configsource.aspx
Related
In C# or else VB.Net, and having only a PID of a process, I wonder if it can be possibly to check at execution time whether the associated process has performance counters enabled.
I'll mean when the performanceCounters setting is enabled in its app.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
...
<system.net>
<settings>
<performanceCounters enabled="true"/>
</settings>
</system.net>
...
</configuration>
However, I'm asking about the possible existance of a proper/built-in solution using reflection, or other .Net Framework members than doing a primitive check for an app.config file and then parsing the file to find the setting, I'm aware of that, its what I'm trying to avoid.
As a secondary question I will ask:
How I could check for the same thing in the current process?,
I ask this because maybe the methodology to determine whether performance counters are enabled in the current process could be easier than determining it in an external process (but again I'm asking this for a solution to avoid parsing the app.config file).
You specifically want to avoid parsing the app.config file, but frankly I would. Your question suggest you don't want to "manually" parse the app.config, which you don't have to (So I'll be stubborn on suggest the following ;-))
Check for the current process:
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var group = (NetSectionGroup)config.GetSectionGroup("system.net");
if (group.Settings.PerformanceCounters.Enabled)
{
Console.WriteLine("ENABLED");
}
Check for other processes, well executables really.
var config = ConfigurationManager.OpenExeConfiguration(#" ... path to other executable ... ");
var group = (NetSectionGroup)config.GetSectionGroup("system.net");
if (group.Settings.PerformanceCounters.Enabled)
{
Console.WriteLine("ENABLED");
}
Usually all per-process Performance Counters have PID (or process name or some other identifying information) embedded in Performance Counters Instance Names:
(the part highlighted in yellow is the PID).
So if Process ID is what you have, you can search around instance names for this substring.
I did this Generic usage function for future needs with App config file, maybe it will not be able to parse the tree level architecture in all scenarios, but hey, its just a start.
Usage:
GetAppConfigSetting(Of Boolean)("system.net", "settings", "performanceCounters", "enabled"))
Source:
Public Shared Function GetAppConfigSetting(Of T)(ByVal sectionGroupName As String,
ByVal sectionName As String,
ByVal elementName As String,
ByVal propertyName As String,
Optional ByVal exePath As String = "") As T
Dim appConfig As Configuration
Dim group As ConfigurationSectionGroup
Dim section As ConfigurationSection
Dim sectionPropInfo As PropertyInformation
Dim element As ConfigurationElement
Dim elementPropInfo As PropertyInformation
If Not String.IsNullOrEmpty(exePath) Then
appConfig = ConfigurationManager.OpenExeConfiguration(exePath)
Else
appConfig = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None)
End If
group = appConfig.GetSectionGroup(sectionGroupName)
If group Is Nothing Then
Return Nothing
End If
section = group.Sections(sectionName)
If section Is Nothing Then
Return Nothing
End If
sectionPropInfo = section.ElementInformation.Properties(elementName)
If sectionPropInfo Is Nothing Then
Return Nothing
End If
element = DirectCast(sectionPropInfo.Value, ConfigurationElement)
If element Is Nothing Then
Return Nothing
End If
elementPropInfo = element.ElementInformation.Properties(propertyName)
If elementPropInfo Is Nothing Then
Return Nothing
End If
Return DirectCast(elementPropInfo.Value, T)
End Function
When I try to access configuration section that is encrypted and cannot be decrypted properly (for example, someone just grabbed config file from another machine blindly) - Configuration class is throwing an exception. I want to catch that situation and rewrite the section completely in such case.
I've tried to remove and add back the section in question, but it seems that removal is ignored - second statement in 'catch' throws another exception about such section already exists:
try
{
// this getter might throw an exception - e.g. if encrypted on another machine
var connStrings = config.ConnectionStrings;
}
catch (ConfigurationException)
{
config.Sections.Remove("connectionStrings");
config.Sections.Add("connectionStrings", new ConnectionStringsSection());
}
It might be related to the fact I have connectionStrings section residing in separate file, i.e. my config file has something like <connectionStrings configSource="connections.config"/>, while actual encrypted content is in the connections.config file.
Is it possible to do what I need without falling back to direct XML manipulations, by using .NET Configuration classes only?
I'm pretty sure this will do what you want. In my case, I just included a bogus connectionString setting:
<connectionStrings>
<add connectionString="foo"/>
</connectionStrings>
I didn't include a "name" property, so trying to read ConnectionStrings will blow up, just like in your case:
try {
var x = ConfigurationManager.ConnectionStrings; //blows up
}
catch {
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
config.Sections.Remove("connectionStrings");
config.Save(); //Now save the changes
ConfigurationManager.RefreshSection("connectionStrings"); //and reload the section
var x = ConfigurationManager.ConnectionStrings; //can now read!
}
You still won't be able to do this:
config.Sections.Add("connectionStrings", new ConnectionStringsSection());
Because (at least on my machine), it's picking up connectionStrings from the Machine.config.
I suspect though that in your case that's fine. You are now at a point where if you want to, you can add your own connection strings and you don't really need to completely blow away the connection string section.
i just came up with the reading, Writing and adding values dynamically in web.Config in asp.net. Have many ideas in mind, but i just wana know what is the best way of adding values in web config dynamically.
for example in my case i have to add
<identity userName="someDomain\User" password="password" impersonate="true" />
in
tag in web config from code behind.
waiting for Good responses
I got you and the code you want is :
public void saveIdentity(string username, string password, bool impersonate)
{
Configuration objConfig = WebConfigurationManager.OpenWebConfiguration("~");
IdentitySection identitySection = (IdentitySection)objConfig.GetSection("system.web/identity");
if (identitySection != null)
{
identitySection.UserName = username;
identitySection.Password = password;
identitySection.Impersonate = impersonate;
}
objConfig.Save();
}
I would recommend you to don't try to update web.config dynamically. By doing so your application will be restart and your user session will be expired.
by doing changes in the following your application will always restart
* web.config
* machine.config
* global.asax
* Anything in the bin directory or it's sub-directories
for details have a look aspnet-application-restarts.html
Why are you trying to set the identity in code? This is usually something that should be set up front when the app is deployed and then left alone. If you can explain what you are trying to accomplish we can likely suggest a better way to do it.
Aside from that are you aware that changing your web config will cause the app to restart? All of your server side caching will get dumped, user sessions will be ended, etc. Just because the tool exists to modify the web config from code does not mean doing so is a good idea.
This is in the desktop application but we can use it in web application
if (Convert.ToInt32(txtPortNumber.Text.Trim()) <= 65535)
{
System.Configuration.Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
System.Net.Configuration.MailSettingsSectionGroup mailSection = config.GetSectionGroup("system.net/mailSettings") as System.Net.Configuration.MailSettingsSectionGroup;
mailSection.Smtp.From = txtFrom.Text.Trim();
mailSection.Smtp.Network.Host = txtFrom.Text.Trim();
mailSection.Smtp.Network.UserName = txtFrom.Text.Trim();
mailSection.Smtp.Network.Password = txtPassword.Text.Trim();
mailSection.Smtp.Network.EnableSsl = chkEnableSSL.Checked;
mailSection.Smtp.Network.Port = Convert.ToInt32(txtPortNumber.Text.Trim());
config.Save(ConfigurationSaveMode.Modified);
MessageBox.Show("Your mail setting has been saved successfully.");
Application.Restart();
}
else
{
MessageBox.Show("Port number is not valid, please enter port number between the 0 to 65535.");
}
So I am using C# ASP.NET 3.5 and I would like to add a feature to my site to turn on and off a sort of debug mode for testing purposes.
Is there a best way to have a file or class that stores or returns simply if myDebug is on or off. It has to be accessed fast since it will be used a lot on multiple pages and it should be easy to set using the website itself.
My first thought is just a class with get/set which is stored on every page... perhaps the master page?
Thanks for any input
-Scott
Sounds like something you'd want to put in AppSettings in your web.config.
(I'm assuming that setting compilation debug to true in web.config is insufficient for what you're trying to do.)
Use AppSettings.
You can get your app settings like so:
string appSettingValue = ConfigurationManager.AppSettings["key"];
You can change your app settings like so.
Code below has been copied from blog link above to show as sample:
private void ChangeAppSettings(string key, string NewValue)
{
Configuration cfg;
cfg = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~");
KeyValueConfigurationElement setting = (KeyValueConfigurationElement)cfg.AppSettings.Settings(key);
if ((setting != null)) {
setting.Value = NewValue;
cfg.Save();
}
}
You might have to call ConfigurationManager.RefreshSection("appSettings"); after the save to have the app see the changes.... Im not sure if the cfg.Save() will reload/refresh the settings.
I've got the function for changing the values in web.config
but my problem is it is not getting the path of web.config correctly and throwing
"Could not find file 'C:\Users\maxnet25\Web.config'"
It was giving error on xmlDoc.Load() function.
My code:
public void UpdateConfigKey(string strKey, string newValue)
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(AppDomain.CurrentDomain.BaseDirectory + "..\\..\\Web.config");
if (!ConfigKeyExists(strKey))
{
throw new ArgumentNullException("Key", "<" + strKey + "> not find in the configuration.");
}
XmlNode appSettingsNode = xmlDoc.SelectSingleNode("configuration/appSettings");
foreach (XmlNode childNode in appSettingsNode)
{
if (childNode.Attributes["key"].Value == strKey)
childNode.Attributes["value"].Value = newValue;
}
xmlDoc.Save(AppDomain.CurrentDomain.BaseDirectory + "..\\..\\Web.config");
xmlDoc.Save(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
Label1 .Text ="Key Upated Successfullly";
}
What error messsage is being given?
Either way, you're not really going about modifying web.config in the right way. You should probably take a look at the System.Configuration.ConfigurationManager class as this provides programmatic access to the web.config file in a structured manner. Note that to access this class you need to add a reference to System.Configuration.dll to your project to bring the ConfigurationManager into scope.
If you look at the example code for the GetSection method, it shows how to create/add settings in the appSettings section of a .net config file, so that example should be enough to get you where you want to go.
If you definately want to use this approach to manipulate your web.config file, I suspect that:
AppDomain.CurrentDomain.BaseDirectory + "..\\..\\Web.config")
is incorrect, based on the path that you've shown in the error message. Try removing the ..\..\ and seeing if that works. AppDomain.CurrentDomain.BaseDirectory should be pointing at the location of your web.config file without modification.
Assuming this is indeed an ASP.NET website, instead of this:
AppDomain.CurrentDomain.BaseDirectory + "..\\..\\Web.config"
Use this:
HttpContext.Current.Server.MapPath("~/Web.config")
On a side note, please be aware that anytime you make a change to web.config, your web application restarts. You might not need to worry about that depending on what your web app does though.
Try using Server.MapPath() to resolve the location of your web.config. If you're in a page, Server is one of the page properties. If not, you can find it in HttpContext.Current.
As an example...
HttpContext.Current.Server.MapPath("~/web.config")
...should return the physical path to the web.config at the top of your web application.
Now, you're probably much better off using the WebConfigurationManager, as shown in this post. The approach is much cleaner, but requires a reference to System.Configuration.
Have you added a web.config to your web site?
You should use either:
System.Configuration.ConfigurationManager
for app.config files, or:
System.Web.Configuration.WebConfigurationManager
for web.config files.
You can actually use System.Configuration.ConfigurationManager with web.config files as well, and to be honest, I'm not actually sure if there's any benefit for using one over the other.
But either way, you should not be using the Xml namespaces and writing/modifying the raw XML.