Sometimes working with silverlight you need to have a sort of service, always available for global tasks or working in background notifing the main thread when something happen. I've found this scenario many times during my work, as an example when I needed to poll a service to get periodic updates, or in another case with a caching service. Every time I developed this services using a static class or an instance of a class exposed by the Application, but the main problem is to manage the lifecycle to run or stop the service freeing the allocated resources when needed.
With Silverlight 3.0 this kind of services has been covered by a new tool named Application Services. An application Service is simply a class that implements the IApplicationService interface. This interface require two methods to be implemented by the Application Service class:
1: public interface IApplicationService
3: void StartService(ApplicationServiceContext context);
4: void StopService();
This methods will be called by the Silverlight runtime when the service need to start during Application initialization and a few moments before the runtime terminate when the browser is closing or the user is navigating away. In the StartService() method the Application Service may run some code to begin his work, initializing variables, running threads and so on. On the other side the same service may notify threads to exit when the StopService() method is called by the runtime.
An Application Service class has to be registered in a specific section of the app.xaml. The application markup file is an ideal place to register this kind of classes. It a global location accessible by all the pages and controls, and the service instances may be simply configured with attributes mapping the class properties. Here is a sample of code showing how to register a FeedPollingService available in the sample source code:
1: <Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
6: <local:FeedPollingService x:Name="polling"
9: Timeout="10000" />
First of all the "local" namespace is declared in the Application tag. The application service is registered in the <Application.Services> element. This element needs you specify a unique name for the service instance. This name may be used to reach the instance from every class in the application. The configured FeedPolllingService exposes a "Completed" event we need to handle to get notified of feed download:
1: public Page()
3: FeedPollingService service = Application.Current.Services["polling"] as FeedPollingService;
4: service.Completed += new EventHandler<CompletedEventArgs>(service_Completed);
This happen in the Page constructor. In the service_Compleded event handler we simply handle the incoming feed binding it to the user interface to show the content. My service contains a thread that poll a rss feed every configured timeout so in the completed event I need to marshal the thread context using the Dispatcher object.
1: #region IApplicationService Members
3: private ManualResetEvent exitEvent = new ManualResetEvent(false);
5: public void StartService(ApplicationServiceContext context)
7: ThreadStart start = new ThreadStart(Service_Thread);
8: Thread thread = new Thread(start);
12: public void StopService()
The FeedPollingService implements the IApplicationContext interface. In the StartService method the service start a thread that do the recurrent polling to the feed. In the StopService method instead a ManualResetEvent is triggered to notify the thread procedure to exit gracefully.
The other part of the application is simply the use of syndication to deserialize the downloaded feed and the binding of the feed items to the interface. The attached source code is available to test the Application Services.
Download Code: Elite.Silverlight3.AppExtensibility.zip (2,07 MB)
Demo Video: ApplicationExtensibility.wmv (676 KB)