windows service strange behavior - c#

I implemented windows service with eventLog and FileSystemWatcher that looks for changes in specific directory and writes messages into MyLog.
strange thing 1:
I install it via installUtil.exe (since the VS2012 doesn't have installer templates) and in some situations when I go to "Services" and start the service I get:
The [service name] service on local computer started and then stopped. Some Services stop automatically if they are not in use by another services or programs.
I've already seen this question. 2 answeres from this post why it can be so:
1) There is no thread starting in OnStart() method.
I use the designer and set most of the properties in the Properties window and I never started any thread manually, but in some cases everything was working, so I think this is not the case.
2) An exception occures in OnStart() method. I think it's not the case cause I don't change the code. I just uninstall, build and install again the same service and in some cases it runs, in some not.
When I was stuck for mabby 2 hours with this thing I noticed that the Source property of eventLog is too long: "FilesMonitoringServices". I changed it to "MonitorSource" and everything started to work. Than I reinstalled it cauple of times and got the same warning as the above. I changed the Source property again and now the service runs.
This is the first strange thing.
strange thing 2: worse. Even if it runs it logs only OnStart() and OnStop() methods, I mean the fileSystemWatcher event handler never excutes. It is strange because today I reinstalled this service mabby hundred times and 3 times it was working but after I reinstalled it once again it stoped. And I haven't changed the code between the reinstallations at all.
Here is the methods and constructor from my class (MonitoringService) that inherits ServiceBase:
public MonitoringService()
{
InitializeComponent();
if (!EventLog.SourceExists(eventLog.Source))
{
EventLog.CreateEventSource(eventLog.Source, eventLog.Log);
}
// haven't changed it between the reinstallations
fileWatcher.Path = #"path";
}
protected override void OnStart(string[] args)
{
fileWatcher.EnableRaisingEvents = true;
eventLog.WriteEntry("start", EventLogEntryType.Information);
base.OnStart(args);
}
protected override void OnStop()
{
fileWatcher.EnableRaisingEvents = false;
fileWatcher.Dispose();
eventLog.WriteEntry("stop", EventLogEntryType.Information);
base.OnStop();
}
And file system watcher event handler:
private void fileSystemWatcher1_Changed(object sender, FileSystemEventArgs e)
{
using (var conn = new SqlConnection(GetConnectionString()))
{
conn.Open();
var productId = Convert.ToInt32(Regex.Match(e.Name, #"\d+").Value);
const string cmd = "UPDATE Products SET ImageModifiedDate=#date WHERE ProductId=#productId";
using (var command = new SqlCommand(cmd, conn))
{
command.Parameters.AddWithValue("#productId", productId);
command.Parameters.AddWithValue("#date", DateTime.Now);
command.ExecuteNonQuery();
}
}
eventLog.WriteEntry(string.Format("{0} has been changed: {1}", e.Name, DateTime.Now), EventLogEntryType.Information);
}
Question: it seems to me that this behavior is caused not by my code but rather by operation system settings . Can it be so?
****Edits: just discovered more specific stuff:**
1) If it shows the message (when I want to start the service):
The [service name] service on local computer started and then stopped. ....
I need to change Source property of eventLog, rebuild and reinstall. And this message will not show up; mabby next time.
2) I have the following folders hierarchy: images/prod-images. images and prod-images directories both contain image files. When the service is runing and I change the image from prod-images folder the message is written into the log as I wanted and the database is updated. But after one this event the service stops! (I checked this 3 times). And when I restart it and repeat this again a couple of times it updates database, writes logs and on the 3d time I get
The [service name] service on local computer started and then stopped. ....
But this is not the best part) If I change the image that is in images directory I can do it multiple times and the service doesn't stop. (only images from images/prod-images are bound to entries in the database).
So, mabbe this feature somehow referes to the database accessing?
Edits 2: in visual studio I use DEBUG -> Attach to Process to debug the service. I set up the breakpoints and change the image. First time the event handler executes flawlessly: the database is updated and the log message is written. But than I continue to press F11 (Step Into) and this event handler executes second time. At the line
var productId = Convert.ToInt32(Regex.Match(e.Name, #"\d+").Value);
I get "FormatException was unhandled". After this I stop debugging and the service stops! That's it: the exception occures in event handler.
Do You have any idea why it executes second time? Thanks!
P.S. I've already submited Davut Gürbüz answer cause he pointed me in the right direction.
Anyway, check out my own answer that explains the actual problem.

If you got start-stop error, this means you have an error in constructor.
Put a try catch into your ctor. You may log the error to eventlog in catch block.
Beside this I create a main method and start win service as a console app. If I get an instance of service in my main method I can also Debug it.
//You should select Console Application from Application properties
static void Main(string[] args)
{
MyWindowsService service = new MyWindowsService();
if (Environment.UserInteractive)
{
service.OnStart(args);
Console.WriteLine("Press any key to stop program");
Console.Read();
service.OnStop();
}
else
{
ServiceBase.Run(service);
}
}
Hope helps

The reason why the fileSystemWatcher1_Changed event handler method was executing twice is because I was monitoring images folder included subdirectories. And this event handler was monitoring all LastWrite events.
So, when I changed the image in images/prod-images directory this handler reacted to the image changing and also to the folder changing.
In this situation I either can change the monitoring path to prod-images or insert an if statement when updating the DB.
Such a silly mistake took me a couple of days to find it out))

