i have been checking around, trying to find a way to write to the exe.config-file.
I can read/write to area just fine, but since we use 2 different DLL's from siemens to automate some stuff, i need to add a bunch of paths in a different section of the exe.config-file.
This is how the config should look like in the structure.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="Siemens.Engineering.dll" value="C:\Program Files (x86)\Siemens\Automation\Portal V13\PublicAPI\V13 SP1\Siemens.Engineering.dll" />
<add key="Siemens.Engineering.Hmi.dll" value="C:\Program Files (x86)\Siemens\Automation\Portal V13\PublicAPI\V13 SP1\Siemens.Engineering.Hmi.dll" />
<add key="TempDirectory" value="D:\Scania Oskarshamn\Alarm_text" />
<add key="AlarmTextPath" value="AlarmTexts" />
<add key="Auto.Compile" value="True" />
<add key="Auto.ExtractAlarms" value="True" />
<add key="Auto.ImportAlarms" value="True" />
<add key="Compile.HMI" value="changes" />
<add key="Lang1" value="sv-SE:Swedish (Sweden)" />
<add key="Lang2" value="en-GB:English (United Kingdom)" />
<add key="Lang3" value="pt-BR:Portugese (Brazil)" />
<add key="LangChecked" value="sv-SE:en-GB" />
</appSettings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Siemens.Engineering" culture="neutral" publicKeyToken="d29ec89bac048f84"/>
<codeBase version="1.2.0.0" href="FILE://C:\Program Files (x86)\Siemens\Automation\Portal V13\PublicAPI\V13 SP1\Siemens.Engineering.dll"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Siemens.Engineering.Hmi" culture="neutral" publicKeyToken="37b6e3a80df0900f"/>
<codeBase version="1.2.0.0" href="FILE://C:\Program Files (x86)\Siemens\Automation\Portal V13\PublicAPI\V13 SP1\Siemens.Engineering.Hmi.dll"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
I need to change the href part in the tags, and if this section does not exist, i also need to add the whole structure below .
I just need to write these parts.
EDIT: Now i dont even need the paths in the config, using registry to lookup path and use AssemblyResolve to make it work.
Solved this by using:
public frmAutomate(AutoData autoData)
{
InitializeComponent();
AppDomain CurrentDomain = AppDomain.CurrentDomain;
CurrentDomain.AssemblyResolve += new ResolveEventHandler(MyResolver);
}
private static Assembly MyResolver(object sender, ResolveEventArgs args)
{
int index = args.Name.IndexOf(',');
if (index == -1)
{
return null;
}
string name = args.Name.Substring(0, index) + ".dll";
// Check for 64bit installation
RegistryKey filePathReg = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Wow6432Node\\Siemens\\Automation\\_InstalledSW\\TIAP13\\TIA_Opns");
// Check for 32bit installation
if (filePathReg == null)
filePathReg = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Siemens\\Automation\\_InstalledSW\\TIAP13\\TIA_Opns");
string filePath = filePathReg.GetValue("Path").ToString() + "PublicAPI\\V13 SP1";
string path = Path.Combine(filePath, name);
// User must provide the correct path
string fullPath = Path.GetFullPath(path);
if (File.Exists(fullPath))
{
return Assembly.LoadFrom(fullPath);
}
return null;
}
Related
i can't figure out what i do wrong.
My project is like that :
MainProject
SubProject (referencing my desires DLL)
I have my app.config (of MainProject) :
<configuration>
<configSections>
<section name="DirectoryServerConfiguration" type="System.Configuration.NameValueSectionHandler"/>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,Log4net"/>
<section name="GeneralConfiguration" type="System.Configuration.NameValueSectionHandler"/>
<section name="ServerConnectionConfiguration" type="System.Configuration.NameValueSectionHandler"/>
<section name="cachingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Caching.Configuration.CacheManagerSettings,Microsoft.Practices.EnterpriseLibrary.Caching"/>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/>
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="ReferencesDLL" />
</assemblyBinding>
</runtime>
<GeneralConfiguration configSource="ConfigFiles\GeneralConfiguration.config"/>
<cachingConfiguration configSource="ConfigFiles\cachingConfiguration.config"/>
<DirectoryServerConfiguration configSource="ConfigFiles\YPAdress.config"/>
<log4net configSource="ConfigFiles\log4net.config"/>
</configuration>
And my compile repository is like that :
Debug
ConfigFiles\ (All the .config files defined in the app.config)
ReferencesDLL\ (All the Dll needed by SubProject)
(All the others compiled files : .exe, .dll, etc..)
As you can see, i have my privatePath define, but when running the app, it can't find the needed dll for SubProject. (no problem for the .config files)
I don't know what i did wrong :( .
You could manually look for the assembly at the known location using an AppDomain.AssemblyResolve event handler:
static void Run()
{
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
// Do work...
AppDomain.CurrentDomain.AssemblyResolve -= CurrentDomain_AssemblyResolve;
}
static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
var dllName = new AssemblyName(args.Name).Name + ".dll";
var assemblyPath = Assembly.GetExecutingAssembly().Location;
var referenceDirectory = new DirectoryInfo(Path.Combine(Path.GetDirectoryName(assemblyPath), "ReferencesDLL"));
if (!referenceDirectory.Exists)
return null; // Can't find the reference directory
var assemblyFile = referenceDirectory.EnumerateFiles(dllName, SearchOption.TopDirectoryOnly).FirstOrDefault();
if (assemblyFile == null)
return null; // Can't find a matching dll
return Assembly.LoadFrom(assemblyFile.FullName);
}
New to C# programming, and I'm kind of stuck right now. How would I create a simple program that let's me extract and display the data source value in connectionStrings. And lets me modify the Id and password? Am I on the right track with parsing
Document X = XDocument.Load("C:\Users\Odd_Creature\Desktop\SecureConfig\\UserProfiles\UserInfo.exe.config")
var configuration= X.Element("configuration").Element("connectionStrings");
var location = configuration.Descendants("").Attributes("").FirstOrDefault().Value;
doc.Save(xmlfile);
XMLFILE
<configuration>
<configProtectedData />
<system.diagnostics />
<system.windows.forms />
<uri />
<appSettings>
<add key="GenerateProfile" value="true" />
<add key="TestScore" value="30" />
<add key="TestApplicationName" value="User Account" />
</appSettings>
<connectionStrings>
<add name="MyExample.database" connectionString="data source=.\SQLEXPRESS;initial catalog=wadb;integrated security=false;encrypt=true;trustservercertificate=true;User Id=Tester;Password=Test1;"
providerName="System.Data.SqlClient" />
</connectionStrings>
This would be a brute force approach to parsing the connection string from an XML file.
static void Main(string[] args)
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("settings.xml");
string connectionStrings = xmlDoc.GetElementsByTagName("connectionStrings")[0].InnerXml;
string tag = "connectionString=\"";
string connectionString = connectionStrings.Substring(connectionStrings.IndexOf(tag) + tag.Length);
string[] tokens = connectionString.Split(';');
Console.WriteLine(tokens.FirstOrDefault(t => t.Contains("data source=")));
Console.WriteLine(tokens.FirstOrDefault(t => t.Contains("User Id=")));
Console.WriteLine(tokens.FirstOrDefault(t => t.Contains("Password=")));
}
And the output would be:
data source=.\SQLEXPRESS
User Id=Tester
Password=Test1
With a little more code, you should be able to edit these fields, and then use xmlDoc.Save() to update your changes.
I have a config file for my program as follows
<appSettings>
<add key="ShowDebugWindow" value="false"/>
<add key="AppDataSubFolder" value="DLI\Keymon"/>
<add key="KeymonSettingsFile" value="Keymon.xml"/>
<add key="KeymonSettingsFileExtension" value="XML"/>
</appSettings>
With some digging around I found out how I can A) check if that key exists B) add a new one if needed. Since my program is in Program Files I found out that to avoid having the config file saved to virtual store that I have to have my program run as admin. That is not allowable so I decided to make a console project that would fix this for me. Easy enough.
So i did this
public static int Main(string[] args)
{
FixConfigFile();
return 0;
}
private static void FixConfigFile()
{//warning if the program is writing to a protect area, the config file might be redirected to virtual store
UpdateSettingIfMissing("ShowDebugWindow", "false");
UpdateSettingIfMissing("AppDataSubFolder", "DLI\\Keymon");
UpdateSettingIfMissing("KeymonSettingsFile", "Keymon.xml");
UpdateSettingIfMissing("KeymonSettingsFileExtension", "XML");
UpdateSettingIfMissing("LeftButton1", "");
UpdateSettingIfMissing("RightButton1", "");
UpdateSettingIfMissing("FunctionButton1", "");
UpdateSettingIfMissing("FunctionButton2", "");
UpdateSettingIfMissing("FunctionButton3", "");
UpdateSettingIfMissing("FunctionButton4", "");
UpdateSettingIfMissing("FunctionButton5", "");
UpdateSettingIfMissing("FunctionButton6", "");
}
private static void UpdateSettingIfMissing(string key, string defaultValue)
{
var setting = ConfigurationManager.AppSettings[key];
if (setting == null)
{
UpdateSetting(key, defaultValue);
}
}
private static void UpdateSetting(string key, string value)
{
Configuration configuration = ConfigurationManager.OpenExeConfiguration(#"Keymon.exe");
configuration.AppSettings.Settings.Add(key, value);
configuration.Save(ConfigurationSaveMode.Minimal);
}
The config file then would look like this
<add key="ShowDebugWindow" value="false,false" />
<add key="AppDataSubFolder" value="DLI\Keymon" />
<add key="KeymonSettingsFile" value="Keymon.xml,Keymon.xml" />
<add key="KeymonSettingsFileExtension" value="XML,XML" />
<add key="LeftButton1" value="" />
<add key="RightButton1" value="" />
<add key="FunctionButton1" value="" />
<add key="FunctionButton2" value="" />
<add key="FunctionButton3" value="" />
<add key="FunctionButton4" value="" />
<add key="FunctionButton5" value="" />
<add key="FunctionButton6" value="" />
notice that the value now has "2" values that are comma separated... WHY??? So as a test I deleted all keys, and ran my program. The values are all correct now, but now keymon crashes because the key/values were not loaded. Which is strange because in keymon i run this..
if (RunFixer)
{
System.Diagnostics.Process.Start("KeymonConfigFixer.exe");
ConfigurationManager.RefreshSection("appSettings");
}
So i don't get it. What am I missing? why is it doing this? Help
It's because in UpdateSettingIfMissing you use ConfigurationManager.AppSettings[key] which opens the app settings for the current application (your console app) while in UpdateSetting you open the settings for Keymon.exe
I'm creating an application on .net framework 4.5
whenever i want to load the app config values (appSettings section) and write the changes, i don't see my changes if i refresh the section. What i am doing wrong? and how can i solve it?
code
private void LoadConfig()
{
NameValueCollection appSettings = ConfigurationManager.AppSettings;
for (int i = 0; i < appSettings.Count; i++)
{
switch (appSettings.GetKey(i))
{
case "initialCatalog":
txtInitialCatalog.Text = appSettings.GetValues(i)[0];
break;
case "dataSource":
txtDatasource.Text = appSettings.GetValues(i)[0];
break;
case "userName":
txtUsername.Text = appSettings.GetValues(i)[0];
break;
case "password":
txtPassword.Text = appSettings.GetValues(i)[0];
break;
case "portalUrl":
txtUrl.Text = appSettings.GetValues(i)[0];
break;
}
}
}
private void SaveConfig()
{
System.Configuration.Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
KeyValueConfigurationCollection appSettings = config.AppSettings.Settings;
appSettings["initialCatalog"].Value = txtInitialCatalog.Text;
appSettings["dataSource"].Value = txtDatasource.Text;
appSettings["userName"].Value = txtUsername.Text;
appSettings["password"].Value = txtPassword.Text;
appSettings["portalUrl"].Value = txtUrl.Text;
config.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("appSettings");
}
App.config file
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<appSettings>
<add key="initialCatalog" value="a" />
<add key="dataSource" value="b" />
<add key="password" value="c" />
<add key="userName" value="d" />
<add key="portalUrl" value="e" />
<add key="poolingTime" value="60000" />
<add key="ClientSettingsProvider.ServiceUri" value="" />
</appSettings>
i call ReadConfig() when the forms is Activated and save the data when a button is pressed (Ok or Apply) i close the application i rerun it but no changes are made to the app.config file
any ideas???
I think what is happening is that you are testing in Visual Studio, it copys the App.Config to your Debug/Release directory and renames it YourApplication.vshost.exe.config which gets reset each time you start your application. Try running the executable outside of Visual Studio which will use the YourApplication.exe.config file and see if that works for you. Your Code is working for me and retaining your changes on application restart if I run it outside of Visual Studio.
usually, I do this:
...
config.AppSettings.Settings.Remove("TextBoxNumber");
config.AppSettings.Settings.Add("TextBoxNumber", "");
It works fine. I guess it is because one of your key is not in the app.config yet. You need Remove/Add it (like the above code), or, create the key in the app.config first.
====================
Update
Try this:
config.AppSettings.Settings["initialCatalog"].Value = txtInitialCatalog.Text;
instead of
appSettings["initialCatalog"].Value = txtInitialCatalog.Text;
Any difference?
We are in need to add performance monitoring to our application.
For the prototype I've created a sample project, which I'm trying to get into work.
I'm trying to use policyInjection for the performance counters, so we'll be able to turn on and off the performance monitoring in the production environment.
So far I can see the actual category in perfmon, but I cannot see any instances (see image), even I'm pretty sure the application is running and instance exists, as you can see in attached sources.
I've tried a lot of things, also googled around, but didn't find any usable solution or clue what to look for.
Application is created as consoleApplication
You can also download a zipped project for VS here:
http://dl.dropbox.com/u/19457132/stackOverflow/Mpd.Instrumentation.PerformanceCounter.zip
Here are my sources.
Program.cs
using System;
using System.Collections;
using System.Configuration.Install;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.PolicyInjection;
using Microsoft.Practices.EnterpriseLibrary.PolicyInjection.Installers;
namespace Mpd.Instrumentation.PerformanceCounter
{
class Program
{
static void Main(string[] args)
{
//RemoveCounters();
InstallCounters();
MyCounters myCounter = PolicyInjection.Create<MyCounters>();
for (int i = 0; i < 100000000; i++)
{
myCounter.SampleMethod(i);
}
Console.ReadLine();
}
public static void InstallCounters()
{
PerformanceCountersInstaller installer = new PerformanceCountersInstaller(new SystemConfigurationSource());
IDictionary state = new Hashtable();
installer.Context = new InstallContext();
installer.Install(state);
installer.Commit(state);
Console.WriteLine("Performance counters have been successfully installed. Press enter to continue");
Console.ReadLine();
}
private static void RemoveCounters()
{
PerformanceCountersInstaller installer = new PerformanceCountersInstaller(new SystemConfigurationSource());
installer.Context = new InstallContext();
installer.Uninstall(null);
Console.WriteLine("Performance counters have been successfully removed. Press enter to continue.");
Console.ReadLine();
}
}
}
MyCounters.cs
using System;
using System.Threading;
namespace Mpd.Instrumentation.PerformanceCounter
{
public class MyCounters : IPerformanceCounter
{
public void SampleMethod(int i)
{
Console.WriteLine(i);
Thread.Sleep(50);
}
}
}
IPerformanceCounter.cs
using System;
namespace Mpd.Instrumentation.PerformanceCounter
{
public class IPerformanceCounter : MarshalByRefObject
{
}
}
And finally app.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="policyInjection" type="Microsoft.Practices.EnterpriseLibrary.PolicyInjection.Configuration.PolicyInjectionSettings, Microsoft.Practices.EnterpriseLibrary.PolicyInjection, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="false" />
<section name="instrumentationConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Common.Instrumentation.Configuration.InstrumentationConfigurationSection, Microsoft.Practices.EnterpriseLibrary.Common, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="false" />
</configSections>
<policyInjection>
<policies>
<add name="SampleCountersPolicy">
<matchingRules>
<add type="Microsoft.Practices.EnterpriseLibrary.PolicyInjection.MatchingRules.MethodSignatureMatchingRule, Microsoft.Practices.EnterpriseLibrary.PolicyInjection, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
match="SampleMethod" ignoreCase="true" name="Method Signature Matching Rule" />
</matchingRules>
<handlers>
<add type="Microsoft.Practices.EnterpriseLibrary.PolicyInjection.CallHandlers.PerformanceCounterCallHandler, Microsoft.Practices.EnterpriseLibrary.PolicyInjection, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
categoryName=".aaaTest" instanceName="Default" useTotalCounter="true"
incrementNumberOfCalls="true" incrementCallsPerSecond="true"
incrementAverageCallDuration="true" incrementTotalExceptions="true"
incrementExceptionsPerSecond="true" order="1" name="Performance Counter Call Handler" />
</handlers>
</add>
</policies>
</policyInjection>
<instrumentationConfiguration performanceCountersEnabled="true"
applicationInstanceName="Default" />
</configuration>
Since the SampleMethod accepts a parameter you need to add that to the matching rules configuration:
<matchingRules>
<add type="Microsoft.Practices.EnterpriseLibrary.PolicyInjection.MatchingRules.MethodSignatureMatchingRule, Microsoft.Practices.EnterpriseLibrary.PolicyInjection, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
match="SampleMethod" ignoreCase="true" name="Method Signature Matching Rule">
<parameters>
<parameter name="i" typeName="System.Int32" />
</parameters>
</add>
</matchingRules>
Without the parameter the matching rule does not match so the call handler is not invoked. If you modify the configuration you should see the instances in perfmon.