How to read any '.config' file in c# but its own - c#

How to read a .config file using ConfigurationManager or any other way.
Below is my code which gives the following error:
'System.Configuration.ConfigurationElement.this
[System.Configuration.ConfigurationProperty] is inaccessible due to
its protection level.'
ExeConfigurationFileMap configFileMap = new ExeConfigurationFileMap();
//txtConfigFile gets a config file path at runtime
configFileMap.ExeConfigFilename = txtConfigFile.FilePath;
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(configFileMap, ConfigurationUserLevel.None);
//Configpath's value is assigned to a textbox named txtConfigPath
txtConfigPath = config.AppSettings["Configpath"];

Configuration.AppSettings returns an AppSettingSections object, AppSettingSections is derived from ConfigurationSection which is derived from ConfigurationElement which defines a this[] operator as protected internal, which mean that it is "inaccessible due to its protection level."
You should try AppSettings.Settings:
txtConfigPath = config.AppSettings.Settings["Configpath"];

Related

Location of |DataDirectory| in WebApi project/template

I do realize there are many questions here on how to change the value of |DataDirectory|. My question is slightly different.
I realized that if you are using a WebApi project with EntityFramework, then the |DataDirectory| points to the App_Data folder which is created by default. I believe the same is true for an MVC project.
So my question is where can I find the code that has specified App_Data as |DataDirectory| in these standard templates. I just want to use the same code for my class library
Thanks
|DataDirectory| is defined in HttpRuntime class under System.Web assembly.
I decompiled System and System.Web assembly and I found source code for AppDomain class and some DataDirectory related following code.
App_Data is a hard coded string in the assembly. However it can be overridden using AppDomain.CreateDomain() method.
Here is the code I found.
Global variable in HttpRuntime class
internal const string DataDirectoryName = "App_Data";
And a function in HttpRuntime class
private void SetUpDataDirectory()
{
string path = Path.Combine(this._appDomainAppPath, "App_Data");
AppDomain.CurrentDomain.SetData("DataDirectory", (object) path, (IPermission) new FileIOPermission(FileIOPermissionAccess.PathDiscovery, path));
}
I found another piece of code in System.Data.Common assembly under DbConnectionOptions.cs file. Here is the code.
internal const string DataDirectory = "|datadirectory|";
And then I found another code in System.Web.DataAccess assembly under SqlConnectionHelper class. Here is the code.
[PermissionSet(SecurityAction.Assert, Unrestricted = true)]
internal static string GetDataDirectory()
{
if (HostingEnvironment.IsHosted)
return Path.Combine(HttpRuntime.AppDomainAppPath, "App_Data");
string path1 = AppDomain.CurrentDomain.GetData("DataDirectory") as string;
if (string.IsNullOrEmpty(path1))
{
string path1_1 = (string) null;
Process currentProcess = Process.GetCurrentProcess();
ProcessModule processModule = currentProcess != null ? currentProcess.MainModule : (ProcessModule) null;
string path2 = processModule != null ? processModule.FileName : (string) null;
if (!string.IsNullOrEmpty(path2))
path1_1 = Path.GetDirectoryName(path2);
if (string.IsNullOrEmpty(path1_1))
path1_1 = Environment.CurrentDirectory;
path1 = Path.Combine(path1_1, "App_Data");
AppDomain.CurrentDomain.SetData("DataDirectory", (object) path1, (IPermission) new FileIOPermission(FileIOPermissionAccess.PathDiscovery, path1));
}
return path1;
}
This means, |DataDirectory| is defined and used at multiple places. But it's common place to get the data is from HttpRuntime and AppDomain property.
I am using JetBrain's DotPeek to decompile these assemblies. I hope the same helps you.

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;
}
}

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

How do I retrieve AppSettings from the assembly config file?

I would like to retrieve the AppSetting key from the assembly config file called: MyAssembly.dll.config. Here's a sample of the config file:
<configuration>
<appSettings>
<add key="MyKey" value="MyVal"/>
</appSettings>
</configuration>
Here's the code to retrieve it:
var myKey = ConfigurationManager.AppSettings["MyKey"];
Using the OpenMappedExeConfiguration gives you back a "Configuration" object which you can use to peek into the class library's config (and the settings that exist there will override the ones by the same name in the main app's config):
ExeConfigurationFileMap map = new ExeConfigurationFileMap();
map.ExeConfigFilename = "ConfigLibrary.config";
Configuration libConfig = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
AppSettingsSection section = (libConfig.GetSection("appSettings") as AppSettingsSection);
value = section.Settings["Test"].Value;
But those settings that are unique to the main app's config and do not exist in the class library's own config are still accessible via the ConfigurationManager static class:
string serial = ConfigurationManager.AppSettings["Serial"];
That still works - the class library's config only hides those settings that are inside its config file; plus you need to use the "libConfig instance to get access to the class library's own config settings, too .
The two worlds (main app.config, classlibrary.config) can totally and very happily co-exist - not a problem there at all!
Marc
var appSettings = ConfigurationManager.OpenExeConfiguration((Assembly.GetAssembly(typeof(MYASSEMBLY))).Location).AppSettings;
then you can do as above.
You can also open it up as an XmlDocument and navigate the document with Xpath. THen there is always LinqToXml
var uri = new Uri(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().CodeBase));
var fileMap = new ExeConfigurationFileMap { ExeConfigFilename = Path.Combine(uri.LocalPath, "MyAssembly.dll.config") };
var assemblyConfig = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
Using System.Configuration
Public Shared Function AppDomainConfiguration() As Configuration
Dim fileMap As New ExeConfigurationFileMap
fileMap.ExeConfigFilename = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile
Return ConfigurationManager.OpenMappedExeConfiguration(fileMap,Configuration.ConfigurationUserLevel.None)
End Function

Categories