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.
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.