Showing posts with label debugging. Show all posts
Showing posts with label debugging. Show all posts

Tuesday, February 16, 2010

Tips and tricks for writing Windows services in C#

This is not meant to be an exhaustive tutorial on writing Windows services. This is just a couple of items that I tend to forget in the time between writing services. It’d be great if it helps anyone else in the process.
  1. If you haven’t done this before, or forgot everything you’ve learned, here’s a tutorial: http://www.grinn.net/blog/dev/2008/01/windows-services-in-c-part-1.html or refer to http://msdn.microsoft.com/en-us/library/zt39148a(VS.80).aspx
  2. Put your Business Logic/BOL/code that does something in a separate assembly, or at the very least in a separate method marked public, so that you can add a gui/console application/unit test to your solution to execute this code. It saves a lot of time in debugging code.
  3. The default timer in the toolbox, System.Windows.Forms.Timer, does not work in a service. You need to use System.Timers.Timer, which can be added to the toolbox. Refer here for an explanation of why it doesn’t work (Winforms timers need a messagepump on a UI thread): http://msdn.microsoft.com/en-us/library/tb9yt5e6.aspx
  4. Remember to stop your timer while processing, and restart it afterwards.To add an installer, right click on the component view of your service, and click “Add Installer”. Don’t bother with manually adding an installer to your project.
  5. Add a setup project to your solution to install the service. Add the service’s primary output action to the install, rollback and uninstall actions. If you don’t add it to rollback, a failure after the base.Install(stateSaver) in the installer class of the service, will leave you with a service that is installed, but can’t be replaced or uninstalled by your MSI. When that happens you need to use the InstallUtil command from the command line.
  6. To use the installutil from the command line, type "C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\installutil" where is the name of the assembly of your service to install the service. Add the /u flag to uninstall the service.
  7. Use Debug.Assert(false, "Attach here to debug") to have your service pop up a message to which you can attach the debugger to step through your code. Not absolutely neccesary, but it makes things easier. For that matter, this can also be used when debugging installers, or anything else requiring to be paused at a certain place for attachment, before a breakpoint can be hit.
  8. Remember to log exceptions, they will not be logged automatically (maybe if you use the logging enterprise application block?). The eventlog is a good place to do this, but remember to register your source first. This is probably best done in the installer, unless you make it configurable in the service. Creating a source requires admin privileges. Here’s a how-to: http://msdn.microsoft.com/en-us/library/k00ce235.aspx
  9. Include something to stop your service after n number of concurrent failures, or to stop logging the exceptions. You don't want to fill up the eventlog with nonsense.
  10. Application settings in the config file is used as usual with Properties.Settings.Default.PropertyName
  11. The default service name can be set on the properties of the service in the component view. There are a few other useful properties here, like CanPauseAndContinue. Check it out.
  12. The account for which to run this service is set in the properties of the ProcessInstaller component in the ProjectInstaller file’s component view.
I’ll add more items to this list as I discover them, but this is all I’ve need so far to write a windows service.

Thursday, November 5, 2009

How to enable tracing on WCF services to troubleshoot things like serialization errors

This is an excerpt from an article on MSDN on tracing. Details can be found there.
It will help you debug that annoying "The connection has been forcibly closed" error, that has no usefull information attached to it at all.

1. Add the following code in your web.config or app.config for the WCF service:
<configuration>
<system.diagnostics>
<sources>
<source name="System.ServiceModel"
switchValue="All"
propagateActivity="true">
<listeners>
<add name="traceListener"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData= "c:\log\Traces.svclog" />
</listeners>
</source>
</sources>
</system.diagnostics>
</configuration>


This code should be added after the
<configSections>
element. Not doing so will cause an error.

Alternatively, use the configuration editor at Start -> All Programs -> Microsoft Windows SDK v6.0A -> Tools -> Service Configuration Editor to enable the diagnostics.

2. Make sure the "c:\log\" path is created and accessible to the appropriate accounts (I've just given the "everyone" account write access to it, but the .net worker process account would probably be enough)

3. Open the Traces.svclog file with the service traceviewer, which can be found here:

"C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\SvcTraceViewer.exe"

or go to Start -> All Programs -> Microsoft Windows SDK v6.0A -> Tools -> Service Trace Viewer

And that's it. The service viewer will show you any errors that was logged, and provides a very handy way to drill into the details.