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

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

Related

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

Uploads within NancyFX hang on upload

nuget package Microsoft.Azure.Storage.File 9.4.2 uploads files somewhere < 26MB just fine, and silently hangs indefinitely when uploading files > 26MB.
Project is targeting .NET (Desktop) Framework 4.7.2.
***** Update *****
This problem occurs when attempting a large-ish file upload, using various clients, and to various cloud services (I've experienced the same problem uploading to S3), but only within the context of a NancyFx web application. Same problem occurs locally as when deployed to an Azure App Service, so it is almost certainly unrelated to my local dev configuration.
To be clear, the uploads hang when attempting an upload within a NancyFx application; I am not uploading to a NancyFx application.
For now, my solution is to just don't do the file upload from within Nancy, but I'll leave this question open in case anyone has an interest in a technical solution to the problem that still exists.
***** End Update *****
And to be clear, file uploads
Attempted usage is as follows:
public void UploadFileFromFile(string azureFileName, string localFileName)
{
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(SafeConfig.AzureFileStorageMaterialConnectionString);
CloudFileClient client = storageAccount.CreateCloudFileClient();
CloudFileShare share = client.GetShareReference(SafeConfig.AzureFileStorageMaterialShareName);
CloudFileDirectory dir = share.GetRootDirectoryReference();
CloudFile fileReference = dir.GetFileReference(azureFileName);
fileReference.UploadFromFile(localFileName);
}
Worth noting, the client hangs just the same when I use the fileReference.UploadFromByteArray() method, and also hangs the same when I try using the various *Async alternatives as well.
When I try use the method fileReference.UploadFromStream(), I get an exception "Object is not in a usable state," which I do not consider to be a particularly actionable exception message. This is my preferred method to use for uploading, but the different error experience might make it a separate question.
I'm using the same package and same code as yours, everything is fine and file size more than 26M can be uploaded. Can you try to restart your visual studio and try again?
My code:
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.File;
using System;
namespace MyConsole
{
class Program
{
static void Main(string[] args)
{
Program p = new Program();
string azureFileName = "1.zip";
string localFileName = #"D:\1.zip";
Console.WriteLine("start upload..");
p.UploadFileFromFile(azureFileName, localFileName);
Console.WriteLine("completed**");
Console.ReadLine();
}
public void UploadFileFromFile(string azureFileName, string localFileName)
{
CloudStorageAccount storageAccount = CloudStorageAccount.Parse("xxxx");
CloudFileClient client = storageAccount.CreateCloudFileClient();
CloudFileShare share = client.GetShareReference("testfolder");
CloudFileDirectory dir = share.GetRootDirectoryReference();
CloudFile fileReference = dir.GetFileReference(azureFileName);
Console.WriteLine("going to upload");
fileReference.UploadFromFile(localFileName);
}
}
}
The file can be uploaded:

Launching C# program from another C# program

Due to me having knowledge of launching apps I am aware that you have multiple ways of launching an application in C# .NET, but I'm running into a issue that occurs when attempting to launch a SDL2 application.
I have attempted the following using the Process class to:
Start the .exe file of the build.
Start the application using "cmd.exe /K" or "cmd.exe /c" followed by "exec" or "call" or "start" followed by "{path to file}" or "{path to batch file to launch the application}". Launching the application via a batch file and CMD works fine. But, whenever I attempt to even launch the application (even in a new instance of Command-Prompt launched from cmd.exe /? start cmd.exe ?params) it will yield no result.
What I can observe is that the application tries to open. It takes forever to launch into the Window mode (starting the 3D environment). After a timeout it will either, render a couple of frames of a blank window before closing or close immediately after opening the window.
So my question is, does anyone have succesfully made a launcher application for a SDL app written in C# .NET? Or knows a way to debug this behaviour? Because unfortunately, the app does not send out a error message and since SDL safely closes the application I can't observe a crash either.
Edit #1
I'm not doing anything fancy with parameters as there shouldn't be any. I already have another one functioning that launches a normal C# application as my launcher requires to open 2 programs. 1 SLD application, 1 COM:VBA controlling application.
Given:
string audioSpectrumProgram = "AudioSpectrum.exe";
string audioSpectrumBatchProgram = "AudioSpectrum.bat";
private void BtnLaunchPPTApp_OnClick()
{
//Powerpoint controlling application
pVBAApp = Process.Start(presenterProgram, $"\"{this.path}\" {this.audioFormatParams[0]} {((this.ckboxGenerate.Checked) ? "--create" : "")} lang={this.languageCodesParams[this.cboxLanguage.SelectedIndex]}");
}
Method 1:
private void BtnLaunchSDLApp_OnClick()
{
pVizualizer = Process.Start(audioSpectrumProgram); //file launched from local path (is correct)
}
Method 2:
pVizualizer = Process.Start(audioSpectrumBatchProgram); //file launched from local path (is correct)
Method 3:
ProcessStartInfo info = new ProcessStartInfo("cmd.exe");
FileInfo spectrumFileInfo = new FileInfo(audioSpectrumProgram);
if (spectrumFileInfo.Exists)
info.Arguments = $"/c \"{spectrumFileInfo.FullName}\"";
pVizualizer = Process.Start(info);
Method 4:
based on senario of method 3. You don't have to parse arguments using ProcessStartInfo.
pVizualizer = Process.Start($"cmd.exe /K call \"{spectrumFileInfo.FullName}\"") //to observe what happens to the application
Edit #2
Not affected by changing the UseShellExecute to true or false
private void btnOpenVisualizer_Click(object sender, EventArgs e)
{
FileInfo spectrumFileInfo = new FileInfo(audioSpectrumProgram);
ProcessStartInfo info = new ProcessStartInfo(spectrumFileInfo.FullName);
info.UseShellExecute = true;
pVizualizer = new Process();
pVizualizer.StartInfo = info;
pVizualizer.EnableRaisingEvents = true;
pVizualizer.Exited += new EventHandler(myProcess_Exited);
pVizualizer.Start();
}
private void myProcess_Exited(object sender, System.EventArgs e)
{
Console.WriteLine(
$"Exit time : {pVizualizer.ExitTime}\n" +
$"Exit code : {pVizualizer.ExitCode}\n"
);
}
A general way of analyzing startup issues is to use SysInternals Process Monitor.
Record the application that is not starting up properly. Use a filter for your application. Then go through all items which don't have SUCCESS in the result column. Typically you want to do that bottom-up, since the last error is the one stopping your application from loading.
Like this you'll find common startup issues like:
missing DLLs or other dependencies
old DLLs or DLLs loaded from wrong location (e.g. registered COM components)
wrong working directory, e.g. access to non-existent config files
Ok For Future reference:
Pathing to the files can be correct and everything might be in order but if you are using DLLs for imports. Change the process's working directory.
The project will run, libs can "sometimes" be found but can cause a weird unknown bug like this one. So the most optimal way of running another C# instance with SDL or any other kind of library:
private void RunSDLProgram()
{
FileInfo spectrumFileInfo = new FileInfo("pathToFile.exe");
ProcessStartInfo info = new ProcessStartInfo(spectrumFileInfo.FullName);
info.RedirectStandardOutput = true;
info.RedirectStandardError = true;
info.UseShellExecute = false;
info.WorkingDirectory = spectrumFileInfo.DirectoryName;
pVizualizer = new Process();
pVizualizer.StartInfo = info;
pVizualizer.EnableRaisingEvents = true;
pVizualizer.Exited += new EventHandler(myProcess_Exited);
pVizualizer.Start();
}
private void myProcess_Exited(object sender, System.EventArgs e)
{
Console.WriteLine(
$"Exit time : {pVizualizer.ExitTime}\n" +
$"Exit code : {pVizualizer.ExitCode}\n" +
$"output : {pVizualizer.StandardOutput}\n" +
$"err : {pVizualizer.StandardError}\n"
);
}
Running a batch file will look at it's own directory and makes all references local, but it won't alter the working directory. (already had my suspicions about changing the work directory but I didn't see a way to call 2 opperations in process.start("cmd.exe");)

Windows Service "Timeout" instantly on startup

I'm currently running in to an issue where a Windows Service I wrote is "timing out" instantly on start up. The message I get is Error 1053: The service did not respond to the start or control request in a timely fashion. I checked Event Viewer and I see that message and another A timeout was reached (30000 milliseconds) while waiting for the X service to connect. Only problem is that it's not waiting 30 seconds to time out, it's more like half a second.
My service's OnStart()
private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private string version = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion;
private string incomingProdFileLocation = ConfigurationManager.AppSettings["ProdIncomingFileLocation"];
private string incomingCertFileLocation = ConfigurationManager.AppSettings["CertIncomingFileLocation"];
//private string incomingCombFileLocation = ConfigurationManager.AppSettings["CombIncomingFileLocation"];
private string processedFileLocation = ConfigurationManager.AppSettings["ProcessedFileLocation"];
private string errorFileLocation = ConfigurationManager.AppSettings["ErrorFileLocation"];
FileSystemWatcher prodWatcher = new FileSystemWatcher();
FileSystemWatcher certWatcher = new FileSystemWatcher();
//FileSystemWatcher combWatcher = new FileSystemWatcher();
protected override void OnStart(string[] args) {
log.InfoFormat("Starting up Merchant Bulk Load Service v{0}", version);
if (verifyDirectories()) {
log.InfoFormat("Initialize Prod FileSystemWatcher() at {0}", incomingProdFileLocation);
prodWatcher.Path = incomingProdFileLocation;
prodWatcher.Filter = "*.csv";
prodWatcher.Created += ProdBulkLoadFileReceived;
prodWatcher.EnableRaisingEvents = true;
log.InfoFormat("Initialize Cert FileSystemWatcher() at {0}", incomingCertFileLocation);
certWatcher.Path = incomingCertFileLocation;
certWatcher.Filter = "*.csv";
certWatcher.Created += CertBulkLoadFileReceived;
certWatcher.EnableRaisingEvents = true;
/*log.InfoFormat("Initialize Comb FileSystemWatcher() at {0}", incomingCombFileLocation);
combWatcher.Path = incomingCombFileLocation;
combWatcher.Filter = "*.csv";
combWatcher.Created += CombBulkLoadFileReceived;
combWatcher.EnableRaisingEvents = true;*/
} else {
log.ErrorFormat("verifyDirectories() returned false. Service stopping");
this.Stop();
}
}
private bool verifyDirectories() {
// verify each of the necessary directories exists before setting up any FileSystemWatcher()s
if (!Directory.Exists(incomingProdFileLocation)) {
log.ErrorFormat("Incoming production file location {0} does not exist. Please create the directory or edit the configuration file.",
incomingProdFileLocation);
return false;
}
if (!Directory.Exists(incomingCertFileLocation)) {
log.ErrorFormat("Incoming cert file location {0} does not exist. Please create the directory or edit the configuration file.",
incomingCertFileLocation);
return false;
}
/*if (!Directory.Exists(incomingCombFileLocation)) {
log.ErrorFormat("Incoming combined file location {0} does not exist. Please create the directory or edit the configuration file.",
incomingCombFileLocation);
return false;
}*/
if (!Directory.Exists(processedFileLocation)) {
log.ErrorFormat("Processed file location {0} does not exist. Please create the directory or edit the configuration file.",
processedFileLocation);
return false;
}
if (!Directory.Exists(errorFileLocation)) {
log.ErrorFormat("Error file location {0} does not exist. Please create the directory or edit the configuration file.",
errorFileLocation);
return false;
}
return true;
}
My entire service works splendidly in our development and certification environments, but won't start in our production environment, it doesn't seem like it's even getting to the OnStart() because a log is never made. Things I've checked:
Made sure service had correct permissions in the necessary directories, it does
Made sure the correct version of .NET framework that my service is targeting (4) is installed, it is
Made sure Event Viewer wasn't throwing any other types of errors that might give me a hint to what's happening, there's nothing
All of the directories for the FileSystemWatcher actually exist, they do
The directory for the log4net file exists, it does
I'm at a loss at the moment; any help would be awesome.
edit
After double checking the .NET framework again I realize I checked the wrong server for the versions. A good way to be certain is to double-click on the actual exe file for the service and see what it says. In my case it literally said "Make sure 4.0 is installed" which prompted me to check again and there I saw that 4.0 wasn't installed.
Are you sure that your .net is up to date. This could happen if for instance 3.5 is on the machine and you're using 4.0.
This is an old ticket, but I just saw the same error (albeit with "90000 milliseconds" rather than 30000) on all of the Windows services we've created as part of our application (about 10 of them). .Net framework was installed and functional.
I examined the registry setting where this 90000 ms (90 second) limit was set.
In the node, HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control
The value of ServicesPipeTimeout was 90000 (Decimal).
I didn't need it to be 90000 and I don't know why it was set thus, but it certainly wasn't waiting 90 seconds -- it was failing instantly.
So I modified the value to 30000 and rebooted the server.
All services begin starting or restarting successfully.

c# windows service special folder exception

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.

Categories

Resources