Related

FTP poller occasionally hangs on file download until restart

I have a Windows service that polls a remote FTP server every three seconds. It checks a directory for files, downloads any files present, and deletes those files once downloaded. Average file size is 10 KB, and rarely they will go up to the 100 KB range.
Occasionally (I have noticed no pattern), the WebClient will throw the following:
System.Net.WebException: The operation has timed out.
at System.Net.WebClient.OpenRead(Uri address)
It will do this for one or more files, usually whatever files are in the remote directory at that time. It will continue to do so indefinitely, churning on the "stuck" files at each polling interval. The bizarre part is that when I stop/start the Windows service, the "stuck" files download perfectly and the polling/downloading works again for long stretches of time. This is bizarre because I download like this:
private object _pollingLock = new object();
public void PollingTimerElapsed(object sender, ElapsedEventArgs e)
{
if(Monitor.TryEnter(_pollingLock);
{
//FtpHelper lists content of files in directory
...
foreach(var file in files)
{
using(var client = new WebClient())
{
client.Proxy = null;
using(var data = client.OpenRead(file.Uri)
{
//Use data stream to write file locally
...
}
}
//FtpHelper deletes the file
...
}
}
//Release the _pollingLock inside a finally
}
I would assume that a new connection is opened and closed for each file (unless .NET is doing something behind the scenes). If a file download had an issue, it would get a fresh retry on the next polling interval (in 3 sec). Why would a service restart make things work?
I've begun to suspect that the issue has something to do with caching (file or connection). Recently I tried going into Internet Explorer and clearing the cache. Approximately 30 sec or so later, all the files downloaded with no service restart. But, the next batch of files to arrive all got hung up again. I might try adding a line like this:
client.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore);
or try disabling KeepAlives, but I want to get some opinions before I start trying random stuff.
So: What is causing the occasional timeouts? Why does restarting the service work? Why did clearing the cache work?
Update
I made the cache policy and keep alive change mentioned above about two weeks ago. I just now got my first timeout since then. It appears to have improved frequency, but alas, it is still happening.
Update
As requested, this is how I am kicking off the Timer:
_pollingTimer.AutoReset = true;
_pollingTimer.Elapser += PollingTimerElapsed;
_pollingTimer.Interval = 10000;
_pollingTimer.Enabled = true;`
Looks like you are kicking off your processing using the System.Timers.Timer.Elapsed event.
One gotcha that I found is that if your Elapsed event takes longer to execute than the timer interval, your event can be called again from another thread before it has finished executing.
This is specifically mentioned in the docs:
If the SynchronizingObject property is null, the Elapsed event is
raised on a ThreadPool thread. If the processing of the Elapsed event
lasts longer than Interval, the event might be raised again on another
ThreadPool thread. In this situation, the event handler should be
reentrant.
Assuming you are indeed using a vanilla timer with AutoReset=true (its on by default), first thing to do would be address this potential issue. You can use a SynchronizingObject, alternatively you can do something like this:
//setup code
Timer myTimer = new Timer(30000);
myTimer.AutoReset = false;
....
//Elapsed handler
public void PollingTimerElapsed(object sender, ElapsedEventArgs e)
{
//do what you currently do
...
//when finished, kick off the timer again
myTimer.Start();
}
Either way, the main thing is to ensure that your code doesn't accidentally get called simultaneously by multiple threads - if that happens there's a good chance that occasionally you'll have one thread trying to download something from the site while another thread is simultaneously deleting the file.
The things that you mentioned e.g. it only happens occasionally, that normally file sizes are small, that its fixed by a restart, etc. would point me in the direction of this being the issue.

SqlDependency in a Windows Service not firing

I am trying to monitor a database table for changes using the SqlDependency class. Though I must be missing something. I have followed all of the examples that I see online and I have reviewed all the questions on this site. I just don't see what I am missing. Here are the initial commands that I ran on the database to enable the service broker and create the queue and service.
CREATE QUEUE ScheduleChangeQueue
GO
CREATE SERVICE ScheduleChangeService ON QUEUE ScheduleChangeQueue ([http://schemas.microsoft.com/SQL/Notifications/PostQueryNotification])
GO
ALTER DATABASE [database] SET ENABLE_BROKER
On the C# side, I have created a class that has a single static Setup method that is called to initiate the process. Here is the code for that:
public class SqlDependencyManager
{
private static bool DoesUserHavePermission()
{
var success = false;
try
{
Program.Log.Info("Retrieving SqlPermission to establish dependency...");
var clientPermission = new SqlClientPermission(System.Security.Permissions.PermissionState.Unrestricted);
// this will throw an error if the user does not have the permissions
clientPermission.Demand();
success = true;
Program.Log.Info("SqlPermission established. Continue setting up dependency.");
}
catch (Exception ex)
{
Program.Log.Error(ex, "SqlPermission not able to be established.");
}
return success;
}
public static void Setup()
{
if (!DoesUserHavePermission())
{
return;
}
var connectionString = ConfigurationManager.ConnectionStrings["ShowMakerPro"].ConnectionString;
// You must stop the dependency before starting a new one.
// You must start the dependency when creating a new one.
SqlDependency.Stop(connectionString);
SqlDependency.Start(connectionString);
using (var cn = new SqlConnection(connectionString))
{
using (var cmd = cn.CreateCommand())
{
cmd.CommandType = CommandType.Text;
//cmd.CommandText = "SELECT MAX(LastChangeTime) FROM Schedule WHERE ChannelID IN ( SELECT ID FROM Channels WHERE Type = 1 ) AND StartTime BETWEEN (GETDATE() - 7) AND (GETDATE() + 30)";
cmd.CommandText = "SELECT LastChangeTime FROM dbo.Schedule";
cmd.Notification = null;
// Creates a new dependency for the SqlCommand. Then creates attaches handler for the notification of data changes
new SqlDependency(cmd).OnChange += SqlDependency_OnChange;
cn.Open();
cmd.ExecuteReader();
}
}
Program.Log.Info("SQL Dependency set. Now monitoring schedule table for changes.");
}
private static void SqlDependency_OnChange(object sender, SqlNotificationEventArgs e)
{
if (e.Type == SqlNotificationType.Change)
{
// this will remove the event handler since the dependency is only for a single notification
((SqlDependency)sender).OnChange -= SqlDependency_OnChange;
ScheduleOutputterService.BuildSchedules();
Program.Log.Info("SQL Dependency triggered schedule rebuild. Resetting SqlDependency to monitor for changes.");
Setup();
}
}
}
I see the code get setup ok and the OnChange method is fired once for the Subscribe but then I never see it fire after that. I manually go into the database and change the LastChangeTime field hoping that it will force the firing of the event but nothing happens.
Can someone please shed some light on where I am screwing up? I see some people saying on line that this works fine in a windows form but they are also having some problems while in a service.
So I finally figured out the answer to my question and I thought I should list all the steps I took to get to this point so someone else coming along behind me will also have another place to look for answers since I seemed unable to find all of my answers in one place.
First off, I noticed in my situation that as soon as the subscription was set the OnChange event would fire right away. That is why I put in the check for change type so I could ignore those events. It turns out that ignoring those events was not a good thing because those events were actually trying to tell me something. Doing a search on my values directed me here:
http://msmvps.com/blogs/siva/archive/2011/11/22/subtle-sqldependency-notification-issue.aspx
This was very valuable because it helped me to see that there must have been a problem with some of my options in the database. Upon further inspection I noticed that my database was set to SQL Server 2000 compatibility. That is obviously my first problem because this is a 2005 and greater feature. So I tried to change my settings to the high version. This worked ok but then I still noticed that I was receiving the same event. So then I checked my database settings and I found that they were not set to match the options required to run service broker. You can see all the required option settings here:
http://msdn.microsoft.com/en-us/library/ms181122(v=SQL.100).aspx
After I inspected all these and tried to do some workarounds to get the right settings all squared away the setup was still failing. But this time it was failing because the updates would not save. It turned out that the client had triggers on the table in question and it's database settings that were being used to execute the trigger were in conflict with the needed settings to run QueryNotifications.
So long story short, the client decided that they did not want to change all the triggers that were being used so they abandoned the effort. But I learned a lot about how to troubleshoot SqlDependency and ServiceBroker. Hopefully these few links I provided will be helpful for someone else. A couple more links that were very helpful were mentioned in the comments but I am going to repost them in this answer so you can have some other items to review.
http://rusanu.com/2006/06/17/the-mysterious-notification/
http://rusanu.com/2005/12/20/troubleshooting-dialogs/

How to detect when a page is being update to IIS

Whenever I update my web app on IIS, any user who currently using it, will see the page be unresponsive and it won't work again until they refresh the browser. (The update process last for about 30 seconds)
I would like to show up a notification, such as a javascript alert, for user to know that the page is being udpated and please try to refresh the page after 30 seconds, etc.
I tried to catch the Exception in Global.ascx but no exception was thrown in this case.
Consider using app_offline.htm. It is a page that will cause clients to see your IIS app as being down. When you're through updating, just remove the page.
You could create a FileSystemWatcher in global.ascx then bubble up (update a js for instance) an exception when a file is updated. You could start with this:
using System.IO;
namespace WebApplication1
{
public class Global : System.Web.HttpApplication
{
FileSystemWatcher watcher;
void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
watcher = new FileSystemWatcher(this.Context.Server.MapPath("/"));
watcher.Changed += new FileSystemEventHandler(watcher_Changed);
}
void watcher_Changed(object sender, FileSystemEventArgs e)
{
//set a value in js file
FileInfo jsFilesChanged = new FileInfo(Path.Combine(this.Context.Server.MapPath("/"), "scripts", "files_changed.js"));
using (StreamWriter jsWriter = (!jsFilesChanged.Exists) ? new StreamWriter(jsFilesChanged.Create()) : new StreamWriter(jsFilesChanged.FullName, false))
{
jsWriter.WriteLine("var changed_file = \"" + e.Name + "\";");
}
}
//.......
}
}
Then in client code include files_changed.js and create a periodic timeout call to check the var changed_file. Also, make sure watcher doesn't get garbage collected.
Some references:
http://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher.aspx
http://www.developerfusion.com/article/84362/extending-filesystemwatcher-to-aspnet/
How the big boys do this:
You need to have a way of posting an alert on a page. Typically this is done by having a table in your database for these alerts. Basically you are just storing some text in there like "hey, the site is going down for maintenance between 8:00am and 8:01am"..
On each page load, you check that table and display any messages found in a conspicuous place (like the top).
Prior to pushing an update you add the alert, while giving them enough time to wrap up whatever it is that they are doing.
After the push is complete you clear out the alerts table.
Honestly the main issue you have is simply one of scheduling updates and communicating to the users what's about to happen. You want to do so in a way that isn't a surprise. That said, you might consider enabling the optimizeCompilations flag in order to try and speed up the compilation time of your website when it is first hit after pushing an update.

ASP.NET FileSystemWatcher Changed Event

I created a ASP.NET Website with Visual Studio 2010 C#.
My program reads a config file to create some classes and display informations.
The config file is not included in the project (does not appear in the solution explorer). If I modify the file while my application is not running, and run it afterwards, it still reads the old version like it keep it in cache. I have to close Visual Studio for it to accept the changes.
My second problem is related to (if not caused by) my first problem. I am using FileSystemWatcher to see if the config file is modified while the application is running, but the Changed event is never called.
private string _configFilePath;
private FileSystemWatcher _watcher;
protected void Page_Load(object sender, EventArgs e)
{
//Gets the config file in the application's parent directory
string appPath = this.MapPath("~");
string[] split = appPath.Split('\\');
_configFilePath = appPath.Substring(0, appPath.Length - split[split.Length-1].Length);
Application.Add("watcher", new FileSystemWatcher(_configFilePath.Substring(0, _configFilePath.Length-1), "*.xml"));
_watcher = (FileSystemWatcher)Application["watcher"];
_watcher.NotifyFilter = NotifyFilters.FileName;
_watcher.Changed += new System.IO.FileSystemEventHandler(Watcher_Changed);
_configFilePath += "ProductsConfig.xml";
UpdateDisplay();
}
private void Watcher_Changed(object source, FileSystemEventArgs e)
{
UpdateDisplay();
}
How can I solve this?
Thank you
My second problem is related to (if not caused by) my first problem. I
am using FileSystemWatcher to see if the config file is modified while
the application is running, but the Changed event is never called.
It's never called because at that point the Thread that's servicing the request is already returned to the pool and the request has ended. The Watcher_Changed event will never fire.
You need to tackle this in a different manner, remember that HTTP is a "disconnected" protocol, after the request has been served, don't expect any of the page events to fire "automagically" when something happens on the server side that would notify all connected users.
One way to do this is via Ajax. You'd need to constantly "ask" the server whether there's new information or not and update the sections of the page that need to be updated as a result of the change on the server.
There are 2 problems here.
1. You never called _watcher.EnableRaisingEvents = true;
2. You try to go to the parent folder of your root folder, which might not be allowed.
/ Tibi

WPF application has encountered a problem and needs to close, how to get good message?

I am currently working on a WPF application that processes data in a database and it worked fine when I tested it with a test database with around 1000 rows but now I want to process around 50 000 rows and it just crashes during the processing giving me "'application' has encountered a problem and needs to close ... Do you want to send error report to Microsoft...".
Now this may seem like a duplicate of a couple of other questions but I've tried AppDomain.CurrentDomain.UnhandledException, AppDomain.CurrentDomain.ProcessExit, Application.DispatcherUnhandledException and it just crashes with no message anyway.
Here's what it looks like:
private void OnStartup(object sender, StartupEventArgs e)
{
AppDomain.CurrentDomain.UnhandledException += (s, args) =>
{
MessageBox.Show("Message1");
};
AppDomain.CurrentDomain.ProcessExit += (s, args) =>
{
MessageBox.Show("Message2");
};
this.DispatcherUnhandledException += (s, args) =>
{
MessageBox.Show("Message3");
};
try
{
Views.MainView view = new Views.MainView();
view.DataContext = new ViewModels.MainViewModel();
view.ShowDialog();
}
catch (Exception exception)
{
MessageBox.Show(exception.ToString());
}
}
The processing is started by a command (a GUI button with command binding to call this):
public void Process()
{
Thread workerThread = new Thread(new ThreadStart(DoProcess));
workerThread.IsBackground = true;
workerThread.Start();
}
private void DoProcess()
{
try
{
// Most probably crashes during that
DoStuff();
}
catch (Exception e)
{
System.Windows.MessageBox.Show(e.ToString());
}
}
I checked the memory usage during execution and it never goes above 70 meg, so that shouldn't be a problem. I use 2 COM components, one that is an .exe and another that is a .dll, I don't know if problems can come from that. Note that sometimes those components crash and I do receive a useful error message when it happens. I work with NHibernate to read/write from the database.
For now I have absolutely no clue what the problem is (the DoStuff() part is quite big), and I don't understand how an error can get past all those exception handlers and just crash the application without information. Note that I can't debug the application in Visual Studio because I run the application on a VM that doesn't have Visual Studio installed (and I've been waiting for 2 months to get my IT department to install me sql server so that I can run my application on my computer).
Any help would be appreciated!
Your DoProcess function is in a background thread. Another thread may be crashing, or you might have an issue calling MessageBox from a background thread because it's not the UI thread -- so you may be getting an exception, and then a new exception is thrown from your catch because of the MessageBox call. Try inserting code to write the message to a file before the MessageBox call and see if that works, or even a Console.Beep() for that matter and listen for it :-) If that uncovers nothing, try adding log statements to files at many places in your code until you narrow down where the crash occurs.
You really need to get Visual Studio and the debugger set up. You'll be probing in the dark without it.

Categories

Resources