Windows Service ElapsedEvent doesn't run after elapsed time - c#

I have created an application running as a Windows Service in C#. It uses WinSCP to retrieve files from an FTP and do some work on them. It will run successfully many times but then just never start a new event after the time has elapsed. The amount of successful runs between a failure is seemingly random. I have to kill the process through Task Manager as it is unresponsive to stopping it via the Services GUI in Windows.
The OnStart method below will always run and log successfully without issue. The issue is that after the elapsed time (600000 ms or 10 minutes), the event will never fire again and the service becomes unresponsive.
protected override void OnStart(string[] args)
{
try
{
//Set up logging and timer parameters
Logging.ConfigureTraceListeners();
Logging.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " ------------LOG ON START------------");
System.Timers.Timer timer = new System.Timers.Timer();
Logging.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " New Timer");
timer.Interval = Convert.ToDouble(ConfigurationManager.AppSettings["PollingTime"]);
Logging.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " Interval Set");
timer.Elapsed += new System.Timers.ElapsedEventHandler(ProcessDocuments);
Logging.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " Timer complete");
timer.Start();
}
catch (Exception e)
{
Logging.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " Failed OnStart");
Logging.WriteLine(e.ToString());
throw;
}
}
Here is a selection of the ProcessDocuments method.
public void ProcessDocuments(object sender, System.Timers.ElapsedEventArgs args)
{
Logging.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " ------------STARTING PROCESSINGDOCUMENTS METHOD------------");
bool testmode = Convert.ToBoolean(ConfigurationManager.AppSettings["TestMode"]);
bool gotfiles = false;
try
{
//Configure FTP session options
Logging.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " ------------BEGIN FTP RETRIEVAL------------");
SessionOptions sessionOptions = new SessionOptions
{
Protocol = Protocol.Sftp,
HostName = ConfigurationManager.AppSettings["HostName"],
UserName = ConfigurationManager.AppSettings["UserName"],
Password = ConfigurationManager.AppSettings["Password"],
SshHostKeyFingerprint = ConfigurationManager.AppSettings["SshHostKeyFingerprint"]
};
}
catch (Exception e)
{
Logging.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " Error:" + e.ToString());
}
Logging.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " ------------ALL PROCESSING COMPLETE------------");
counter++;
Logging.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " Counter:" + counter);
}
Here is generally what the logs look like.
2023-01-01 22:16:16 ------------LOG ON START------------
2023-01-01 22:16:16 New Timer
2023-01-01 22:16:16 Interval Set
2023-01-01 22:16:16 Timer complete
2023-01-04 18:44:03 ------------STARTING PROCESSINGDOCUMENTS METHOD------------
2023-01-04 18:44:03 ------------BEGIN FTP RETRIEVAL------------
2023-01-04 18:44:03 Set Session Options
2023-01-04 18:44:05 In production mode
2023-01-04 18:44:05 Remote Path is: [file path]
2023-01-04 18:44:05 Local Path is: [file path]
2023-01-04 18:44:06 ------------NO FILES FOUND------------
2023-01-04 18:44:06 ------------ALL PROCESSING COMPLETE------------
2023-01-04 18:44:06 Counter:1
I added a counter to see if there was a pattern in the failures. When it fails, it logs that counter at the end and then never starts the ProcessDocuments method again. Here is what multiple successful runs looks like in the logs.
2022-11-09 22:08:16 ------------STARTING PROCESSINGDOCUMENTS METHOD------------
2022-11-09 22:08:16 ------------BEGIN FTP RETRIEVAL------------
2022-11-09 22:08:16 Set Session Options
2022-11-09 22:08:18 In production mode
2022-11-09 22:08:18 Remote Path is: [file path]
2022-11-09 22:08:18 Local Path is: [file path]
2022-11-09 22:08:18 ------------NO FILES FOUND------------
2022-11-09 22:08:19 ------------ALL PROCESSING COMPLETE------------
2022-11-09 22:08:19 Counter:321
2022-11-09 22:18:16 ------------STARTING PROCESSINGDOCUMENTS METHOD------------
2022-11-09 22:18:16 ------------BEGIN FTP RETRIEVAL------------
2022-11-09 22:18:16 Set Session Options
2022-11-09 22:18:18 In production mode
2022-11-09 22:18:18 Remote Path is: [file path]
2022-11-09 22:18:18 Local Path is: [file path]
2022-11-09 22:18:18 ------------NO FILES FOUND------------
2022-11-09 22:18:19 ------------ALL PROCESSING COMPLETE------------
2022-11-09 22:18:19 Counter:322
I have it run for thousands of instances or stop after 1. I haven't been able to find anything in my logs or via the Event Viewer linked to the failures.

