I am having problems with a application that wants to write to the .exe.config.
See following code:
using System;
using System.Configuration;
using System.IO;
namespace ConfigurationManagerError
{
class Program
{
static void Main(string[] args)
{
try
{
// set Config-File to persistent folder
ExeConfigurationFileMap exeMap = new ExeConfigurationFileMap();
exeMap.ExeConfigFilename = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData),
"ConfigError\\ConfigurationManagerError.exe.config");
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(exeMap, ConfigurationUserLevel.None);
config.AppSettings.Settings.Add(
new KeyValueConfigurationElement("TestKey", "TestValue"));
config.Save(ConfigurationSaveMode.Modified);
Console.WriteLine("Successfully write of Configuration-File to " + config.FilePath);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
Console.Read();
}
}
}
As long as I run as a user with read and write access on the folder everything works.
If I have a user that has no write permission in the folder there is a exception that says that permission to write the .exe.config is not allowed.
Until now everything is as expected.
But if I now have a user that has the right to write to existing files but not to create new files an exception is thrown with something like
Access to the path 'C:\ProgramData\ConfigError\ila2ba_0.tmp' is denied
It seems that ConfigurationManager wants to create a tmp-File.
How can this be solved?
Thanks a lot!
Best regards,
Joerg
A user specific configuration setting which need to be rewritten multiple times should be saved under user's application data directory.
You can have a generic application configuration installed along with your application which can be merged with user specific configuration and required config setting can be overridden as per your requirement.
Related
I'm trying to write log in Windows event viewer. I created class and create method for catching exceptions. Here is my code :
[EventSource(Name = "Samples-EventSourceDemos-EventLog")]
public sealed class MinimalEventSource : EventSource
{
public static MinimalEventSource Log = new MinimalEventSource();
[NonEvent]
public void WriteLog(Exception exception)
{
UnhandledException(exception.Message);
}
[Event(601, Message = "Unhandled exception occurred. Details: {0}", Keywords = EventKeywords.None, Level = EventLevel.Critical)]
private void UnhandledException(string exceptionMsg)
{
this.WriteEvent(601, exceptionMsg);
}
}
static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
throw new Exception("TestException");
}
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
MinimalEventSource.Log.WriteLog(e.ExceptionObject as Exception);
Process.GetCurrentProcess().Kill();
}
In Windows event viewer I couldn't find this log
I installed Microsoft.Diagnostics.Tracing.EventSource from nuget. It creates manifests after rebuilding. Here is debug folder
I decided to registr it by code :
string commandOfRegistringEventSource = "";
using (Process process = new Process())
{
ProcessStartInfo startInfo = new ProcessStartInfo
{
WindowStyle = ProcessWindowStyle.Hidden,
FileName = "cmd.exe",
Arguments = commandOfRegistringEventSource
};
process.StartInfo = startInfo;
process.Start();
}
I tried execute using wevtutil.exe im <EtwManifestManFile> /rf:"<EtwManifestDllFile>" /mf:"<EtwManifestDllFile>", but it shows errors like The system cannot find the file specified.,... Please help me to write cmd command of registring EventSource. Here is manifest
C:\Users\dilshodk\source\repos\ETW loggiing\ETW loggiing\bin\Debug\ETW loggiing.Samples-EventSourceDemos-EventLog.etwManifest.dll
C:\Users\dilshodk\source\repos\ETW loggiing\ETW loggiing\bin\Debug\ETW loggiing.Samples-EventSourceDemos-EventLog.etwManifest.man
You need some more steps to get this working. First of all, you need to set the Channel property of the Event attribute like this:
[EventSource(Name = "Samples-EventSourceDemos-EventLog")]
public sealed class MinimalEventSource : EventSource
{
public static MinimalEventSource Log = new MinimalEventSource();
[NonEvent]
public void WriteLog(Exception exception)
{
UnhandledException(exception.Message);
}
[Event(601, Channel = EventChannel.Admin, Message = "Unhandled exception occurred. Details: {0}", Keywords = EventKeywords.None, Level = EventLevel.Critical)]
private void UnhandledException(string exceptionMsg)
{
this.IsEnabled().Dump();
this.WriteEvent(601, exceptionMsg);
}
}
The, second, your EventSource need to be registered. The steps are outline here:
One requirement introduced by channel support is the need to statically register the ETW provider manifest. The NuGet package supports generating the files needed for static registration as part of your build. After your build completes a new step is run that generates a pair of files for each of the event source types defined in the project:
..etwManifest.man and
..etwManifest.dll
The first file contains the ETW manifest while the second one contains the binary form of the ETW manifest plus any needed native resources (localization string tables in particular).
The tool that generates the above two files is “eventRegister.exe” and it performs two functions:
It ensures the registration files are generated for all event source types that need static registration, and
It performs a number of validation checks on all the event source types defined in the output assembly.
Deploying your component will need to include these files and perform one registration step at installation time and one un-registration step at un-installation time.
Registration:
wevtutil.exe im <EtwManifestManFile> /rf:"<EtwManifestDllFullPathName>" /mf:"<EtwManifestDllFullPathName>"
Unregistration:
wevtutil.exe um <EtwManifestManFile>
For static registration eventRegister.exe generates manifests that include all localization information. This is needed because the manifest is generated at build time, when there’s no information regarding the culture in which the final application will run.
Note you will see that in the .etwManfest.man file that the build generated, there are path names for the resource file and manifest file in this file. They are the paths that existed at build time. These paths are NOT used if you use the /rf and /mf options. Thus you should always specify the /rf: and /mf options (unless you hand modify the .etwManifest.man file to specify deployment-time file paths for the DLL).
Finally, it is important that you use FULLY qualified names for the /mf: and /rf: options. You can use environment variables THAT ARE AVAILABLE TO ALL PROCESSes (e.g. %SystemRoot% or %ProgramFiles%), but you should not use relative paths (it is not clear what they are relative to, probably System32, but don’t count on it).
The general recommendation is to copy your etwManifest.dll and .etwManifest.man to a directory under %ProgramFiles% and then use wevtutil to register them at that location.
The easiest way to create the files described above is to add this NuGet Package as it will create those files when building your project. It comes with the docs in .docx format.
I have done this in the past write to the event log Application:
using (EventLog eventLog = new EventLog("Application"))
{
eventLog.Source = "Application";
eventLog.WriteEntry("Log message test", EventLogEntryType.Information, 101, 1);
}
I have a set of applications that I want to share applications settings. Let’s call them App1, App2 and App3
I created a common project in a separate namespace and handled the getting and setting of user configurations values in this project. I used the Settings tab in that project’s properties to create the user setting values.
For example in a static Configuration class in the MyCommon namespace, I have these methods:
public static Config PopulateConfig()
{
// Config is a simple class containing values pulled from the user config
Config result = new Config();
try {
result.ImportArchiveFolder = MyCommon.Properties.Settings.Default.ArchiveFolder;
result.ReportFolder = MyCommon.Properties.Settings.Default.ReportFolder;
}
catch (Exception ex) {
MessageBox.Show("Error loading configuration: " + ex.Message,
"Configuration error",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
return result;
}
public static void SaveConfig(Config config)
{
try {
if (config.ImportArchiveFolder != MyCommon.Properties.Settings.Default.ArchiveFolder) {
MyCommon.Properties.Settings.Default.ArchiveFolder = config.ImportArchiveFolder;
}
if (config.ReportArchiveFolder != MyCommon.Properties.Settings.Default. ReportFolder) {
MyCommon.Properties.Settings.Default.ReportFolder = config.ReportArchiveFolder;
}
MyCommon.Properties.Settings.Default.Save();
}
catch (Exception ex) {
MessageBox.Show("Error saving configuration: " + ex.Message,
"Configuration error",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
While it works to be able to read and save these values it saves them under the individual exe’s name such as App2 rather than MyCommon in the user’s AppData structure.
Username\AppData\MyCompany\App1_Url_randomString\V1.0.1.0\user.config
Username\AppData\MyCompany\App2_Url_randomString\V1.0.1.0\user.config
If tried to use the ConfigurationManager.OpenMappedExeConfiguration to open a fixed copy but have run into a stumbling block.
I think I need to know where to tell it to place this shared configuration, I wanted to see it managed automatically in the AppData folder, but I don’t know how to specify the “Special folder” that reflects the shared assembly’s version. I would want the config to follow the shared project.
File structure should be something like this
Username\AppData\MyCompany\MyCommon_Url_randomString\V1.0.1.0\user.config
The nice thing about the ConfigurationManager is that if I change the version of the assembly it will read the previous values and create a new folder with those so I can run both versions of the program with independent consideration of their configurations. I'd like to keep that in this shared scenario.
Username\AppData\MyCompany\MyCommon_Url_randomString\V1.0.1.0\user.config
\V1.0.1.1\user.config
I ended up using the registry with the Settings as the initial defaults.
The shared programs used the registry for the settings. When the program started it would look to see if there were any settings in the common registry and if so it would use those. If not it would use it's own settings file for defaults.
The option editor allows the administrator to edit the options for all of the shared applications, saving all settings to the common registry folder.
C# application.exe not working in Win10,but it worked on my Win7. I tried to debug in Win10 it shows me this error which is correct in win7.
using System;
using System.Windows.Forms;
using System.IO;
namespace WindowsFormsApplication2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
string fullComputerName = Environment.MachineName;
//Create a Folder Path
string createFolderPath = #"C:\\Users\\" +fullComputerName+"\\Documents\\Cheques";
//Create a File Inside of a Folder
string createTxtFile= createFolderPath + "\\ChequeForDeposit.TXT";
try
{
if(!Directory.Exists(createFolderPath))
{ return; }
Directory.CreateDirectory(createFolderPath);
}
catch { }
finally { }
if(!File.Exists(createTxtFile))
{ File.Create(createTxtFile); }//The error is here
}
}
}
when i check in my win7 pc, it creates a folder and a text file. But not in Win10. it is so strange.
Your try/catch does not ensure that directory folder will exist (may generate an exception when you try to create the folder). So before creating the file, check immediately folder is exists.
Your condition is incorrect. If folder not exists then you should return, otherwise create.
try
{
if(Directory.Exists(createFolderPath) && !File.Exists(createTxtFile))
{
File.Create(createTxtFile);
}
}
Also check the permission issue. e.g. Check the permissions for the desktop folder. In Windows Explorer right click on the desktop folder, select properties and there go to the security tab. You should have write permission for that folder.
i think the folder C:\Users\ is Protected system folder by design. either you have to run as Administrator or create the file in some other drive, for eg:
#"D:\Users\" +fullComputerName+"\Documents\Cheques"
I have a class library which is deployed on an ISP server to be consumed by an ASP.NET web service. I'd like to keep track of any errors and in this case the windows event log is inaccessible to me. So I thought I'd write to a txt file using the StreamWriter class. Problem is if I don't give an absolute path and just a file name it tries to write to C:\Windows\System32, and that's no good to me.
How can I tell it to use maybe the data directory or the application root? Any thoughts?
Use Server.MapPath to get a path relative to the web application.
using (FileStream fs = new FileStream(Server.MapPath("~/logs/logfile.txt"),
FileMode.Append)) {
//do logging here.
}
While some of the previous posters have suggested using reflection to get the executing assembly, I'm not sure whether or not that will net you the web application or the w3wp process. If it's the latter, you're still going to end up trying to write to the System32 folder.
Here is what I used to use, it's a little clunky but it gets the job done:
using System;
using System.Collections.Generic;
using System.Web.UI;
public static class Logger
{
private static readonly Page Pge = new Page();
private static readonly string Path = Pge.Server.MapPath("~/yourLogPath/Log.txt");
private const string LineBreaker = "\r\n\r======================================================================================= \r\n\r";
public static void LogError(string myMessage, Exception e)
{
const LogSeverity severity = LogSeverity.Error;
string messageToWrite = string.Format("{0} {1}: {2} \r\n\r {3}\r\n\r {4}{5}", DateTime.Now, severity, myMessage, e.Message, e.StackTrace, LineBreaker);
System.IO.File.AppendAllText(Path, messageToWrite);
}
}
I had this class in it's own project, separate from the website itself, and I used it in all of my other non website projects...
Edit:
Btw LogSeverity is just an enum I made up...
In my web product, in the web.config I specify an appSettings block like this:
<configuration>
<appSettings>
<add key="MyLogPath" value="LogPath" />
</appSettings>
</configuration>
which you can use from the code like
ConfigurationManager.AppSettings["MyLogPath"]
then you can have the installer configure it to wherever you want. you probably don't want the log files in your application directory.
Try checking out:
Application.StartupPath;
Here's a link to the docs
Gets the path for the executable file
that started the application, not
including the executable name.
string path = Application.StartupPath;
Note: you'll still need to add a file name.
You can find out the path of your executable by doing this:
string path = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
In a .NET Win console application, I would like to access an App.config file in a location different from the console application binary. For example, how can C:\bin\Text.exe get its settings from C:\Test.exe.config?
using System.Configuration;
Configuration config =
ConfigurationManager.OpenExeConfiguration("C:\Test.exe");
You can then access the app settings, connection strings, etc from the config instance. This assumes of course that the config file is properly formatted and your app has read access to the directory. Notice the path is not "C:\Test.exe.config" The method looks for a config file associated with the file you specify. If you specify "C:\Test.exe.config" it will look for "C:\Test.exe.config.config" Kinda lame, but understandable, I guess.
Reference here: http://msdn.microsoft.com/en-us/library/system.configuration.configurationmanager.openexeconfiguration.aspx
It appears that you can use the AppDomain.SetData method to achieve this. The documentation states:
You cannot insert or modify system entries with this method.
Regardless, doing so does appear to work. The documentation for the AppDomain.GetData method lists the system entries available, of interest is the "APP_CONFIG_FILE" entry.
If we set the "APP_CONFIG_FILE" before any application settings are used, we can modify where the app.config is loaded from. For example:
public class Program
{
public static void Main()
{
AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", #"C:\Temp\test.config");
//...
}
}
I found this solution documented in this blog and a more complete answer (to a related question) can be found here.
Use the following (remember to include System.Configuration assembly)
ConfigurationManager.OpenExeConfiguration(exePath)
You can set it by creating a new app domain:
AppDomainSetup domainSetup = new AppDomainSetup();
domainSetup.ConfigurationFile = fileLocation;
AppDomain add = AppDomain.CreateDomain("myNewAppDomain", securityInfo, domainSetup);
AppDomainSetup domainSetup = new AppDomainSetup();
domainSetup.ConfigurationFile = #"D:\Mine\Company\";
string browserName = ConfigurationManager.AppSettings["browser"];