c# windows service special folder exception - c#

I have developed a Windows service application. All this service does is initiate filewatcher and listen for a .csv file being created, then it processes that file. Before now we were using the application folder for monitoring, but as security permissions are required to copy the file inside the application root directory we decided to change its path to be the My Documents folder. After the installer completes during the installation process, the ProductName folder is created under the My Documents folder. (The archive folder is also created under ProductName folder.) After the install we have a structure like My Documents\ProductName\Archive\
When we try to start the service, it stops, and the only exception we could see inside event viewer is:
Exception Info: System.ArgumentException
Stack:
at System.IO.FileSystemWatcher.set_Path(System.String)
public partial class ServiceName : ServiceBase
{
private readonly IMachineResultProcessos _controler;
private readonly FileSystemWatcher _watcher;
private readonly string _rootpath = Path.Combine(Environment.GetFolderPath( Environment.SpecialFolder.MyDocuments),"ProductName");
public ServiceName()
{
InitializeComponent();
_controler = new DataProcessos();
_watcher = new FileSystemWatcher
{
Path = _rootpath + #"\Archive",
Filter = "*.csv"
};
_watcher.Created += OnFileCreated;
_watcher.EnableRaisingEvents = true;
}
}
It works under debug, but has problems when deploying on client machine.
Any suggestions or ideas would be welcome.

Related

FileSystemWatcher does not inform about events on Samba share [duplicate]

