Best kept secret in Visual Studio, or how to generate a Windows service installer class

When writing a windows service application I always stuck at the same moment. And that is when I need to add an installer class for the service. With the installer class you can configure the behavior of a Windows service, like the startup type and the service name to show up in services list.

Although this is quite a helpful class, I’m always doomed when it’s the moment to add it to my project. Ok, I could implement the service installer class from scratch and derive from InstallerBase, but something in the back of my head reminds me that there is way that VS can generate the class for you. But, unfortunately it’s nearly impossible to find the function in the menus VS is providing. And the place is so well hidden, that it is impossible to remember where you found it once you used it.

Here is where you can find it:

Click on the Service implementation class, that the [Design] page comes up. Then right click somewhere in the gray area of the screen and choose “add installer” from the context menu.

image

Maybe this might make sense in a way for at least someone. I find it absolutely unintuitive and it’s definitely the last place I’d search. Always.

Advertisements

Setup tracing in ASP.NET

Logging and tracing is most important to your application. With the .Net Framework developers have quite a handy tool to trace and log automatically data about the current state of an application in a production environment. Although this is not new, the infrastructure is available since the first version of .Net, it’s definitely worth to talk about it, because of the flexibility tracing is offering and the easy way of configuration.

Another important point, and in my eyes something that is often forgotten by developers, is that the configuration can be done by the IT department and almost independent from the developer. In my experience many  developers underestimate the IT perspective. Although developers provide logging and maybe tracing as well, they do it in their own way, by logging into a database for instance. The disadvantage is obvious, those logs are difficult to integrate into the monitoring tools of an IT department. The configuration includes the source that is to be logged, when it is to be logged and finally where it should be logged to. In some cases it could make sense to log into the event log, in other cases  it won’t, but in the end it should be a decision made by the IT staff.

Goal

In the following web application I used three different trace listeners. Because this application is installed on the web, it was necessary for me to be able to follow the complete trace of every single request while it’s passing through all methods in the application. By event type filters you can configure the verbosity of different trace listeners. For example, you want a critical exception logged to the windows event log, while application tracing information needs to be logged to a file only while you are reproducing a specific error.

<system.diagnostics>
   <sharedListeners>
     <add name="FileLog" type="Microsoft.VisualBasic.Logging.FileLogTraceListener, Microsoft.VisualBasic, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"  
          initializeData="FileLogWriter" location="Custom" customLocation="e:\dsmtemp\" traceOutputOptions="DateTime" />
     <add name="CustomDbLogger" type="dbLib.CustomTraceListener, dbLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a8a57c651bc37c00">
          <filter type="System.Diagnostics.EventTypeFilter" initializeData="Warning" />      
     </add>
     <add name="EventLog" type="System.Diagnostics.EventLogTraceListener" initializeData="MyApplication">        
          <filter type="System.Diagnostics.EventTypeFilter" initializeData="Error" />
     </add>
     </sharedListeners>
   <sources>
      <source name="DefaultSource" switchName="TraceSwitch" switchType="System.Diagnostics.SourceSwitch">        
          <listeners>          
             <add name="FileLog"/>          
             <add name="EventLog"/>          
             <add name="LimLog"/>        
         </listeners>      
      </source>    
   </sources>    
   <switches>      
      <add name="TraceSwitch" value="Verbose" />    
    </switches>  
</system.diagnostics>

The code above shows a configuration example for three different trace listeners.

First, I added a file trace logger that captures all trace events and stores in a file. I also configured that the listener automatically adds a timestamp to the end of each line.

The second listener is a custom trace listener that can write specific trace data to a database.

And finally, I added an eventlog trace listener. All those listeners are added to the sources collection by name.

By adding filters you can control when the listeners take effect. A filter takes a string representing the EventType enum in escalating order, like:

  • Verbose
  • Information
  • Warning
  • Critical
  • Error

The enum has some more values, like Start and Stop which are typically used by WCF tracing.

The configuratin above shows that the CustomDbLogger should only log to the database if the EventType is of Warning and above. This includes all Critical and Error events. While only events of type Error are written to the Windows Eventlog.

I use the file logging for method tracing. It is configured generally in the default  TraceSwitch. In this example it is set to Verbose, which would log everything that is available. It is recommended to set this to Information or even higher to Warning in production and only switched to Verbose if you are investigating a concrete error or misbehavior.

Tracing in code

