log4net •  C++ •  VB6 •  VBA •  .NET  •  Silverlight •  Windows Phone 7 •  ASP.NET

Universal Trace Monitor for Software Developers and Testers

Using DevTracer with Microsoft® Windows Phone 7 Apps and Silverlight

For using DevTracer with Windows Phone 7 or Silverlight some additional code is required to get the trace information out of the Silverlight plug-in or the phone.

At the bottom of this page you find a link where you can download a Visual Studio 2010 solution with sample code. It includes projects for Silverlight and Windows Phone 7, just everything required to use DevTracer Monitor. Below a short description of the core parts can be found. The core parts are:

  • A web service.

    The Silverlight or Windows Phone 7 application sends the trace information to this web service. The web service, which is running on the full version of the .NET framework, then can use a Trace Listener to forward the trace information to DevTracer Monitor.

    This web service only has one method: public void Write(string str)

  • Send trace information to the web service.

    The sample code contains a class NrTracer, which calls web service. This class just collects the trace information, and then used a background thread to send the information to the Web service. The calling thread is therefore not blocked, and you hardly see any decrease in performance.

    Because by default in Silverlight and Windows Phone 7 a web service can only be called asynchronously, the code also syncs the calls to the Web Service.

The Web Service

The web service only has one method:
using System;
using System.Diagnostics;

public class DevtracerService : IDevtracerService
{
    public void Write(string str)
    {
        try
        {
            Trace.Write(str);
        }
        catch (Exception)
        {
        }
    }
}

The Web.Config file for the web service then uses the following lines to redirect the output of Debug.Write() to DevTracer Monitor.

  <system.diagnostics>
    <trace autoflush="false" indentsize="4">
      <listeners>
        <add name="myListener"
         type=
          "NRSoftware.Tracer.Listener,NRSoftware.Tracer,Version=1.0.0.0,Culture=neutral,PublicKeyToken=867dfab712f16c0b"
         initializeData="localhost:12345" />
        <remove name="Default" />
      </listeners>
    </trace>
  </system.diagnostics>

For details about configuring an application to use with DevTracer Monitor see Using a Configuration File.

The directory where the Web Service is hosted should also have a file clientaccesspolicy.xml. Without this file a Silverlight application cannot access the Web Service, if the service is hosted at a Url different from the one where the Silverlight application is loaded from. More information about this subject can be found at Making a Service Available Across Domain Boundaries.

Helper Class for the Application Being Traced

The sample code includes a static class NrTracer which can be used to send the trace information to the web service. The method called by Silverlight or Windows Phone 7 applications is NrTracer.Write(string str):

public static void Write(string str)
{
  lock (_locker)
  {
    _sb.Append(str); // append to StringBuilder
  }
  _eventDataToSend.Set(); // notify thread 

  if (_thread == null)
  {
     _thread = new Thread(ThreadRunner);
     _thread.Start();
  }
}

This method adds the trace information to a StringBuilder in a thread safe manner, notifies the thread that there are new data, and starts the thread if it is not running yet.

Because this method basically only appends the trace information to a string builder, the calling thread (often the UI thread) is not blocked.

ThreadRunner() is the method sending the trace information to the web service. First an instance of the proxy for the web service is created. The sample code does not use a configuration file for creating the proxy. It uses BasicHttpBinding (other bindings are not supported in Silverlight 3 and Windows Phone 7). The web service Url is provided by the public property NrTracer.ServiceUrl. It must be set before any method of NrTracer is used. A good place to set it is the constructor in app.xaml.cs. The sample code actually sets it in the constructor of class NrTracer.

if (string.IsNullOrEmpty(ServiceUrl))
  {
     _thread = null; 
     return; // terminate thread
  }

Binding binding = new BasicHttpBinding();
EndpointAddress address = new EndpointAddress(ServiceUrl);
_client = new DevtracerServiceClient(binding, address);
_client.WriteCompleted += delegate(object o, AsyncCompletedEventArgs args)
   {
       if (args.Error != null)
            Error += "WriteCompletedError " + args.Error.Message;
       _eventWebservicesSyncer.Set();
   };

