Encrypting connection string: "This operation does not apply at runtime" - c#

I have a console application and it has app.config. When I run this code:
class Program
{
static void Main()
{
ConnectionStringsSection connSection = ConfigurationManager.GetSection("connectionStrings") as
ConnectionStringsSection;
if (connSection != null)
{
if (!connSection.SectionInformation.IsProtected)
connSection.SectionInformation.ProtectSection("RsaProtectedConfigurationProvider");
else
connSection.SectionInformation.UnprotectSection();
}
Console.Read();
}
}
I get error: "This operation does not apply at runtime". I also tried giving permissions to my app.config but no luck.
What can the issue?

You can try the following:
static void Main()
{
// Get the current configuration file.
System.Configuration.Configuration config =
ConfigurationManager.OpenExeConfiguration(
ConfigurationUserLevel.None);
ConnectionStringsSection connSection = config.GetSection("connectionStrings") as
ConnectionStringsSection;
if (connSection != null)
{
if (!connSection.SectionInformation.IsProtected)
connSection.SectionInformation.ProtectSection(null);
else
connSection.SectionInformation.UnprotectSection();
}
connSection.SectionInformation.ForceSave = true;
config.Save(ConfigurationSaveMode.Full);
Console.ReadKey();
}

I think you are supposed to use the OpenExeConfiguration method in this scenario:
System.Configuration.Configuration config =
ConfigurationManager.OpenExeConfiguration(pathToExecutable);
ConnectionStringsSection connSection =
config .GetSection("connectionStrings") as ConnectionStringsSection;
the parameter pathToExecutable should be the full path to the exe of your application, for example: "C:\application\bin\myapp.exe"

You are not supposed to encrypt sections at runtime, you encrypt them before runtime with the aspnet_setreg.exe tool. More info here.
ASP.NET then reads the encrypted sections at runtime transparently.

Related

Dynamically changing the value of AppSettings in App.config in a WCF WebService

I'm trying to change the value of a key in the <appSettings> section of the app.config file at runtime so that it represents a proper date, but for some reason when running the program it doesn't change anything at all. I've tried the code and it worked in other occasions with test projects, but for some reason it doesn't work here.
Here's the code in question:
private void ChangeSyncDate(DateTime date)
{
System.Configuration.Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); // Open App.config
config.AppSettings.Settings["SyncDate"].Value = date.ToString();
config.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("appSettings");
}
And this is the function that uses that code:
public List<Business.Reservation> RequestReservationRetrieval()
{
string syncstring = ConfigurationManager.AppSettings["SyncDate"];
List<Business.Reservation> webReservations;
using (repo = new ReservationRepository())
{
webReservations = repo.ObtainReservations();
}
if(syncstring.Equals("nil"))
{
ChangeSyncDate(DateTime.Now); // and here
return webReservations;
}
else
{
DateTime syncdate = Convert.ToDateTime(syncstring);
foreach(Reservation r in webReservations)
{
if (r.Date <= DateTime.Now && r.Date >= syncdate)
webReservations.Remove(r);
}
ChangeSyncDate(DateTime.Now); // here
return webReservations;
}
}
As it stands, the value in app.config that I mean to change isn't changing at all.
This is the value I'm trying to modify:
<appSettings>
<add key="SyncDate" value="nil"/>
</appSettings>
Thank you for taking the time to read this.
You should be using WebConfigurationManager not ConfigurationManager to open the AppSettings. Give it a try.

Using Configuration manager?

Looking at an example where the server receives a file on the streamReader from the client.
string key = "UploadSalesFileToServer";
GetValue(key);
is added to the function, which uses:
private static string GetValue(string name)
{
var fileMap = new ExeConfigurationFileMap();
fileMap.ExeConfigFilename = System.Web.HttpContext.Current.Server.MapPath("~/Modules/Work/web.config");
var configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
string configValue = configuration.AppSettings.Settings[name].Value;
return configValue;
}
and in web.config I use:
<appSettings>
<add key="UploadSalesFileToServer"
value="1111-fasad-32233-ffdsff"/>
</appSettings>
Can anyone tell me what happens here through out? the app settings is used to check the correct file is being received?
GetValue trying to read config value from configuration file which is not exactly application configuration and situated in different directory under relative path "~/Modules/Work/web.config"

App config for dynamically loaded assemblies

