The Application Class and Application Services in Silverlight 3

  • Aug 24, 2009 at 12:00 PM
  • Shawn Wildermuth
  • 4 Comments

Url: http://wildermuth.com/downloads/FunWithAppServi...

Silverlight Logo

While digging into Silverlight 3, I noticed an oft overlooked new feature: Application Services. The problem revolves around the Application class so let's talk about that class first, then i'll get ot the services.

In Visual Studio (or Blend), the Application class represents a pretty important piece of the runtime environment. In fact (much to a surprise to some Silverlight Dev's), the Main Page XAML file is not the first thing loaded. Typically the first thing loaded is the Application class (the class behind the app.xaml file). How does it know to load this class?  The AppManifest.xaml file.  Ok, let's dive a little deeper.

When you build a Silverlight application, it creates a .xap file with your assembly and other resources (other assemblies, images, fonts, etc.) that are needed by your application. In addition, it creates a final AppManifest.xaml file for the .xap file.  Here's a sample:

<Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
           EntryPointAssembly="FunWithAppServices"
            EntryPointType="FunWithAppServices.App"
            RuntimeVersion="3.0.40624.0">
  <Deployment.Parts>
    <AssemblyPart x:Name="FunWithAppServices"
                  Source="FunWithAppServices.dll" />
    <AssemblyPart x:Name="MyAppService"
                  Source="MyAppService.dll" />
  </Deployment.Parts>
</Deployment>

This AppManifest.xaml file is created during the build (which is why it looks different from the one in your project). Not that there are two attributes that describe the EntryPoint to the .xap file.  This tells the runtime which assembly to load and what type to create to start the application.

When the application class (called App in the default templates) is loaded, it starts the whole process for creating an instance of the MainPage as shown below:

public partial class App : Application
{

  public App()
  {
    this.Startup += this.Application_Startup;
    this.Exit += this.Application_Exit;
    this.UnhandledException += this.Application_UnhandledException;

    InitializeComponent();
  }

  private void Application_Startup(object sender, StartupEventArgs e)
  {
    this.RootVisual = new MainPage();
  }

...
}

So why does any of this matter? Because the Application lives for the life of the application. Therefore many developers find it a common place to hang other functionality. In fact, some frameworks help by getting you to derive your App class from another class to provide even more functionality. Of course, as soon as you need/want two of these sets of functionality, you're stuck because you can't multi-derive in .NET.

The problem with this is as different services to the application are necessary, the App class gets busy and hard to maintain. This is especially hard to loosely couple these services with the application. The main reason many developers put these services on the App class is to ensure that those services are available through the lifetime of the application. In Silverlight 3, Microsoft has come up with another option: Application Services.

The idea of Application Services is pretty simple: any set of functionality that needs to have the same lifetime as the Application.  An Application Service is a class that supports the IApplicationService interface (and optionally IApplicationLifetimeAware). IApplicationService is simple:

public interface IApplicationService
{
  void StartService(ApplicationServiceContext context);
  void StopService();
}

The interface supports starting and stopping of the service (as well as sharing application startup initParams). I might have a Logger service that I want to use in my Silverlight app. If I implement the interface, I can then set up this service in the App.xaml file to start up with the applicaton using the Application.ApplicationLifetimeObjects element:

<Application xmlns="..."
             xmlns:x="..." 
             x:Class="..."
             xmlns:s="clr-namespace:MyAppService;assembly=MyAppService"
             >
  <Application.ApplicationLifetimeObjects>
    <s:Logger />
  </Application.ApplicationLifetimeObjects>
  ...
</Application>

The problem with this facility is that while the ApplicaitonLifetimeObjects is handling the lifetime for you, there is not a simple way to get the object. That's why Microsoft advises to create a static Current property like so:

public class Logger : IApplicationService, IApplicationLifetimeAware
{
  static Logger _current = null;

  public static Logger Current
  {
    get { return _current; }
  }

  void IApplicationService.StartService(
    ApplicationServiceContext context)
  {
    _current = this;  
  }

  void IApplicationService.StopService()
  {
    _current = null;
  }
...
}

In addition to the IApplicationService, another useful interface here is the IApplicationLifetimeAware interface. This interface gives you a bit more control in the starting and stopping of the service.  Here's the interface:

public interface IApplicationLifetimeAware
{
  void Starting();
  void Started();
  void Exiting();
  void Exited();
}

This interface simply allows you to handle the before and after states of Starting and Exiting the service.  This is useful when you need that extra level of granularity.

the Application Service model allows for better separation between lifetime management and services that you want to supply to your Silverlight application. Start using it and please pleave the App alone...please ;)

Here's a link to my simple (and somewhat contrived) example:

 http://wildermuth.com/downloads/FunWithAppServices.zip

 

Comments

Gravatar

Rodrigo Díaz Concha Tuesday, August 25, 2009

Nice example!

Gravatar

Rob Wednesday, August 26, 2009

The problem with this is that it is forcing additional responsibilities on the App which are not appropriate and it is doing a poor job of solving the real problems. I'm quite disappointed that Microsoft bloated Silverlight by adding this. The proper way to handle this scenario would be to use an IoC tool, bootstrapped during app startup.

Gravatar

Scott Densmore Wednesday, August 26, 2009

How would we test this application service? Should the practice be to have this as an abstract for some other object that does the functionality? It seems this could get complicated if we have dependencies since this is basically a singleton. Good stuff! Keep it up!


Leave a Comment

*
*
*