Related

C# .net core application doesn't create log file when executed thru Powershell, but creates log file when executed thru Command Line or Visual Studio

I have a .net core 5.0 console app with log4net 2.0.12.Upon execution, from visual studio or from command line after publish, log file generated successfully. When the same published app is executed thru PowerShell, app executes as expected but log file does not get generated.
> $CLI_HOME= "C:\PowerShellDemoDeployment\PowerShellDemo\"
$CLI = "PowerShellDemo.exe"
$COMMAND = $CLI_HOME + $CLI
"Command being executed: " + $COMMAND
Invoke-Expression $COMMAND
namespace PowerShellDemo
{
class Program
{
static ILog logforLoader = LogManager.GetLogger(typeof(Program));
static void Main(string[] args)
{
var logRepository = LogManager.GetRepository(Assembly.GetEntryAssembly());
XmlConfigurator.Configure(logRepository, new FileInfo("log4net.config"));
logforLoader.Info("Process started at :" + DateTime.Now.ToString());
Console.WriteLine("Started...Going to Sleep for some time");
Thread.Sleep(1000);
Console.WriteLine("Woke up ...finishing... ");
logforLoader.Info("Process Completed at :" + DateTime.Now.ToString());
}
}
}

How to access IIS through C# Console Application

I am trying to access my server's IIS pool in order to recycle it through C# code.
This is my code:
static void Main(string[] args)
{
try
{
string sMachine = "MyHostName";
string sAppPool = "MyAppPoolName";
string sPath = "IIS://" + sMachine + "/W3SVC/AppPools/" + sAppPool;
Console.WriteLine(sPath);
DirectoryEntry w3svc = new DirectoryEntry(sPath, "MyUserName", "MyPassword");
w3svc.Invoke("Recycle", null);
Console.WriteLine("Application pool recycled");
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
}
}
I changed the sMachine / sAppPool / UserName, Password, but in my code I send them with the real data.
When I run it on my VM I get a message
Error: Unknown Exception
I think it occurs because the permission so I run it with the administrator of the VM and run as administrator the exe file, but still I get the same error.
How could I access the IIS?
Thanks in advance.

C# batch file execution never exits