I'm trying to load modules into my application dynamically, but I want to specify separate app.config files for each one.
Say I have following app.config setting for main app:
<appSettings>
<add key="House" value="Stark"/>
<add key="Motto" value="Winter is coming."/>
</appSettings>
And another for library that I load using Assembly.LoadFrom:
<appSettings>
<add key="House" value="Lannister"/>
<add key="Motto" value="Hear me roar!"/>
</appSettings>
Both libraries have a class implementing the same interface, with the following method:
public string Name
{
get { return ConfigurationManager.AppSettings["House"]; }
}
And sure enough calls to Name from both main class and loaded assembly class output Stark.
Is there a way to make main app use its own app.config and each loaded assembly use theirs? Names of config files are different in the output, so that should be possible I think.
Ok, here's the simple solution I ended up with:
Create the follow function in the utility library:
public static Configuration LoadConfig()
{
Assembly currentAssembly = Assembly.GetCallingAssembly();
return ConfigurationManager.OpenExeConfiguration(currentAssembly.Location);
}
Using it in dynamically loaded libraries like this:
private static readonly Configuration Config = ConfigHelpers.LoadConfig();
No matter how that library gets loaded it uses the correct config file.
Edit:
This might be the better solution for loading files into ASP.NET applications:
public static Configuration LoadConfig()
{
Assembly currentAssembly = Assembly.GetCallingAssembly();
string configPath = new Uri(currentAssembly.CodeBase).LocalPath;
return ConfigurationManager.OpenExeConfiguration(configPath);
}
To copy file after build you might want to add the following line to post-build events for asp app (pulling the config from library):
copy "$(SolutionDir)<YourLibProjectName>\$(OutDir)$(Configuration)\<YourLibProjectName>.dll.config" "$(ProjectDir)$(OutDir)"
As far as I know, you need separate application domains for the app.config to work separately. The creation of an AppDomainSetup allows you to specify which config file to use. Here's how I do it:
try
{
//Create the new application domain
AppDomainSetup ads = new AppDomainSetup();
ads.ApplicationBase = Path.GetDirectoryName(config.ExePath) + #"\";
ads.ConfigurationFile =
Path.GetDirectoryName(config.ExePath) + #"\" + config.ExeName + ".config";
ads.ShadowCopyFiles = "false";
ads.ApplicationName = config.ExeName;
AppDomain newDomain = AppDomain.CreateDomain(config.ExeName + " Domain",
AppDomain.CurrentDomain.Evidence, ads);
//Execute the application in the new appdomain
retValue = newDomain.ExecuteAssembly(config.ExePath,
AppDomain.CurrentDomain.Evidence, null);
//Unload the application domain
AppDomain.Unload(newDomain);
}
catch (Exception e)
{
Trace.WriteLine("APPLICATION LOADER: Failed to start application at: " +
config.ExePath);
HandleTerminalError(e);
}
Another way you could go about getting the desired effect would be to implement your configuration values inside a resource file compiled into each of your DLLs. A simple interface over the configuration object would allow you to switch out looking in an app.config versus looking in a resource file.
It may work if you change the code little bit:
public string Name
{
get {
Configuration conf = ConfigurationManager.OpenExeConfiguration("library.dll");
return conf.AppSettings.Settings["House"].Value;
}
}

Loading Properties.Settings from a different file at runtime

