Showing posts with label Windows Phone 7. Show all posts
Showing posts with label Windows Phone 7. Show all posts

Tuesday, October 25, 2011

Chrysalis – Injection of Application Services and State

In my last post I introduced the concept of application and session state within a Windows Phone 7 application, and described how the Chrysalis framework makes it easy to share state between multiple pages (and hence view models) within an application, including full tombstoning support. As usual, all the source code is available on the Chrysalis CodePlex site under the “Source Code” tab.

Application Services

To recap, Chrysalis allows multiple view models to share the same state between multiple pages by using one of the two ChrysalisService.GetService methods,

   1: public class ChrysalisService
   2: {
   3:      ...
   4:  
   5:      public T GetService<T>() { ... }
   6:      public object GetService(Type serviceType) { ... }
   7:  
   8:      ...
   9: }

The first time one of these methods is called, a new instance of the specified type is created (calling the default parameter-less constructor). Any subsequent calls will return the same “singleton” instance. As the method names allude to, this can be used not only for general state, but for any services that may wish to be shared throughout the application.


Furthermore, Chrysalis makes it simple for these services to persist state when the application is tombstoned. All that is required is for the service to implement the IHasSessionState interface,



   1: public interface IHasSessionState
   2: {
   3:     // *** Methods ***
   4:  
   5:     void Initialize(object state);
   6:     object SaveState();
   7: }

The first time the service is created within a session the Initialize method is called with the state parameter set to null. In this instance default values can be set along with any other initialization required by the service. Upon tombstoning the SaveState method is called from which you can return any state you wish to persist. Upon reactivation this state is passed back to the newly created instance of the service (remember – during tombstoning the application process is killed and all objects are lost) via the Initialize method.


Chrysalis and Dependency Injection


Whilst the ChrysalisService class provides the GetService methods, this is only one way in which your view models can obtain such state information. Another method is “dependency injection”. This refers to a situation where external dependencies (in our case the state objects) are injected into our view model, rather than the view model itself having to seek them out.


In Chrysalis this is done by defining public properties for each of the services that we wish to inject into the view model. To indicate that these should be injected we add the [ChrysalisImport] attribute to the property. Finally, in the constructor we check whether Chrysalis is initialised and tell the ChrysalisService to satisfy any imports by calling the SatifyImports(…) method.


For example within the sample CalculatorViewModel included with the source download,



   1: public class CalculatorViewModel : ViewModelBase, IHasSessionState
   2: {
   3:     // *** Constructors ***
   4:  
   5:     public CalculatorViewModel()
   6:     {
   7:         if (ChrysalisService.Current != null)
   8:             ChrysalisService.Current.SatisfyImports(this);
   9:     }
  10:  
  11:     // *** Properties ***
  12:  
  13:     ...
  14:  
  15:     [ChrysalisImport]
  16:     public CalculatorSessionState SessionState
  17:     {
  18:         get;
  19:         set;
  20:     }
  21:  
  22:     ...
  23: }

This defines a property called SessionState that is marked with the [ChrysalisImport] attribute. In the constructor we notify Chrysalis that it should inject any dependencies, which when it returns will have set the property to an instance of CalculatorSessionState. As with the GetService calls this will return the same instance across all view models, creating a new object only if this is the first such reference. Note that you can define any number of properties to be injected and they will all be satisfied by the one SatisfyImports(…) call.


Using Interfaces for Dependency Injection


Whilst being able to declaratively inject singleton instances of classes is useful, there are a number of reasons that you would wish to decouple such properties from the concrete implementations – for example to inject mock implementations for testing purposes. This is usually done by specifying an interface rather than a class type, and this too is enabled in the Chrysalis framework.


For example in the ChoosersViewModel sample included in the source code,



   1: [ChrysalisImport]
   2: public IChooserExecutionService ChooserExecutionService
   3: {
   4:     get;
   5:     set;

6: }


However, we now need a way to link the interface to the concrete implementation. In the Chrysalis framework this is done by simply attributing the interface with the ExportImplementationAttribute specifying the concrete type to use.



   1: [ExportImplementationAttribute(typeof(ChooserExecutionService))]
   2: public interface IChooserExecutionService
   3: {
   4:     ...
   5: }

 


Comparing Chrysalis with Other Dependency Injection Frameworks


Before I conclude I would like to take a moment to contrast dependency injection in the Chrysalis framework to other implementations. Dependency injection within Chrysalis was designed to support the very basic injection of services (to enable unit testing, etc.) and integration with the rest of the Chrysalis model – this it performs well. If you require more advanced services then it is recommended that you use a full dependency injection container implementation.

Tuesday, December 14, 2010

Chrysalis – Application and Session State

In my last few posts I have focused on the tombstoning features of the Chrysalis Windows Phone 7 application framework. In this post I will look at the related role of application and session state, and how these can ensure that data is persisted during tombstoning using the Chrysalis framework. As usual, all the source code is available on the Chrysalis CodePlex site under the “Source Code” tab.

Application and Session State