This question already has answers here:
C# FileSystemWatcher Serious Problem?
(4 answers)
FileSystemWatcher with Samba on Linux
(3 answers)
Closed 2 years ago.
I use the FileSystemWatcher in my C# application and this application runs as a Windows Service on my server. The watchers path is a Samba share from another network.
The application works totally fine when the folder path of the watcher is a folder on the Server, but with the shared folder no events are raised - I need to be informed when a file is created in the folder, then I move it to another one, rename it, read it and so on. (I also tried the watcher.Changed event but nothing is happening there either)
I found a similar question here:
FileSystemWatcher with Samba on Linux
Does anybody know if the FSW has still problems with Samba-shared folders?
I already tried to use a StreamReader and StreamWriter to test if I even have access to the shared folder - this works without any problems. I also thought about resetting the EnableRaisingEvents to true if the FSW "breaks" (like it is mentioned in the question above) but I am a bit confused how to even find out if it broke - because I don't get an error, it just does nothing at all.
This is a part of my watcher class, it runs as a BackgroundService:
protected override Task ExecuteAsync(CancellationToken stoppingToken)
{
Initialize();
TestAccessability();
RunFileWatcher();
return Task.CompletedTask;
}
private void TestAccessability()
{
// Get the directories currently on the shared drive.
DirectoryInfo[] sDirs = new DirectoryInfo(#"\\10.18.249.8\halit4ind$").GetDirectories();
// Write each directory name to a file.
using (StreamWriter sw = new StreamWriter(importPath + "\\SDriveDirs.txt"))
{
foreach (DirectoryInfo dir in sDirs)
{
sw.WriteLine(dir.Name);
}
}
// Read and show each line from the file.
string line = "";
using (StreamReader sr = new StreamReader(importPath + "\\SDriveDirs.txt"))
{
while ((line = sr.ReadLine()) != null)
{
Console.WriteLine(line);
}
}
}
private void RunFileWatcher()
{
logger.LogInformation($"RunFileWatcher watching path {importPath}");
watcher = new FileSystemWatcher
{
Path = #importPath,
Filter = "*.csv"
};
watcher.Created += OnCreated;
watcher.Changed += OnCreated;
watcher.EnableRaisingEvents = true;
}
private void OnCreated(object source, FileSystemEventArgs e)
{
logger.LogInformation($"File {e.FullPath} created/changed - Type: {e.ChangeType}");
if (e.ChangeType == WatcherChangeTypes.Created)
{
var newFilename = TryMoveFileToWork(e.Name);
MoveFileToArchiv(newFilename);
}
}
This is the output I get in the console (I tried creating a file in \10.18.249.8\halit4ind$\Outbox but nothing happens):
pers
Inbox
Outbox
Work
Archiv
[07:19:57 INF] RunFileWatcher watching path \\10.18.249.8\halit4ind$\Outbox
[07:19:57 DBG] Failed to locate the development https certificate at 'null'.
[07:19:57 DBG] Hosting started
[07:19:57 DBG] Loaded hosting startup assembly InfoniqaServiceHali
Hosting environment: Production
Content root path: D:\Services\InfoniqaServiceHali
Now listening on: http://0.0.0.0:7040
Application started. Press Ctrl+C to shut down.
This is the output I get if I use another path:
pers
Inbox
Outbox
Work
Archiv
[08:49:35 INF] RunFileWatcher watching path D:\temp\Outbox
[08:49:35 DBG] Failed to locate the development https certificate at 'null'.
[08:49:35 DBG] Hosting started
[08:49:35 DBG] Loaded hosting startup assembly InfoniqaServiceHali
Hosting environment: Production
Content root path: D:\Services\InfoniqaServiceHali
Now listening on: http://0.0.0.0:7040
Application started. Press Ctrl+C to shut down.
[08:49:44 INF] File D:\temp\Outbox\Personal.csv created/changed - Type: Created
[08:49:44 INF] TryMoveFileToWork Personal.csv

How to return the directory of the running .NET Core 2.2 app hosted on an Azure Windows Server VM?

So I have a .NET Core 2.2 app running on an Azure VM with Windows Server 2019 which has the following disk configuration:
The disk on the red box is where the App files are located. Now, when Directory.GetCurrentDirectory() is called by the app, it returns the root directory of the project and not the current directory where the app is running. When I tried to run it locally, it works.
To illustrate it:
When run locally, the directory ~/MyApp/bin/Debug/netcoreapp2.2/ is returned by the call. When run in the VM, ~/MyApp/ is returned instead.
Here's the relevant code where the issue happens. What I do here is when the app is closed, it copies the current configuration file from ~/MyApp/bin/Debug/netcoreapp2.2/ to the ~/MyApp/ directory. This code works when run on a local machine, but it is not when running on the VM. How to make sure that calling Directory.GetCurrentDirectory() does indeed point to the directory of the running app?
private void ProcessExit(object sender, EventArgs e)
{
try
{
string rawConfigLocation = _config.GetSection("configurationSettings")["ConfigurationDirectory"];
File.Delete($"{Path.Combine(rawConfigLocation, "Config.json.inc")}");
using (var writer = File.CreateText($"{Path.Combine(Directory.GetCurrentDirectory(), "Config.json.inc")}"))
{
using (var reader = new StreamReader(Path.Combine(Directory.GetCurrentDirectory(), "Config.json")))
{
while (!reader.EndOfStream) writer.WriteLine(reader.ReadLine());
writer.Close();
}
Console.WriteLine(rawConfigLocation);
File.Move($"{Path.Combine(Directory.GetCurrentDirectory(), "Config.json.inc")}", $"{Path.Combine(rawConfigLocation, "Config.json.inc")}");
File.Delete($"{Path.Combine(rawConfigLocation, "Config.json")}");
File.Move($"{Path.Combine(rawConfigLocation, "Config.json.inc")}", $"{Path.Combine(rawConfigLocation, "Config.json")}");
Debug.WriteLine($"New file saved as {Path.Combine(rawConfigLocation, "Config.json")}");
#region [WINDOWS ONLY] Lines for debugging. Will be removed if the issue of incorrect config saving is fixed.
using (EventLog eventLog = new EventLog("MyApp"))
{
eventLog.Source = "MyApp";
eventLog.WriteEntry(
$"Raw Config Location: {_config.GetSection("configurationSettings")["ConfigurationDirectory"]}{Environment.NewLine}" +
$"File that was deleted: {Path.Combine(rawConfigLocation, "Config.json.inc")}{Environment.NewLine}" +
$"Temporary file created: {Path.Combine(Directory.GetCurrentDirectory(), "Config.json.inc")}{Environment.NewLine}" +
$"Current Directory: {Directory.GetCurrentDirectory()}{Environment.NewLine}" +
$"New file saved as {Path.Combine(rawConfigLocation, "Config.json")}",
EventLogEntryType.Information,
101,
1);
}
#endregion
}
}

Overwrite restricted application file?

I'm trying to manually patch my application. The application makes use of a Service which i make sure to stop and uninstall prior to attempting any overwriting of the application dll's.
The issue is that i can't overwrite, or even delete some of the dll files which are the core of the application, these dll files are used by the service i uninstalled first.
I use the following method to pass in the new file-path in order to replace the old DLL which is located inside the root directory of the application in C:\Program Files\AppName\
public static bool CopyFile(string newFile, string oldFile)
{
var newfile = new FileInfo(newFile);
var oldfile = new FileInfo(oldFile);
var f2 = new FileIOPermission(FileIOPermissionAccess.AllAccess, oldFile);
f2.AddPathList(FileIOPermissionAccess.Write | FileIOPermissionAccess.Read, newFile);
try
{
f2.Demand();
}
catch (SecurityException s)
{
Console.WriteLine(s.Message);
}
for (int x = 0; x < 100; x++)
{
try
{
File.Delete(oldfile.FullName);
newfile.CopyTo(oldfile.FullName, true);
return true;
}
catch
{
Thread.Sleep(200);
}
}
return false;
}
I just wish to provide a new file and remove the old one, replace it, overwrite it.... The application
Note: The application i run to do the patching runs as administrator.
Any idea?
I was able to fix this issue by making use of a "middle man" in other words, another application which downloads another executable and passes command line arguments to it.
Originally, my service would download an executable (call it Installer.exe). Installer.exe would then attempt to stop the service and patch the content, this did not work.
I now have the service running, it downloads "Installer.exe".
Installer.exe will load up and download PatchPayload.exe.
PatchPayload.exe runs and kills off the Service, uninstalls it and then download all required patch content from a centralized server and patch the service core files individually then install the service and run it again.

Install SQL Server CE database in separate folder [Windows Mobile 6 Smart device ap]

Install SQL Server CE database in a separate folder, and application in other folder as usual. While uninstalling application from device, database won't delete. When reinstalling application on the same device, check if database exist in it [where we saved on first install], if not exist save in common folder for all smart devices [like \Program Files\], else use existing DB .
How can I do this using C#, Windows Mobile 6?????
After reading your comment, I'd suggest something similar to the following:
When your application starts, have it check for the existence of your database at the path you require (or at a path specified in an INI file)
If the database is not found, ask the user if the default database should be used (or, just copy it over if they should have no choice).
When the application is removed, this database will remain.
When your application is reinstalled, it can use the database that was left.
Example:
namespace DBTest1 {
public partial class Form1 : Form {
const readonly string MYDATABASE = "\\Application Data\\DBTest1\\sqlce.db";
private void Form1() {
InitializeComponent();
CreateIfNotThere(DBTest1.Properties.Resources.sqlcedb, MYDATABASE);
}
void CreateIfNotThere(object data, string filename) {
if (String.IsNullOrEmpty(filename)) {
filename = string.Format(#"{0}{1}{2}",
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
Path.DirectorySeparatorChar, "sqlCe.db");
}
if (data != null) {
byte[] array = (byte[])data;
FileInfo file = new FileInfo(filename);
if (!file.Exists) {
using (FileStream fs = file.Create()) {
fs.Write(array, 0, array.Length);
}
}
}
}
// other code
}
If you want to get into writing custom CABWIZ steps, there is a nice write up in the How to create the inf file for a smart device cab project from command line? thread.

Create a ReadOnly log file with Log4Net

I'm developing application in c# that creates 2 log files (.txt files): one for errors and another for modifications made by users. This two files are created with log4net. The issue I see is that this files can be edited, and so altered by mistake.
I would like to set this files to readonly, and that log4net still could write on them. Because if I just change the property in the file, the next log wont be written.
There is a way to do that?
Also, the user of the app can open this logs file from within the app. For that I use the next code:
System.IO.FileInfo finfo = new System.IO.FileInfo("path");
if (finfo.Exists)
{
//finfo.Attributes = System.IO.FileAttributes.ReadOnly;
// I don't use the previous line at the moment, because it blocks the followings logs.
System.Diagnostics.Process.Start("path");
}
And this is the code to create and call the logger:
public static class CLogger
{
private static readonly ILog logger = LogManager.GetLogger(typeof(CLogger));
static CLogger()
{
XmlConfigurator.Configure(new System.IO.FileInfo("path to .config file"));
}
public static void WriteLog(ELogLevel logLevel, String log)
{
if (logLevel.Equals(ELogLevel.DEBUG))
{
logger.Debug(log);
}
else if (logLevel.Equals(ELogLevel.ERROR))
.
.
.
else if (logLevel.Equals(ELogLevel.WARN))
{
logger.Warn(log);
}
}
}
Calling to the logger:
CLogger.WriteLog(ELogLevel.ERROR, ex.ToString());
Basically, if the application runs under the rights of the user, than the user ultimately must have the rights to access the files: if he doesn't, the application wouldn't be able to write into this files either.
I would change the rights on the folder where the logs are being written. The web server granted Read/Write, all other only Read.

Categories

Resources