Is there any way to load settings from a different file other than the default App.config file at runtime? I'd like to do this after the default config file is loaded.
I use the Settings.Settings GUI in Visual Studio to create my App.config file for me. The config file ends up looking like this:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="SnipetTester.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</sectionGroup>
</configSections>
<applicationSettings>
<SnipetTester.Properties.Settings>
<setting name="SettingSomething" serializeAs="String">
<value>1234</value>
</setting>
</SnipetTester.Properties.Settings>
</applicationSettings>
</configuration>
In code, I'm able to access the settings like this:
Console.WriteLine("Default setting value: " + Properties.Settings.Default.SettingSomething);
The idea is that when the application is run, I should be able to specify a config file at run time and have the application load the config file into the Properties.Settings.Default object instead of using the default app.config file. The formats of the config files would be the same, but the values of the settings would be different.
I know of a way to do this with the ConfigurationManager.OpenExeConfiguration(configFile);. However, in the tests that I've run, it doesn't update the Properties.Settings.Default object to reflect the new values from the config file.
After thinking about this a bit longer, I've been able to come up with a solution that I like a little better. I'm sure it has some pitfalls, but I think it'll work for what I need it to do.
Essentially, the Properties.Settings class is automatically generated by Visual Studio; it generates the code for the class for you. I was able to find where the code was generated and add a few function calls to load a config file on its own. Here's my addition:
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{
//Parses a config file and loads its settings
public void Load(string filename)
{
System.Xml.Linq.XElement xml = null;
try
{
string text = System.IO.File.ReadAllText(filename);
xml = System.Xml.Linq.XElement.Parse(text);
}
catch
{
//Pokemon catch statement (gotta catch 'em all)
//If some exception occurs while loading the file,
//assume either the file was unable to be read or
//the config file is not in the right format.
//The xml variable will be null and none of the
//settings will be loaded.
}
if(xml != null)
{
foreach(System.Xml.Linq.XElement currentElement in xml.Elements())
{
switch (currentElement.Name.LocalName)
{
case "userSettings":
case "applicationSettings":
foreach (System.Xml.Linq.XElement settingNamespace in currentElement.Elements())
{
if (settingNamespace.Name.LocalName == "SnipetTester.Properties.Settings")
{
foreach (System.Xml.Linq.XElement setting in settingNamespace.Elements())
{
LoadSetting(setting);
}
}
}
break;
default:
break;
}
}
}
}
//Loads a setting based on it's xml representation in the config file
private void LoadSetting(System.Xml.Linq.XElement setting)
{
string name = null, type = null, value = null;
if (setting.Name.LocalName == "setting")
{
System.Xml.Linq.XAttribute xName = setting.Attribute("name");
if (xName != null)
{
name = xName.Value;
}
System.Xml.Linq.XAttribute xSerialize = setting.Attribute("serializeAs");
if (xSerialize != null)
{
type = xSerialize.Value;
}
System.Xml.Linq.XElement xValue = setting.Element("value");
if (xValue != null)
{
value = xValue.Value;
}
}
if (string.IsNullOrEmpty(name) == false &&
string.IsNullOrEmpty(type) == false &&
string.IsNullOrEmpty(value) == false)
{
switch (name)
{
//One of the pitfalls is that everytime you add a new
//setting to the config file, you will need to add another
//case to the switch statement.
case "SettingSomething":
this[name] = value;
break;
default:
break;
}
}
}
}
The code I added exposes an Properties.Settings.Load(string filename) function. The function accepts a config filename as a parameter. It will parse the file and load up any settings it encounters in the config file. To revert back to the original configuration, simply call Properties.Settings.Reload().
Hope this might help someone else!
Look at using ExeConfigurationFileMap and ConfigurationManager.OpenMappedExeConfiguration.
See Cracking the Mysteries of .Net 2.0 Configuration
The ExeConfigurationFileMap allows you to specifically configure the
exact pathnames to machine, exe, roaming and local configuration
files, all together, or piecemeal, when calling
OpenMappedExeConfiguration(). You are not required to specify all
files, but all files will be identified and merged when the
Configuration object is created. When using
OpenMappedExeConfiguration, it is important to understand that all
levels of configuration up through the level you request will always
be merged. If you specify a custom exe and local configuration file,
but do not specify a machine and roaming file, the default machine and
roaming files will be found and merged with the specified exe and user
files. This can have unexpected consequences if the specified files
have not been kept properly in sync with default files.
It depends on the type of the application:
Web Application & Windows Application - use the configSource xml attribute if you are willing to store the config files in the same folder (or subfolders) as the application
Create a settings provider and also implement IApplicationSettingsProvider. Samples here and here. You might also need to use the IConfigurationManagerInternal interface to replace the default .NET configuration manager. When implementing the provider don't forget to make a difference between user settings and application settings and the roaming profiles.
If you want to get started quickly just decompile the LocalFileSettingsProvider class (the default settings provider) and change it to your needs (you might find some useles code and might need to replicate all of the classes on which it depends).
Good luck
You can include the types so you don't need to manually update the source every time.
`private void LoadSetting(System.Xml.Linq.XElement setting)
{
string name = null, type = null;
string value = null;
if (setting.Name.LocalName == "setting")
{
System.Xml.Linq.XAttribute xName = setting.Attribute("name");
if (xName != null)
{
name = xName.Value;
}
System.Xml.Linq.XAttribute xSerialize = setting.Attribute("serializeAs");
if (xSerialize != null)
{
type = xSerialize.Value;
}
System.Xml.Linq.XElement xValue = setting.Element("value");
if (xValue != null)
{
if (this[name].GetType() == typeof(System.Collections.Specialized.StringCollection))
{
foreach (string s in xValue.Element("ArrayOfString").Elements())
{
if (!((System.Collections.Specialized.StringCollection)this[name]).Contains(s))
((System.Collections.Specialized.StringCollection)this[name]).Add(s);
}
}
else
{
value = xValue.Value;
}
if (this[name].GetType() == typeof(int))
{
this[name] = int.Parse(value);
}
else if (this[name].GetType() == typeof(bool))
{
this[name] = bool.Parse(value);
}
else
{
this[name] = value;
}
}
}`