With the configuration we did in the application config file our work is almost done. All we need in code is to write a new log entry.

   My.Application.Log.WriteEntry(lr.ToString, TraceEventType.Verbose)
   My.Application.Log.DefaultFileLogWriter.Flush()

Our three trace listeners can now apply their event filters and check if its necessary to persist the trace data or ignore it.

By calling flush we ensure that the trace line is written immediately to the log file. Otherwise the trace trace listener would queue it, until a specific flush event appears (which can be configured as well) or until the application is recycled.

Custom TraceListener

Writing a customer TraceListener is easy. You need to inherit from a TraceListener and override the WriteLine method.

Public Class CustomDbTraceListener    
       Inherits TraceListener   
       Public Sub New()        
          MyBase.new()    
       End Sub
       Public Overloads Overrides Sub WriteLine(message As String)        
          'TODO: Implement your logging logic here    
       End Sub
End Class

Dynamic tables with jQuery templates

To render tables in HTML dynamically using JavaScript and a JSON enabled ASP.NET WCF service is pretty easy using jQuery templates. Here’s a little sample application that updates an HTML table with log data coming from a web server.

jQuery.templ()

jQuery template is a plugin for jQuery that can render specifiied HTML content as a template, using specified data. You can find more about jQuery.templ() on the jQuery website here.

Server setup

First we need a service that provides a method that is polled by the client to retrieve our data. I’m using an ASP.NET web application that is exposing a WCF service and a webHttp binding. That makes it quite easy to wrap my collection of table row objects later on into JSON objects, which can be, in most convenient way, consumed by a JavaScript client.

Here’s the service configuration part from the web.config, showing the binding and behavior.

  <system.serviceModel>
      <bindings>
        <webHttpBinding>
          <binding name="jsonBinding" maxBufferSize="2147483647" maxBufferPoolSize="524288"
            maxReceivedMessageSize="2147483647">
          </binding>
        </webHttpBinding>
      </bindings>
      <behaviors>
        <serviceBehaviors>
          <behavior name="NotifyServiceBehaviour">
            <serviceDebug includeExceptionDetailInFaults="true"/>
            <serviceMetadata httpGetEnabled="True"/>
          </behavior>
        </serviceBehaviors>
        <endpointBehaviors>
          <behavior name="JsonBehavior">
            <webHttp />
          </behavior>
        </endpointBehaviors>
      </behaviors>
      <services>

The method implementation providing the log data is easy. To avoid any caching on the client I append a Cache-Controll header to the response headers collection.

  Public Function GetRows(guid As String) As LogRows Implements ILog.GetRows
        WebOperationContext.Current.OutgoingResponse.Headers.Add("Cache-Control", "no-cache")
        Return LogService.Instance.GetRows(New Guid(guid))
    End Function

Client setup

The  client consists of a webpage that contains a simple HTML table extended by JavaScript, a JavaScript file for the templating logic and the necessary jQuery files of course.

To template a table we need to make the table body dynamic, we do that by using inline JavaScript, to setup our column names. By accepting the convention that the property names in our returned JSON object is list are the names of the columns in the table, it’s easy for the jquery tenplate engine to render the actual table  body.

 <tbody id="placeholder">
            <script id="logTemplate" type="text/x-jquery-tmpl">
                <tr id="myTableRow">
                    <td>${Category}</td>
                    <td>${LogDate}</td>
                    <td>${SystemID}</td>
                    <td>${Source}</td>
                    <td>${Message}</td>
                    <td>${Stack}</td>
                </tr>
            </script>
        </tbody>

The script id attribute points to a JavaScript function that does the template replacing. The tr tag defines the table row template for the iteration. Each td contains the actual column/property to be replaced.

The JavaScript logic that renders and refreshes the table contains of three functions. First, the init function that creates a new Guid, to identify the client. Second, the server method is called in the getLog function. And finally renderTable is called, which searches for the table body with the id “placeholder” and replaces the template rows with the actual data.

//initialization
//each new client gets a new GUID assigned
function init(url) {
    var clientId = jQuery.Guid.New();
    url = url + clientId;
    getLog(url);
}

//Retrieves new log messages every 10 seconds 
function getLog(url) {
    $.getJSON(url, null, function (result) { renderTable(result); });
    setTimeout(function () { getLog(url) }, 2000);
}

//pumps the async result from service into the templated table
function renderTable(result) {
    if (result != null) {
        $("#logTemplate").tmpl(result.Log).prependTo("#placeholder");
    }
}

I’m using the object.prependTo() method to prepend the new rows, because usually you want read a log viewer

top down.