After the proxy is created, a handler for the WriteCompleted event is set up. The call to _eventDataToSend.Set() is used for syncing the calls to the Write() method of the web service.

The code doing the real work of the thread first gets the data from the StringBuilder. This is done in a thread safe manner again.

_eventDataToSend.WaitOne(); // wait for data
string str = null;
lock (_locker)
{
   if (_sb.Length > 0)
   {
      str = _sb.ToString();
      _sb.Remove(0, _sb.Length);  // Clear() not supported in silverlight 3 and silverlight windows phone
   }
}   
 

The code for sending the data seems to be complex at first glance. Because the number of characters which can be send to a web service are limited, the data are send in slices of at most MaxNoOfCharsToSend, which is set to 8.000 in the sample code. Of course it is possible to increase the limit by changing the web.config file of the web service, but doing it this way it is working with standard values.

for (int i = 0; i < str.Length; i += MaxNoOfCharsToSend)
{
    int startIdx = i;
    int characters = MaxNoOfCharsToSend;
    if (startIdx + characters >= str.Length)
        characters = str.Length - i;
    string temp = str.Substring(i, characters);
    if (characters > 0)
    {
        _client.WriteAsync(temp);
        if (!_eventWebservicesSyncer.WaitOne(TimeoutMilliseconds)) // waits for WriteCompleted event
            Error = "Timeout calling WriteAsync";
        if (!string.IsNullOrEmpty(Error))// could also have been set in WriteLineCompleted
            return; // terminate the thread
    }
}

Error Handling

Class NrTracer contains some very basic error handling, which is sufficient for most cases. There is a public property string Error, which indicates an error if string.IsNullOrEmpty(Error)==false. Whenever en error occurs, the thread sending the trace information to the web service is terminated.

The most common error is related to connection to web sevice, either because the web server's ServiceUrl is not specified correctly, or there is a problem connecting to the service.

Additional Methods for Convenience

In addition to Write() there are three more methods, which call Write() internally:

  • void WriteFormat(string format, params object[] strs)

    This method uses String.Format() for formatting.
    Example: NrTracer.WriteLineFormat("This is line {0}",lineIndex);

  • void WriteLineFormat(string format, params object[] strs)

    Same as WriteFormat, but appends an Enviroment.Newline

  • void WriteLine(string str)

    Same as Write, but appends an Enviroment.Newline

Sample Code

The ZIP-File contains a Visual Studio 2010 SP1 solution with five projects:

  • DevtracerService

    The project for the web service described above.

  • Wp7Tracer

    The project for class NrTracer described above.

  • SilverlightTracerTest

    Project for Silverlight application for demonstrating NrTracer. This project references Wp7Tracer.

  • SilverlightTracerTest.Web

    ASP.NET application for hosting SilverlightTracerTest.

  • Wp7TracerTest

    Project for Windows Phone 7 application for demonstrating NrTracer. This project references Wp7Tracer.

Click here to download
the sample code

Download size is about 0.6 MB.

Using DevTracer Monitor with an Application Deployed on the Web or Phone

In most cases DevTracer will be used while developing an application. But sometimes it would be great for trouble shooting if it could be used with a productive application already deployed.

In this case the application must be deployed with class NrTracer, and there must be a way to configure the application to use it. But where will the web sevcice be hosted?

One possibility is to use a dynamic DNS service like http://www.dyndns.com so your developing machine can be contacted by the application, and you can host the web sevice on your local machine. The ServiceUrl will be something like http://myDomain.dyndns.com/devtracerservice.svc. This works fine with Silverlight and Windows Phone 7 applications.

We recently had a problem with a Windows Phone 7 application, which only showed up when using a very slow data connection. The problem did not show up when connecting the phone to the developing machine and attaching a debugger, because in this case the the data connection was fast enough. But using DevTracer and and DynDns helped us to solve the problem.