All examples of state I have discussed so far have been associated with a single page of a Windows Phone 7 application (view state), ensuring that any data entered is persisted during navigation and application tombstoning. In real applications much of the data crosses across multiple pages, and hence multiple views and view models. Application data is data that stores settings and information that is reused between multiple application instances. This includes user settings, user details as well as any downloaded data that rarely changes. Session data on the other hand is data that crosses multiple pages of an application, but is not reused between application instances, such as session keys for web services or some transient state.

When, and how the data is different for each of these types of state,

  • View state – Persisted on navigation to/from the page to the page state bag.
  • Application state – Persisted and restored upon application shutdown/startup and also during tombstoning using isolated storage.
  • Session state – Persisted during tombstoning to the application state bag.

Storing Application and Session State with Chrysalis

When working with data that crosses several pages (and therefore view models) we need a way to ensure that we can store and access the same data from each page. In the ‘Calculator’ sample provided with Chrysalis, this data is stored in the CalculatorSessionState object,

   1: public class CalculatorSessionState
   2: {
   3:     // *** Properties ***
   4:  
   5:     public string Operator { get; set; }
   6:  
   7:     ...
   8: }

This simply stores the current operator (+, –, / or *) that the calculator is using as a string. This is also displayed on the Calculator information page, and is true session state in that navigation back from the calculator page, and then returning will persist the value chosen.


Since we need to access the state from both the CalculatorViewModel and the CalculatorInformationViewModel, we need to be able to create a single instance of this state to share across both of these locations. Chrysalis provides a simple and straightforward way of creating such “singleton” objects by calling one of the ChrysalisService.GetService methods,



   1: public class ChrysalisService
   2: {
   3:     ...
   4:  
   5:     public T GetService<T>() { ... }
   6:     public object GetService(Type serviceType) { ... }
   7:  
   8:     ...
   9: }

This method will return a single instance of the requested type, initializing a new instance if this is the first such request (note that this will call, and requires, a public parameter-less constructor). Now we can call this method in the constructors of the CalculatorViewModel and the CalculatorInformationViewModel and be sure that we have the same instance in each case.


Supporting Tombstoning


So far I have shown how to share state between pages, but what happens when the application is tombstoned (see here if you wish to refresh yourself on what this means)? Since the process is killed, any state will be lost. On restart we have an entirely new process so Chrysalis will create a new instance with default values.


To provide a seamless user experience, we should persist any session state and restore it when the application is reactivated. Chrysalis makes this easy. All you have to do is to ensure that your state object implements the IHasSessionState interface. For example, the full code for CalculatorSessionState is,



   1: public class CalculatorSessionState : IHasSessionState
   2: {
   3:     // *** Properties ***
   4:  
   5:     public string Operator { get; set; }
   6:  
   7:     // *** IHasSessionState Methods ***
   8:  
   9:     void IHasSessionState.Initialize(object state)
  10:     {
  11:         SessionState sessionState = state as SessionState;
  12:  
  13:         if (sessionState == null)
  14:             Operator = "+";
  15:         else
  16:             Operator = sessionState.Operator;
  17:     }
  18:  
  19:     object IHasSessionState.SaveState()
  20:     {
  21:         return new SessionState()
  22:             {
  23:                 Operator = this.Operator
  24:             };
  25:     }
  26:  
  27:     // *** Sub-classes ***
  28:  
  29:     public class SessionState
  30:     {
  31:         public string Operator { get; set; }
  32:     }
  33: }

Now when the class is first initialised, Chrysalis will call the IHasSessionState.Initialize method. If the application has just been launched the ‘state’ parameter will be null and we can initialise with default values. When the application is subsequently tombstoned Chrysalis will call the IHasSessionState.SaveState method, from which we can return some state to persist until later reactivated. When this does occur a new instance of CalculatorSessionState is created, but this time our previously returned state is supplied as the parameter which we can restore.


Summary


We have now seen how Chrysalis can easily allow you to share session state between pages. By using the Chrysalis tombstoning support on the view model and the IHasSessionState interface on any shared state, we should no longer worry about what will happen if our application is tombstoned. Chrysalis will ensure that any state is restored to that before we were tombstoned, and your users will have a seamless experience.


Once again, you can download a zip file of the entire source code for Chrysalis and the associated sample application from the “Source Code” tab at the Chrysalis CodePlex site.

Sunday, November 21, 2010

Chrysalis – Tombstoning support (Part II - Implementation Details)

In my last post I introduced the tombstoning features of the Chrysalis Windows Phone 7 application framework. To summarise, this allowed developers using the Model-View-ViewModel presentation pattern to easily ensure that their ViewModels could maintain their state during tombstoning. In this post I will provide an overview of how Chrysalis implements this feature. As usual, all the source code is available on the Chrysalis CodePlex site under the “Source Code” tab.

The Chrysalis Service

One of the first steps when using the Chrysalis framework is to register the ChrysalisService in the App.xaml file’s ApplicationLifetimeObjects section (see my last post for details). This takes advantage of Silverlight’s application extension services (see MSDN) which allow you to register services that run at start-up of the application. The advantage of this approach is that once registered, the rest of the application can take advantage of the features of ChrysalisService without having to use any custom base classes of pages, View Models, etc.