I am trying to execute a batch file which runs on its own. I am now trying to automate this by deploying it as a windows service which listens for a folder and invokes the batch file using file watcher event. Here is the code -
void fileSystemWatcher_Created(object sender, FileSystemEventArgs e)
{
ServiceEventLog.WriteEntry(TheServiceName + " Inside fileSystemWatcher_Created() - ");
if (e.Name.Trim().ToUpper().Contains("FU4DGF_TRADES"))
{
try
{
Utilities.SendEmail("IAMLDNSMTP", 25, "desmond.quilty#investecmail.com", "IAMITDevelopmentServices#investecmail.com", "Ben.Howard#investecmail.com", "prasad.matkar#investecmail.com", "StatPro BatchFile Execution Started ", "");
int exitCode;
// ProcessStartInfo processInfo;
ServiceEventLog.WriteEntry(TheServiceName + " Before creation of instance of Batch process - ");
Process process = new Process();
process.StartInfo.FileName = #"C:\Program Files (x86)\StatPro Suite\MonthlyUpload.bat";
process.StartInfo.RedirectStandardOutput = false;
process.StartInfo.RedirectStandardError = false;
process.StartInfo.CreateNoWindow = false;
process.StartInfo.WorkingDirectory = #"C:\Program Files (x86)\StatPro Suite";
process.StartInfo.UseShellExecute = false;
ServiceEventLog.WriteEntry(TheServiceName + " Before start of Batch process - ");
process.Start();
ServiceEventLog.WriteEntry(TheServiceName + " After start of Batch process - ");
process.WaitForExit();
//while (!process.HasExited)
//{
// System.Threading.Thread.Sleep(100);
//}
ServiceEventLog.WriteEntry(TheServiceName + " After process.close - ");
System.Environment.ExitCode = process.ExitCode;
}
I can see from my event log that it goes as far as logging - Before start of Batch process. Presumably after that the process starts by invoking process.Start() but then nothing happens. Nothing in the event log, the service is still running i.e. not crashed. No errors. I can see from task manager that it does invoke the exe that it is supposed to invoke via the batch file but the exe simply remains in memory with constant memory and 0 CPU usage suggesting the exe is not doing anything. If I run the batch file manually it works fine. Any idea what could be going wrong?
You disabled UseShellExecute. This means that you can't use the shell to execute the file. bat files are not executables, they are shell scripts.
Since you're not redirecting standard I/O anyway, just enable UseShellExecute and you should be fine.

Can't dial with DotRas in Windows Server 2012 R2

i'm totally new to DotRas so please be patient.. I have a windows server 2012 R2 with "Route and remote access" configured. In this simple configuration there is a dialer connection to a vpn as you can see in the first picture..
So, if i click connect.. everything works fine and the status of the network interface changes from disconnected to connected.
Going to the event viewer this is what i got:
Events from RASCLIENT sourcelog:
Event 1:
CoId={A52088DC-5358-44D6-8B77-DA49516C3FBD}: The user SYSTEM has started dialing a VPN connection using a all-user connection profile named VpnAtlanta02. The connection settings are:
Dial-in User = c******s
VpnStrategy = PPTP
DataEncryption = Require
PrerequisiteEntry =
AutoLogon = No
UseRasCredentials = Yes
Authentication Type = MS-CHAPv2
Ipv4DefaultGateway = No
Ipv4AddressAssignment = By Server
Ipv4DNSServerAssignment = By Server
Ipv6DefaultGateway = Yes
Ipv6AddressAssignment = By Server
Ipv6DNSServerAssignment = By Server
IpDnsFlags =
IpNBTEnabled = No
UseFlags = Private Connection
ConnectOnWinlogon = No.
Event 2:
CoId={A52088DC-5358-44D6-8B77-DA49516C3FBD}: The user SYSTEM is trying to establish a link to the Remote Access Server for the connection named VpnAtlanta02 using the following device:
Server address/Phone Number = ***.***.***.***
Device = WAN Miniport (PPTP)
Port = VPN3-4
MediaType = VPN.
Event 3:
CoId={A52088DC-5358-44D6-8B77-DA49516C3FBD}: The user SYSTEM has successfully established a link to the Remote Access Server using the following device:
Server address/Phone Number = ***.***.***.***
Device = WAN Miniport (PPTP)
Port = VPN3-4
MediaType = VPN.
Event 4:
CoId={A52088DC-5358-44D6-8B77-DA49516C3FBD}: The link to the Remote Access Server has been established by user SYSTEM.
Event 5:
CoId={A52088DC-5358-44D6-8B77-DA49516C3FBD}: The user SYSTEM has dialed a connection named VpnAtlanta02 to the Remote Access Server which has successfully connected. The connection parameters are:
TunnelIpAddress = 172.20.0.19
TunnelIpv6Address = None
Dial-in User = c******s.
Now.. my goal is to get connected from a windows service
So here is my code (the essential part):
Dialer = new RasDialer();
Dialer.PhoneBookPath = "C:\\Windows\\System32\\ras\\Router.pbk";
Dialer.Timeout = 20 * 1000;
Dialer.HangUpPollingInterval = 20 * 1000;
Dialer.AllowUseStoredCredentials = false;
Dialer.AutoUpdateCredentials = RasUpdateCredential.None;
Dialer.EntryName = "VpnAtlanta02";
Dialer.Credentials = new System.Net.NetworkCredential("c******s", "*********");
Watcher = new RasConnectionWatcher();
Watcher.EnableRaisingEvents = true;
Watcher.Connected += Watcher_Connected;
Watcher.Disconnected += Watcher_Disconnected;
InfoLog("Begin connection");
Watcher.Handle = Dialer.Dial();
private void Watcher_Disconnected(object sender, RasConnectionEventArgs e)
{
InfoLog(e.Connection.EntryName + " is disconnected");
}
private void Watcher_Connected(object sender, RasConnectionEventArgs e)
{
InfoLog(e.Connection.EntryName + " is connected");
}
Sofar, no matter what... going to the event viewer looking for the RasClient event source, as expected i got 5 events logged. 1,2,3 and 4 are equal to the ones generated by the manual connection unfortunately the last (5) is:
CoId={E2814072-13C7-44CF-998A-A1160FDC86E3}: The user SYSTEM dialed a connection named VpnAtlanta02 which has failed. The error code returned on failure is 720.
Please consider that if you think at some wrong credentials or else.. i did a try with no credentials at all and as expected in that case i wasn't able to get event 4
Any ideas?
First thing first! This is not the answer to my question but... I think it could be helpful for anyone who's experienced the same trouble.
After a bunch of tries and even some attempts to debug using DotRas source code i didn't get any step forward, besides i'm not sure this can actually be done. I said that because trying with "rasdial" command from an administrator command prompt i've got the same result: failed with error code 720. That said i've got my solution using powershell.
There's 3 powerful cmdlets which are all i was looking for
- Get-VpnS2SInterface
- Connect-VpnS2SInterface
- Disconnect-VpnS2SInterface
So i just set 3 simple methods and now everything works like a charm
public Boolean IsConnected()
{
Boolean retVal = false;
using (PowerShell ps = PowerShell.Create())
{
ps.AddCommand("Get-VpnS2SInterface");
ps.AddParameter("Name", "VpnAtlanta02");
foreach (PSObject result in ps.Invoke())
{
retVal = ("" + result.Members["ConnectionState"].Value).ToLower() == "connected";
}
}
return retVal;
}
public void Connect()
{
using (PowerShell ps = PowerShell.Create())
{
ps.AddCommand("Connect-VpnS2SInterface");
ps.AddParameter("Name", "VpnAtlanta02");
ps.AddParameter("PassThru");
foreach (PSObject result in ps.Invoke())
{
String destination = "";
foreach (String s in result.Members["Destination"].Value as String[])
{
destination += "{" + s + "}";
}
Service1.InfoLog("Destination=" + destination + "\r\n" +
"ConnectionState=" + result.Members["ConnectionState"].Value + "\r\n");
}
}
}
public void Disconnect()
{
using (PowerShell ps = PowerShell.Create())
{
ps.AddCommand("Disconnect-VpnS2SInterface");
ps.AddParameter("Name", "VpnAtlanta02");
ps.AddParameter("Force");
ps.Invoke();
Service1.InfoLog("Nic: " + "VpnAtlanta02" + " is connected: " + IsConnected());
}
}

portforwarding in c# (matter with NATUPNPlib)

hi guys i use code below to forward port 9090 to my laptop
NATUPNPLib.UPnPNAT upnpnat = new NATUPNPLib.UPnPNAT();
NATUPNPLib.IStaticPortMappingCollection mappings = upnpnat.StaticPortMappingCollection;
mappings.Add(9090, "TCP", 9090, "192.168.1.104", true, "ProApp-SHARE");
and this code for firewall permission
string command = "netsh http add urlacl url=http://" + "192.168.1.104" + ":" + "9090" + "/ user=everyone";
StreamWriter ns = new StreamWriter(Application.StartupPath + #"\fw.bat", false);
ns.WriteLine(command);
ns.Close();
Process n = new Process();
n.StartInfo.FileName = Application.StartupPath + #"\fw.bat";
if (System.Environment.OSVersion.Version.Major >= 6)
{
n.StartInfo.Verb = "runas";
}
n.Start();
when i do this i can access my local website that runs on 192.168.1.104:9090 from internet , but after 30 seconds up to 1 minute its just disabled , and i have to run these codes again, can some one help me with this???
UPnP is notoriously badly implemented in most routers. You might want to try using a different UPnP library to perform the port map. Check out Open.NAT.

Categories