Adding values in web config dynamically? How To + Best way - c#

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.");
}

Related

Best practice for peristantly storing a string on a C# IIS WCF web service

I have a text string I want to persist in a WCF web service. What is the best practice for storing it between sessions and between reboots/restarts of IIS?
Storing it in a text file on the operating system? Or is there a built in persistence object?
This string is a piece of text I need to return from the web service and occasionally update via a call being made to the web service. (The web service has a Read Only database back end, so I don't have the option to save this string to a database--without adding a separate database call and I'd rather avoid that extra point of failure.)
You mean a connection string? web.config
Or a password, or key? web.config
Something that's displayed to the user? resource table
P.s. I ended up using the web.config solution. For those interested in doing what I did here's the hoops I jumped through:
1) Set up a directory under the web application's root and opened that up to write permission to the IISUser. (Used a sub directory to avoid compromising security in the main application directory) Then added the following to the top of my source code:
System.Configuration.Configuration _webConfig =
WebConfigurationManager.OpenWebConfiguration("~\\directory_where_IISUser_has_write_permisions\\");
2) Namespaces needed:
using System.Web.Configuration;
using System.Configuration;
3) Code to create a new setting. The try/catch handles when the setting doesn't exist. Yes, it's a total hack. If someone knows how to check for the existence of the setting please let me know in a comment!
try
{
_webConfig.AppSettings.Settings["SettingName"].Value = textMessage;
} catch {
_webConfig.AppSettings.Settings.Add("SettingName", textMessage);
}
_webConfig.Save(ConfigurationSaveMode.Modified);
4) Code to read:
TextMessage = _webConfig.AppSettings.Settings["SettingName"].Value;
EDIT:
You can do something like:
bool bKeyExists = false;
foreach (SettingsProperty settingsProperty in appSettings.Properties)
{
if (settingsProperty.Name == _strKey)
{
bKeyExists = true;
break;
}
}
Or, with LINQ:
bool bKeyExists = appSettings.Properties.Cast<SettingsProperty>().Where(x => x.Name == _strKey).FirstOrDefault() != null;

How to change DCOM config identity programmatically

Is there any way to get the information about Launching identity of DCOM application programmatically. See the picture attached to understand what i mean.
I tried to use WMI
ManagementObjectSearcher s = new ManagementObjectSearcher(new ManagementScope(#"\\.\root\cimv2"), new ObjectQuery(
"select * from Win32_DCOMApplicationSetting where AppID='{048EB43E-2059-422F-95E0-557DA96038AF}'"))
ManagementObjectCollection dcomSett = s.Get();
var value = dcomSett.Cast<ManagementObject>().ToArray()
[0].Properties["RunAsUser"].Value;
but "RunAsUser" property was empty.
Also tried Interop.COMAdmin
COMAdmin.COMAdminCatalogClass catalog = (COMAdmin.COMAdminCatalogClass)new COMAdmin.COMAdminCatalog();
(COMAdmin.COMAdminCatalogCollection)catalog.GetCollection("Applications")
in this way i managed to get applications which are listed under the "COM+ Applications" node in the "Component Services" snap-in of MMC:
I'm new in COM, DCOM, COM+ stuff and sure that i missed something important.
After a while i found out why i used to get NULL in the first approach (ManagementObject).
You will receive:
NULL if identity is currently set to The launching user
"Interactive User" in case of "The interactive user"
some string with username in case of third option (see the first picture)
But still i need a way to change identity for items like Microsoft PowerPoint Slide under DCOM Config node in MMC.
In the DCOM config, if you are using a specific user for the identity and you want to update the password via code, you need to update it in the Local Security Authority (LSA). This is possible with Windows API calls. MS has some sample code for a utility called dcomperm that does it, and you can see how they implemented in C++. You could make the same calls in C#. See the SetRunAsPassword method here. They are using the method LsaOpenPolicy to get a handle to the policy and calling LsaStorePrivateData to update the password. Then they are adding "login as a batch job" access to the account (but that shouldn't be necessary if you are only changing the password).
This sample code on pinvoke.net looks like it is making the requisite calls, except for the optional part about granting the login as a batch job permission. Note the "key" in the LSA is in the format SCM:{GUID-of-DCOM-object} Example: SCM:{00000000-0000-0000-0000-000000000000}
Oh, and I should mention as an aside that if you wanted to change the RunAs user itself (i.e. the username), you'd need to also update that in the windows registry directly (AFAIK that's the only way to do it). DCOM entries are stored under HKLM\SOFTWARE\Classes\AppID. You can do that with WMI or just use the Registry classes in .NET.
This is very simple , you can get APPId from
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AppID\{048EB43E-2059-422F-95E0-557DA96038AF}
using
(RegistryKey dcomPPTIdentity = Registry.LocalMachine.OpenSubKey("Software\\Classes\\AppID\\{048EB43E-2059-422F-95E0-557DA96038AF}"))
{
if (dcomPPTIdentity != null)
{
Registry.SetValue(dcomPPTIdentity.ToString(), "RunAs", "userName");
}
}
I am using COMAdmin DLL successfully. Try something like this:
COMAdminCatalog catalog = new COMAdminCatalog();
COMAdminCatalogCollection applications = catalog.GetCollection("Applications");
applications.Populate();
for (int i = 0; i < applications.Count; i++)
{
COMAdminCatalogObject application = COMAppCollectionInUse.Item[i];
if (application.Name == "Your COM+ application name")
{
application.Value["Identity"] = "nt authority\\localservice"; // for example
}
}
This works for me on my development server. Keep in mind, it is run against the server directly on the server
using COMAdmin;
using System;
namespace ComComponents
{
class Program
{
static void Main(string[] args)
{
COMAdminCatalog catalog = new COMAdminCatalog();
COMAdminCatalogCollection applications = catalog.GetCollection("Applications");
applications.Populate();
for (int i = 0; i < applications.Count; i++)
{
COMAdminCatalogObject application = applications.Item[i];
Console.WriteLine(application.Name);
Console.WriteLine(application.Value["Identity"]);
}
Console.WriteLine("Press any key to continue...");
Console.ReadKey();
}
}
}

Store & Return Settings for a Webpage

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.

web.config in asp.net

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.

Reloading configuration without restarting application using ConfigurationManager.RefreshSection

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

Categories

Resources