The bulk of the initialization of the ChrysalisService happens within the StartService method, which Siliverlight calls during application start-up.

   1: void IApplicationService.StartService(ApplicationServiceContext context)
   2: {
   3:     // Set this as the current ServiceManager via the static property
   4:  
   5:     ChrysalisService.Current = this;
   6:  
   7:     // Attach to the PhoneApplicationService lifetime events
   8:  
   9:     PhoneApplicationService phoneApplicationService = PhoneApplicationService.Current;
  10:  
  11:     phoneApplicationService.Activated += new EventHandler<ActivatedEventArgs>(PhoneApplicationService_Activated);
  12:     phoneApplicationService.Deactivated += new EventHandler<DeactivatedEventArgs>(PhoneApplicationService_Deactivated);
  13:     phoneApplicationService.Closing += new EventHandler<ClosingEventArgs>(PhoneApplicationService_Closing);
  14:  
  15:     // Attach to the page navigation events
  16:     // NB: We set off a DispatcherTimer since we need to wait for the RootVisual property to be set before we can access this
  17:  
  18:     ExecuteViaDispatcherTimer(() =>
  19:         {
  20:             if (Application.Current.RootVisual != null)
  21:                 PhoneApplicationFrame_RootVisualLoaded((PhoneApplicationFrame)Application.Current.RootVisual);
  22:         });
  23: }


Firstly we store a static reference to our service so that we can find it at any other point within the application execution. After this we get the current PhoneApplicationService (added by default to all Silverlight Windows Phone 7 applications). Since Silverlight will initialize all application services in the order we have specified in the App.xaml file, this will already have been initialized. We then attach to the Activated, Deactivated and Closing events. Note that we do not need to attach to the Launching event since we can identify this if our service has been initialized without the Activated event.


The next step is to attach to navigation events to and from pages within the application. Normally you would do this by using the NavigationService class accessible from the current page, but since at this point of application execution no page is present (and hence the application’s RootVisual property is null) we have no way to access this. The ChrysalisService class overcomes this problem by queuing a request using a DispatcherTimer with a delay of 0ms. Although this sounds like it should execute immediately, the contract for the DispatcherTimer merely states that it should call the callback at least the specified time after starting. In fact this is queued up when the dispatcher next becomes free, conveniently after the RootVisual has been initialized.



   1: private void PhoneApplicationFrame_RootVisualLoaded(PhoneApplicationFrame frame)
   2: {
   3:     // Attach to the navigation events
   4:  
   5:     frame.Navigating += new NavigatingCancelEventHandler(NavigationService_Navigating);
   6:     frame.Navigated += new NavigatedEventHandler(NavigationService_Navigated);
   7:  
   8:     // Set the current page
   9:  
  10:     CurrentPage = frame.Content as PhoneApplicationPage;
  11:  
  12:     ...
  13: }

We can then use the RootVisual (which we know for Windows Phone 7 Silverlight applications will be a PhoneApplicationFrame) to attach to the Navigating and Navigated events. We also store a reference to the current page for future use, which is also updated on any successful navigation events.


Notifying the ViewModel of application events


Now the ChrysalisService is able to identify all the application events of interest, we need a way to pass this to the current ViewModel. This is done via the two interfaces, IPhoneLifetimeAware and IPhoneNavigationAware.



   1: public interface IPhoneLifetimeAware
   2: {
   3:     void Activated();
   4:     void Closed();
   5:     void Deactivated();
   6:     void Launched();
   7: }



   1: public interface IPhoneNavigationAware
   2: {
   3:     void NavigatingFrom(NavigatingCancelEventArgs e);
   4:     void NavigatedTo(NavigationEventArgs e);
   5: }

Since we are tracking the current page at any point of time, we can identify the ViewModel associated with it by using the DataContext of that page. If the returned object implements either of the above interfaces then we can call the relevant methods in response to application events.


Storing application page state


We have not yet addressed the main use of this feature, for storing state relevant to the ViewModel during tombstoning. This is done via a third interface that the ViewModel can implement (as is done by the provided ViewModelBase class), IHasSessionState.



   1: public interface IHasSessionState
   2: {
   3:     void Initialize(object state);
   4:     object SaveState();
   5: }

 

The SaveState() method is called by ChrysalisService whenever the application is Deactivated or when navigation occurs away from the respective page. From this method the ViewModel can return some state that will be automatically persisted during tombstoning.

Similarly, the Initialize(…) method is called by ChrysalisService whenever the application is Activated or when navigation occurs to the respective page. The ViewModel can then reinstate any state required to recreate the page prior to tombstoning.


Summary


I have now described how the Chrysalis application framework allows developers to easily manage any state relating to individual ViewModels (and therefore to individual pages of an application). In my next post I will describe how Chrysalis allows applications to store application state that may span several pages, and how this can easily be persisted between tombstoning and application restarts as is required.