How To Read UnitTest Project's App.Config From Test With HostType("Moles")

I have the folowing tests:
[TestClass]
public class GeneralTest
{
[TestMethod]
public void VerifyAppDomainHasConfigurationSettings()
{
string value = ConfigurationManager.AppSettings["TestValue"];
Assert.IsFalse(String.IsNullOrEmpty(value), "No App.Config found.");
}
[TestMethod]
[HostType("Moles")]
public void VerifyAppDomainHasConfigurationSettingsMoles()
{
string value = ConfigurationManager.AppSettings["TestValue"];
Assert.IsFalse(String.IsNullOrEmpty(value), "No App.Config found.");
}
}
The only difference between them is [HostType("Moles")]. But the first passes and the second fails. How can I read App.config from the second test?
Or may be I can add some another config file in other place?
Assuming you are trying to access values in appSettings, how about just adding the configuration at the beginning of your test. Something like:
ConfigurationManager.AppSettings["Key"] = "Value";
Then when your test tries to read the AppSettings "Key", "Value" will be returned.
You just add your "App.Config" file to the unit test project . It will read automatically.
See http://social.msdn.microsoft.com/Forums/en/pex/thread/9b4b9ec5-582c-41e8-8b9c-1bb9457ba3f6
In the mean time, as a work around, you could try adding the configuration settings to Microsoft.Moles.VsHost.x86.exe.config
[ClassInitialize]
public static void MyClassInitialize(TestContext testContext)
{
System.Configuration.Moles.MConfigurationManager.GetSectionString =
(string configurationName) =>
{
ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
Assembly assembly = Assembly.GetExecutingAssembly();
fileMap.ExeConfigFilename = assembly.Location + ".config";
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
object section = config.GetSection(configurationName);
if (section is DefaultSection)
{
ConfigurationSection configurationSection = (ConfigurationSection) section;
Type sectionType = Type.GetType(configurationSection.SectionInformation.Type);
if (sectionType != null)
{
IConfigurationSectionHandler sectionHandler =
(IConfigurationSectionHandler)AppDomain.CurrentDomain.CreateInstanceAndUnwrap(sectionType.Assembly.FullName, sectionType.FullName);
section =
sectionHandler.Create(
configurationSection.SectionInformation.GetParentSection(),
null,
XElement.Parse(configurationSection.SectionInformation.GetRawXml()).ToXmlNode());
}
}
return section;
};
}
I ran across this issue at work and didn't like any of these answers. I also have the problem that the configuration file is being read in a static constructor which means I can't Mole ConfigurationManager before the static constructor is executed.
I tried this on my home computer and found that the configuration file was being read correctly. It turns out I was using Pex 0.94.51006.1 at home. This is slightly older than the current one. I was able to find a download for the older academic version:
http://research.microsoft.com/en-us/downloads/d2279651-851f-4d7a-bf05-16fd7eb26559/default.aspx
I installed this on my work computer and everything is working perfectly. At this point, I'm downgrading to the older version until a newer working version is released.
This is what I am using to get the correct AppConfig and ConnectionString sections:
var config = System.Configuration.ConfigurationManager.OpenExeConfiguration(Reflection.Assembly.GetExecutingAssembly().Location);
typeof(Configuration.ConfigurationElementCollection).GetField("bReadOnly", Reflection.BindingFlags.Instance | Reflection.BindingFlags.NonPublic).SetValue(System.Configuration.ConfigurationManager.ConnectionStrings, false);
foreach (Configuration.ConnectionStringSettings conn in config.ConnectionStrings.ConnectionStrings)
System.Configuration.ConfigurationManager.ConnectionStrings.Add(conn);
foreach (Configuration.KeyValueConfigurationElement conf in config.AppSettings.Settings)
System.Configuration.ConfigurationManager.AppSettings(conf.Key) = conf.Value;
Saw the ConnectionString part here

Categories