Alex van Beek

About Alex van Beek

I'm always keen to keep up with all the new and fancy technologies and I enjoy teaching those technologies to other people. I'm currently specialized in .Net, Flex, (enterprise) Silverlight and mobile development: Android and Windows Phone

Silverlight: Navigation Framework tip: using the XAML escape sequence

With all the Windows 8/Metro/WinRT hype on the internet today, I decided it was time for a quick tip concerning the XAML escape sequence and the good old navigation framework present in Silverlight 4 and Silverlight 5. I only learned about the XAML escape sequence until recently and I can image that there quite a number of people out there that are still unfamiliar with it. The nice thing is that you can also use the XAML escape sequence in WPF, Windows Phone and WinRT, if you like to do so. Continue reading

The C# using statement and suppressed exceptions compared to Java 7 try…with

Yesterday Java SE 7 was released. Last night I had the opportunity to play with some of it’s new features, including Java 7’s new “resource management” syntax. Of course, we have had this feature in C# for quite some time, but I was actually curious to see whether the Java people learned from the C# implementation and thus implemented it in a better way. Much to my surprise ;) , they did. Let me elaborate……

The example

Take a look at the following C# class:

   1:    class MyResource : IDisposable

   2:    {

   3:  

   4:        public void DoWork()

   5:        {

   6:            Console.WriteLine("Working!!!!!!!!");

   7:            throw new ArgumentException("A");

   8:        }

   9:  

  10:  

  11:        public void Dispose()

  12:        {

  13:            throw new ArgumentException("B");

  14:        }

  15:    }

It’s a class that implements IDisposable (in Java 7 it’s called AutoClosable) so it can be used with C#’s using statement. Now imagine that we create a method “CallDoWork”, which wraps a call to DoWork in a using block. This “CallDoWork” method is called by an external caller. Can you guess what happens when the CallDoWork method is called? Will the caller get the “A” exception from the DoWork method or the “B” exception from the call to the Dispose method? Take a look at the following program:

   1:   class Program

   2:   {

   3:       static void Main(string[] args)

   4:       {

   5:  

   6:           try

   7:           {

   8:               CallDoWork();

   9:           }

  10:           catch (Exception ex)

  11:           {

  12:               Console.WriteLine(ex.Message);

  13:           }

  14:           Console.ReadKey();

  15:       }

  16:  

  17:  

  18:       private static void CallDoWork()

  19:       {

  20:           using (MyResource r = new MyResource())

  21:           {

  22:               r.DoWork();

  23:           }

  24:       }

  25:   }

 So the question actually is, “What will be the output of this program? A or B?” Well here it is:

image

This means that that exception A has just disappeared, which could be a problem, since most exceptions should be logged somewhere. Let’s change the CallDoWorkMethod in a way that an exception from the DoWork method is logged and an exception from the Dispose method is also logged:

   1:        private static void CallDoWork()

   2:        {

   3:            try

   4:            {

   5:                using (MyResource r = new MyResource())

   6:                {

   7:                    try

   8:                    {

   9:                        r.DoWork();

  10:                    }

  11:                    catch (Exception ex)

  12:                    {

  13:                        Console.WriteLine(ex.Message);

  14:                    }

  15:                }

  16:            }

  17:            catch (Exception ex)

  18:            {

  19:                Console.WriteLine(ex.Message);

  20:            }

  21:        }

So how does the using block look now? Not quite as small right? Don’t worry, the alternative without a using statement is still worse:

   1:          MyResource r = null;

   2:          try

   3:          {

   4:              r = new MyResource();

   5:              r.DoWork();

   6:          }

   7:          catch (Exception ex)

   8:          {

   9:              Console.WriteLine(ex.Message);

  10:          }

  11:          finally

  12:          {

  13:              if (r != null)

  14:              {

  15:                  try

  16:                  {

  17:                      r.Dispose();

  18:                  }

  19:                  catch (Exception ex)

  20:                  {

  21:                      Console.WriteLine(ex.Message);

  22:                  }

  23:              }

  24:          }

Note that I haven’t even added code to wrap the exceptions and rethrow them. Also note that this isn’t a problem that’s purely theoretical. Take a look at the following code snippet:

   1: class Program

   2: {

   3:     static void Main(string[] args)

   4:     {

   5:         try

   6:         {

   7:             CallService();

   8:             Console.WriteLine("Service call succeeded!");

   9:         }

  10:         catch (Exception ex)

  11:         {

  12:             Console.WriteLine("Unexpected error occured: " + ex.Message);

  13:         }

  14:         Console.ReadKey();

  15:     }

  16:  

  17:  

  18:     private static void CallService()

  19:     {

  20:         using (HelloServiceClient client = new HelloServiceClient())

  21:         {

  22:             client.DoWork();

  23:         }

  24:     }

  25: }

The code in the main method calls CallService defined on line 18. This methods wraps a call to a WCF Service in a using block. This WCF Service uses a wsHttpBinding. Now take a look at the output if the service is down:

image

This is NOT the error message from the call to the proxy, but it’s an error message from an exception that get’s thrown because the Dispose method was called while the channel was in the “Faulted” state. Now I know that in WCF you should check before you dispose and that you shouldn’t use proxies in a using statement, but I wanted you to show that there are framework Dispose methods that actually throw exceptions. Next to that, you might never know for certain whether a third party component throws an exception in a Dispose method. In a real life application you’ll probably don’t sprinkle exception handling code like the above throughout your application, you’ll probable create some generic solution or handle exceptions in a certain layer of your application. I just want to make you aware that a using statement can suppress an exception and that this exception might never reach your exception handling solution or your exception handling layer.

The Java way and the new Try…With syntax

As I previously stated, the guys at Oracle have learned from the using statement in C# and implemented a nice solution:

   1: public class TryWithRes 

   2: {    

   3:     public static void main(String[] args) 

   4:     {        

   5:         try(NewResource res = new NewResource("Res1 closing"))

   6:         {

   7:             res.doWork();

   8:         } 

   9:         catch(Exception e)

  10:         {

  11:             System.out.println("Exception thrown by doWork()" + e);

  12:             if(e.getSuppressed() != null)

  13:             {                

  14:                 for(Throwable t : e.getSuppressed())

  15:                 {                    

  16:                     System.out.println("Exception thrown by close(): " + t);                

  17:                 }            

  18:             }        

  19:         }     

  20:     }

  21: }

I have formatted the code in a C# way so all you C# guys can follow along ;) . Instead of the “using” keyword, Java 7 uses the try keyword on line 5. I’ve seen some people on the internet complaining about the “try” on line 5 instead of a new keyword, but because of the try keyword, the catch on line 9 feels very natural to me. Java 7 also shows different behavior, the exception that get’s caught on line 9 isn’t the exception that get’s thrown by the close() method of NewResource, like it would be the case when you surrounded a using block in C# with try..catch, but it’s the exception from doWork(). Next to that, the Exception class was expanded with a new “getSuppressed()” method (shown on lines 12 and 14), which you can use to get the exception from the close method. Technically, I didn’t need a foreach loop on line 14, this would be needed if I nested multiple try…with statements, but I just wanted to show that getSuppressed() returns a collection.

You don’t have to provide a catch when using the new try…with syntax, so now you can create a generic exception handling solution or layer and you can log all the exceptions thanks to the new getSuppressed() method, without losing any of them and while still using automatic resource management. If you want to know more about the new Java 7 try…with syntax, you can find an excellent article on the Oracle website here.

Conclusion

I have to say, I really like the new try…with syntax and also how suppressed exceptions are dealt with. The big difference between “using” and “try…with” is obviously that “using” in C# generates a “try…finally” in IL, while “try…with” in Java generates a “try…catch…finally” in bytecode. The “catch” stores the primary exception and when the “finally” executes and an exception is thrown, this exception is added to the primary stored exception using the new “addSuppressed()” method. After this, the stored primary exception which holds the suppressed exception, is thrown from the finally block.

I think this a perfect example of how .Net and Java drive each other to get better and I can only congratulate Oracle and the Java community on a great Java 7 SE release!

Windows Phone 7.1: WCF Data Services and tomb stoning

In Windows Phone 7 there was support for using WCF Data Services, but this support was somewhat limited. For example, using the LINQ syntax wasn’t supported, so we had to create our uri’s ourselves. Next to that, we had to generate our classes manually, using the command line and DataSvcUtil.exe. In Windows Phone 7.1 things  have changed. We can now use LINQ syntax to create our uri’s and we have support for”Add service reference” in Visual Studio 2010. This article will show how to get started with WCF Data Services and Windows Phone 7.1, which is important as it will be the primary way to access your data from a Windows Phone application.

The Server

In order to get started with WCF Data Services and Windows Phone 7.1, we’ll need to create a WCF Data Service. Here is an overview of my web project, which is hosted in the same solution as my Windows Phone 7.1 application:

image

This isn’t that exciting. I started out with an empty ASP.NET web project and added an entity data model to it (the .edmx file). I only selected the Product table from the Adventureworks database. After adding the .edmx file, I added a new WCF Data Service to it. Here is the code in the .svc file:

   1: using System.Data.Services;

   2: using System.Data.Services.Common;

   3:  

   4: namespace ProductServiceHost

   5: {

   6:     public class ProductService : DataService<AdventureWorks2008Entities>

   7:     {

   8:         public static void InitializeService(DataServiceConfiguration config)

   9:         {

  10:             config.SetEntitySetAccessRule("Product", EntitySetRights.All);

  11:             config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;

  12:         }

  13:     }

  14: }

As you can see, it’s a normal WCF Data Service which uses my AdventureWorks2008Entities ObjectContext. I won’t go into detail about WCF Data Services at the server, since there isn’t any difference at the server for a Windows Phone client. Just a remark on the side, you have to love the little amount of effort it takes to create a WCF Data Service!

The Windows Phone client

Let’s first take a look at the client application:

image

As you can see, the client simply shows the products in a listbox. Beneath the listbox there are buttons to perform CUD functionality. If the user selects a product and presses “View”, the UI changes and a few properties can be edited:

image

When the user presses the save button in the top screen, all the changes (inserts, deletes and updates) will be submitted to the WCF Data Service shown earlier.

Loading data

The first thing to do is to use the new “Add Service reference feature” in Visual Studio 2010:

image

This will generate our client classes. Now you might think that if you’ve already used the OData client library in the full .Net framework you know what’s coming. This is partially true. The OData client library for Windows Phone uses a somewhat easier programming model. Let’s take a look at where the data is loaded:

   1: // Constructor

   2:     public MainPage()

   3:     {

   4:         InitializeComponent();

   5:         _context = new AdventureWorks2008Entities(new Uri("http://localhost:49753/ProductService.svc/", UriKind.Absolute));

   6:         _products = new DataServiceCollection<Product>(_context);

   7:         _context.SaveChangesDefaultOptions = SaveChangesOptions.Batch;

   8:         _newInstance = true;

   9:     }

  10:  

  11:     protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)

  12:     {

  13:         base.OnNavigatedTo(e);

  14:  

  15:         if (_newInstance)

  16:         {

  17:             if (State.ContainsKey("productService"))

  18:             {

  19:                 // need to restore the state.....

  20:                 string stateString = (string)State["productService"];

  21:                 DataServiceState state = DataServiceState.Deserialize(stateString);

  22:                 _context = (AdventureWorks2008Entities)state.Context;

  23:                 _products = (DataServiceCollection<Product>)state.RootCollections["products"];

  24:                 _lbxProducts.ItemsSource = _products;

  25:             }

  26:             else

  27:             {

  28:                 //A new instance with no state saved, load new data....

  29:                 DataServiceQuery<Product> products = (DataServiceQuery<Product>)

  30:                     from p in _context.Product

  31:                     where p.ListPrice < 500

  32:                     select p;

  33:                 Debug.WriteLine("Products uri: " + products.RequestUri);

  34:                 _products.LoadCompleted += new EventHandler<LoadCompletedEventArgs>(HandleProductsLoaded);

  35:                 _products.LoadAsync(products);

  36:             }

  37:         }

  38:         _newInstance = false;

  39:     }

  40:  

  41:     protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)

  42:     {

  43:         base.OnNavigatedFrom(e);

  44:         if (e.NavigationMode != NavigationMode.Back)

  45:         {

  46:             Dictionary<string, object> collections = new Dictionary<string, object>(1);

  47:             collections["products"] = _products;

  48:             try

  49:             {

  50:                 string state = DataServiceState.Serialize(_context, collections);

  51:                 State["productService"] = state;

  52:             }

  53:             catch (SerializationException ex)

  54:             {

  55:                 Debug.WriteLine("Serialization exception: " + ex.Message);

  56:             }

  57:         }

  58:     }

Don’t worry to much about the if statements and the restoring state parts. Let’s start at 5- 7. At line 5 I create a new DataServiceContext class, which was generated when I added the service reference. This class is the so called spider in the web when you use the WCF Data Service client library. It’s comparable to the ObjectContext class if you’re familiar with the Entity Framework. It contains a DataServiceQuery<Product>  object, comparable to an EntitySet of the Entity Framework. You can use this to query the products. Next to query objects for all the EntitySets you expose at the server, the DataServiceContext also contains methods to add, remove and update objects.

Now you might think that you would use the add, remove and update methods on the DataServiceContext to perform modifications and this is possible, but it’s more common the use a DataServiceCollection<> to perform modifications. This DataServiceCollection is instantiated on line 6, and the DataServiceContext is passed in, in it’s constructor.

Let’s skip a few lines to lines 29-35. Line 29 is very interesting. You can see that I use a LINQ query on the Product property of the DataServiceContext. You can always cast this result back to a DataServiceQuery object, which is very useful for debugging. Line 29 is a huge win for Windows Phone 7.1. Constructing a LINQ query that was not executed, but parsed into an expression tree and translated to something else, wasn’t possible in Windows Phone 7. As you might know, this LINQ query is translated to an uri to which a GET request is sent by the DataServiceContext. Because all the information of my query is contained in the uri, this means that the query is handed to my WCF Data Service, which reconstructs it and sends it to the Entity Framework. This means that my data is filtered in the database, while I create a simple LINQ query on the client. This still amazes me :) .

You can see the Debug.WriteLine statement on line 33, this is it’s output:

Products uri: http://localhost:49753/ProductService.svc/Product()?$filter=ListPrice lt 500M

After constructing the LINQ query, the DataServiceCollection comes into play. The idea is that you supply a query to it’s LoadAsync() method. The collection executes the query and fires the LoadCompleted event when finished. All of this is happening on lines 34-35. The entities that are the result of the query are added to the collection. This collection implements INotifyCollectionChanged, so it can be used for data binding. Using this collection has a couple of advantages over using the DataServiceContext directly:

  • Change Tracking for updates: The DataServiceContext doesn’t do any change tracking and you have to use the UpdateObject() method to indicate that an object is modified. If you use the DataServiceCollection, the collection is responsible for tracking all the objects that it contains. Because the collection also has a reference to the DataServiceContext, it notifies the DataServiceContext of all changes to the collection and the entities in the collection. This means that you can just add,remove and update objects in the collection and when you want to persist the changes you call SaveChanges() on the DataServiceContext.
  • UI Thread marshalling. The DataServiceContext doesn’t do any UI Thread marshalling. The DataServiceCollection does, this means that the LoadCompleted event fires on the UI thread and I can just assign the collection to the ItemsSource property of my listbox.
  • Easier handling for paging: If you’ve worked with the OData Client library in the full .Net framework you know that when a query is paged on the server, it’s a bit of a pain to get all the pages. This becomes easy with the DataServiceCollection class in Windows Phone thanks to it’s LoadNextPartialSetAsync() method, which adds the next page of entities to the collection.

CUD

As you might have guessed, CUD functionality becomes very simple thanks to the DataServiceCollection, as I can just work with it like with any normal collection. This the handler for the add button:

   1: private void HandleAddProduct(object sender, RoutedEventArgs e)

   2:       {

   3:           Product p = new Product()

   4:           {

   5:               Name = "Change this!" + new Random().Next(),

   6:               ProductNumber = new Random().Next().ToString(),

   7:               ModifiedDate = DateTime.Now,

   8:               SellEndDate = DateTime.Now,

   9:               SellStartDate = DateTime.Now,

  10:               ReorderPoint = 1,

  11:               SafetyStockLevel = 1,

  12:               rowguid = Guid.NewGuid()

  13:           };

  14:  

  15:           _products.Add(p);

  16:           _lbxProducts.SelectedItem = p;

  17:       }

I just set some default values because they are mandatory in the Adventureworks database. On line 15 I add the new product to the DataServiceCollection.

This is the handler for the Delete button:

   1: private void HandleRemoveProduct(object sender, RoutedEventArgs e)

   2:       {

   3:           _products.Remove((Product)_lbxProducts.SelectedItem);

   4:       }

This doesn’t need a lot of explanation. Finally the handler for the save button:

   1: private void HandleSaveProduct(object sender, RoutedEventArgs e)

   2:     {

   3:         _context.BeginSaveChanges(HandleSaveChanges, null);

   4:     }

   5:  

   6:     private void HandleSaveChanges(IAsyncResult result)

   7:     {

   8:         Dispatcher.BeginInvoke(() =>

   9:         HandleSaveChangesForUiThread(result));

  10:  

  11:  

  12:     }

  13:  

  14:     private void HandleSaveChangesForUiThread(IAsyncResult result)

  15:     {

  16:         try

  17:         {

  18:             _context.EndSaveChanges(result);

  19:             MessageBox.Show("Save completed!");

  20:  

  21:         }

  22:         catch (DataServiceRequestException ex)

  23:         {

  24:             DataServiceResponse response = ex.Response;

  25:             ChangeOperationResponse singleResponse = (ChangeOperationResponse)response.SingleOrDefault((co) => co.Error != null);

  26:             if (singleResponse != null)

  27:             {

  28:                 MessageBox.Show("Error: " + singleResponse.Error.Message + ", for product: " + ((Product)((EntityDescriptor)singleResponse.Descriptor).Entity).Name + ", all changes were rolled back at the server");

  29:             }

  30:             else

  31:             {

  32:                 MessageBox.Show("Unknown error: " + ex.Message);

  33:             }

  34:         }

  35:     }

Line 1 is the actual handler for the save button. In this method I call the BeginSaveChanges() method of the DataServiceContext and pass a callback to it. This callback is defined on line 6. These methods follow the normal ASync pattern of the .Net framework. There is one catch… As you’ll probably know, I should call the EndSaveChanges() method in the callback. But the call to EndSaveChanges() and the code after it should run on the UI thread. This is important because if EndSaveChanges() isn’t called on the UI thread you’ll get an exception. This is because the DataServiceContext receives generated values from the server when EndSaveChanges is called (like a generated id) and set’s them on the Product entity that was saved. This will fire the INotifyPropertyChanged event of an entity which will in turn update the UI, which should of course happen on the UI thread. An entity which is generated by the OData client library doesn’t fire INotifyPopertyChanged on the UI Thread! That’s why I call the Dispatcher.BeginInvoke() method on line 8. The method that’s passed in is defined on lines 14-34. I call the EndSaveChanges() on line 18. The rest of the method is pretty much standard WCF DataServices error handling.

Tombstoning

Of course it would be a pity if the user of our nifty application added all those new cool products, changed the price of a couple of others, then the user takes an incoming phone call and our application can be tomstoned, which would delete all the changes the user has made. Luckily, the OData Client Library for Windows Phone has a special api to handle tombstoning. This api can save all our state, including loaded entities and pending changes. This means that the user can just continue with his work when the call has ended. Let’s take a look at the overridden OnNavigatedFrom method, which is also called when the application is tombstoned:

   1: protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)

   2:        {

   3:            base.OnNavigatedFrom(e);

   4:            if (e.NavigationMode != NavigationMode.Back)

   5:            {

   6:                Dictionary<string, object> collections = new Dictionary<string, object>(1);

   7:                collections["products"] = _products;

   8:                try

   9:                {

  10:                    string state = DataServiceState.Serialize(_context, collections);

  11:                    State["productService"] = state;

  12:                }

  13:                catch (SerializationException ex)

  14:                {

  15:                    Debug.WriteLine("Serialization exception: " + ex.Message);

  16:                }

  17:            }

  18:        }

At line 5 I check with the new Windows Phone 7.1 api whether it’s a backwards navigation. If it is, I don’t have to save any state, since this means that either the page is closed and removed from the backstack or the entire application is closed. Either way, the user will expect new fresh data when this page is visited again. If it isn’t, I must prepare for tombstoning. This is what’s happening:

  • Line 6: I Instantiate a dictionary, which holds all the DataServiceCollection objects I want to preserve. I add my DataServiceCollection to this on line 7.
  • Line8: I use the static Serialize method of the DataServiceState class to turn all the tracking information in the context and all the loaded entities in my collection into a string.
  • Line 10: I add this string with all the needed information to the State dictionary of the current page. This means that this string is preserved when the application is tombstoned.
  • Line 13: I needed this catch because of a bug in this beta. It turns out that if BeginSaveChanges() caused an exception (example: Network is not available), that even when this exception is correctly handled, the DataServiceContext can’t be serialized anymore. I do hope that this bug get’s fixed in the final release.

Next up is the OnNavigatedTo method, which is also called when my application is restored after tombstoning. Here it is:

   1: protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)

   2:       {

   3:           base.OnNavigatedTo(e);

   4:  

   5:           if (_newInstance)

   6:           {

   7:               if (State.ContainsKey("productService"))

   8:               {

   9:                   // need to restore the state.....

  10:                   string stateString = (string)State["productService"];

  11:                   DataServiceState state = DataServiceState.Deserialize(stateString);

  12:                   _context = (AdventureWorks2008Entities)state.Context;

  13:                   _products = (DataServiceCollection<Product>)state.RootCollections["products"];

  14:                   _lbxProducts.ItemsSource = _products;

  15:               }

  16:               else

  17:               {

  18:                   //A new instance with no state saved, load new data....

  19:                   DataServiceQuery<Product> products = (DataServiceQuery<Product>)

  20:                       from p in _context.Product

  21:                       where p.ListPrice < 500

  22:                       select p;

  23:                   Debug.WriteLine("Products uri: " + products.RequestUri);

  24:                   _products.LoadCompleted += new EventHandler<LoadCompletedEventArgs>(HandleProductsLoaded);

  25:                   _products.LoadAsync(products);

  26:               }

  27:           }

  28:           _newInstance = false;

  29:       }

On line 5 I check whether the constructor is called. This is necesary because an application doesn’t always become tombstoned after it has been deactivated. It can remain in memory the same as it was left behind if the resources of the device allow it. This is called “Fast App Switching”. If this happens, the OnNavigatedTo fires if the user returns to the application, but the constructor doesn’t fire. So if fast app switching took place, you don’t have to restore your state. By the way, fast app switching is the default in the windows phone emulator when you press it’s Windows button. You can change this on the project properties if you want to test tombstoning:

image

On line 7 I check if the state was previously saved. This is necesary because OnNavigatedTo of course also fires when the application starts normally. If the state exists I retrieve the string on line 10 from the State dictionary. On line 11 I turn this string into a DataServiceState object by using the static DataServiceState.DeSerialize() method. This DataServiceState object has two properties:

  • Context, which contains the DataServiceContext with all the tracking information I serialized earlier.
  • RootCollections, this is the dictionary which holds all the DataServiceCollection objects I serialized earlier. I retrieve my “products” DataServiceCollection on line 13.

On line 14 I assign the restored DataServiceCollection to the ItemsSource property of my listbox and with this all state has been restored.

Conclusion

In my opinion the OData Client Library for Windows Phone and WCF Data Services will be the primary way of interacting with your data from your Windows Phone application. This will be the case because the library is the only client technology which supports change tracking in a Windows Phone application and strongly typed LINQ queries which are actually executed on the server. This will be the case at least until WCF RIA Services is supported.

While the api is a little rough around the edges:

  • INotifyPropertyChanged isn’t fired on the UI Thread (which isn’t necessarily a bad thing).
  • SerializationException occurs when saving state after an exception has been handled.

I’m sure these issues will be solved before the final release. The library is very stable and I encourage you to dig in, because it’s definitely the easiest and fastest way to create CRUD functionality for your Windows Phone 7.1 applications. You can find the example project here.

Multi tasking in Windows Phone 7.1

One of the coolest features in Windows Phone 7.1 is the new multi tasking feature (next to the new LINQ to SQL support of course). In this article I’ll show you how this works.

Background

It is important to understand how multi tasking in Windows Phone 7.1 is implemented. I first thought that I could have some kind of background service running, comparable to a background service in Windows. Well, this isn’t the case. Multi tasking in Windows Phone 7.1 is so called “Scheduled Multi Tasking”. This means that I can define a piece of code (we’ll get to this later) and the operating system is then responsible for scheduling this piece of code. How often and when this piece of code is run is dependant on multiple factors:

  • The kind of code to run.
  • The state of the device.
  • Available resources.
  • And so on.

Depending on the factors outlined above, Windows Phone 7.1 will run your piece of code or not. This means for certain pieces of code, that they may never be run. Windows Phone 7.1 supports two kinds of code that you can schedule to run in the background, these two kinds of code are represented by the following classes:

  • PeriodicTask
  • ResourceIntensiveTask

Depending on the type of task you choose, the schedule and the constraints that the tasks must adhere to, differ. These are the constraints for a PeriodicTask:

  • MemoryCap: 5MB.
  • Scheduled Interval: 30 minutes, but the execution time can drift by 10 minutes.
  • Scheduled Duration: 15 seconds.
  • Battery Save Mode can prevent execution.
  • There is a limit per device how many PeriodicTasks can be scheduled. This can be as low as six.

These are the constraints for a so called ResourceIntensiveTask:

  • MemoryCap: 5MB.
  • Scheduled Interval: Uncertain: A ResourceIntensiveTask will run when the phone meets the following conditions:
    • It’s connected to an external power source.
    • The battery is charged over 90%.
    • It has a WIFI connection or it’s connected through a PC.
    • The device screen is locked.
    • There is no active phone call.
  • Scheduled Duration: 10 minutes (If a RecourseInsensiveTask is run and the conditions of the devices change in a way that the ResourceIntensiveTask shouldn’t have been run, it’s terminated immediately).

You can see by looking at the constraints above that there is no guarantee that a ResourceIntensiveTask will be run at all. The idea is that you use the PeriodicTask to do small updates, refresh an RSS feed for example. A typical scenario for a ResourceIntensiveTask would be an occasionally connected application, which stores data locally (perhaps in the new local database feature). If all the above conditions are met, the data could be synchronized with the server.

Next to the constraints above, there are a couple of common constraints:

  • Each scheduled task will stop being scheduled after two weeks from the time it was first scheduled by using the Add() (later) method. Every time your main application is run, it can change this date to two weeks from the current time.
  • Scheduled tasks can’t use the API’s listed on the following page: http://msdn.microsoft.com/en-us/library/hh202962(v=VS.92).aspx.
  • Each application can schedule at most one PeriodicTask AND one ResourceIntensiveTask.
  • Tasks can only be scheduled the first time after a user initiated action from your main application. So you can’t make an application which schedules a background task as soon as it is installed.

Scheduling a task

Let’s take a look at the code needed to schedule a background task. The sample application contains one button. When this button is clicked it will schedule or prolong the already scheduled task. Here is the code behind:

   1: using System;

   2: using System.IO.IsolatedStorage;

   3: using System.Windows;

   4: using Microsoft.Phone.Controls;

   5: using Microsoft.Phone.Scheduler;

   6:  

   7: namespace MainApplication

   8: {

   9:     public partial class MainPage : PhoneApplicationPage

  10:     {

  11:         public MainPage()

  12:         {

  13:             InitializeComponent();

  14:         }

  15:  

  16:         protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)

  17:         {

  18:             base.OnNavigatedTo(e);

  19:             string minutes;

  20:             if (NavigationContext.QueryString.TryGetValue("minutes", out minutes))

  21:             {

  22:                 MessageBox.Show("The application was started by clicking a toast: " + minutes);

  23:             }

  24:         }

  25:  

  26:         private void HandleButtonClick(object sender, RoutedEventArgs e)

  27:         {

  28:             PeriodicTask myFirstTask;

  29:             myFirstTask = (PeriodicTask)ScheduledActionService.Find("MyFirstTask");

  30:             if (myFirstTask == null)

  31:             {

  32:                 //The first time this application is run....

  33:                 myFirstTask = new PeriodicTask("MyFirstTask");

  34:                 myFirstTask.Description = "Updates the tile with the current minutes and shows a toast";

  35:             }

  36:             else

  37:             {

  38:                 if (!myFirstTask.IsScheduled)

  39:                 {

  40:                     string lastResult;

  41:                     if (IsolatedStorageSettings.ApplicationSettings.TryGetValue<string>("taskResult", out lastResult))

  42:                     {

  43:                         if (lastResult == "Succes")

  44:                         {

  45:                             //User must have disabled it.

  46:                             MessageBox.Show("Please enable the background task in the settings menu and run this app again");

  47:                             ScheduledActionService.Remove(myFirstTask.Name);

  48:                             return;

  49:                         }

  50:                         else if (lastResult == "Faillure")

  51:                         {

  52:                             //Inspect isolated storage for more information and take appropriate action

  53:                         }

  54:                     }

  55:                 }

  56:                 ScheduledActionService.Remove(myFirstTask.Name);

  57:             }

  58:  

  59:             //Prolong the task or schedule a new one:

  60:             myFirstTask.ExpirationTime = DateTime.Now.AddDays(14);

  61:             try

  62:             {

  63:                 ScheduledActionService.Add(myFirstTask);

  64:             }

  65:             catch (InvalidOperationException)

  66:             {

  67:                 MessageBox.Show("Maximum amount of background tasks for your device might have been reached." +

  68:                     " Disable some tasks or enable this task on the settings menu and run this app again.");

  69:             }

  70:             catch (SchedulerServiceException)

  71:             {

  72:                 MessageBox.Show("Something really bad happened. an unexpected error has occurred.");

  73:             }

  74:  

  75:         }

  76:     }

  77:  

  78: }

The most interesting part begins on line 29. When the button is clicked I first check whether the task already is scheduled. This is necessary because an application can only schedule one PeriodicTask. On line 33, if the task doesn’t exist, I create it. Setting the description on line 34 is mandatory for a PeriodicTask. This is the description the user sees when he views all the scheduled background tasks through the settings menu. If it does exist, I check whether the task is still being scheduled on line 38. A scheduled task can become unscheduled because of two reasons:

  • The task called the Abort() method, to indicate something went wrong.
  • The user disabled the background task through the settings menu. If this is the case, the user can only allow the application to restart it’s tasks when the application is launched. The user can’t enable a disabled background task from the settings menu.

As we’ll see later, the only way you can find out what has happened is through IsolatedStorage. My task writes a result to IsolatedStorage (“Success” or “Faillure”). If the last result is “Success”” and the task isn’t scheduled, it must mean that the user has disabled it. If this is the case, I notify the user and remove the task on line 47 so that it can be restarted. I would really have liked a property on the PeriodicTask class, which I can use to determine the reason a task isn’t scheduled anymore. Next to that, a way to find out if the task has been enabled again by the user, is also very welcome.

If the last result is “Faillure” or the task is still scheduled, I remove the task on line 56 (more about why I remove the task while it’s still scheduled in a moment). You can of course log error details to IsolatedStorage from your task and inspect them here. After the inspection has been done, I let the method continue. The code from line 60 will be executed whether a new task has been created or an existing task has been found (which has or hasn’t been aborted). On line 60 I set the ExpirationTime to two weeks from now, this is the maximum. This also means that an existing task is prolonged. You can’t just change the ExpirationTime for an already scheduled task, this is why I removed it on 56. Finally, on line 63 I submit my task to the ScheduledActionService through the add method. This will make sure that the task is scheduled. You have to catch the InvalidOperationException on line 65. This will occur when the maximum amount of background tasks has been reached for a device or when the user disabled the background task for this application. The SchedulerServiceException on line 70 must also be caught, as this means a serious internal error.

Note that to create a ResourceIntensiveTask, I only have to replace “PeriodicTask” in the code above with “ResourceIntensiveTask”. The configuration of the task is completely the same. 

The SchedulerAgent

By now you, the well respected reader must have noticed something obvious…… I still haven’t shown you the code that actually get’s executed when the task is run by the operating system. This is because that code is is contained in a whole different Visual Studio project. You add this project by using the new “Windows Phone Task Scheduler Agent” project template:

image

You should add this project to the same solution as the main project and immediately add a reference from the main project to this project. After you created this project, it already contains one class. This class will contain the code that will be run by the operating system:

   1: using System;

   2: using System.IO.IsolatedStorage;

   3: using System.Linq;

   4: using Microsoft.Phone.Scheduler;

   5: using Microsoft.Phone.Shell;

   6:  

   7: namespace MyFirstAgent

   8: {

   9:     public class TaskScheduler : ScheduledTaskAgent

  10:     {

  11:  

  12:         /// <summary>

  13:         /// Agent that runs a scheduled task

  14:         /// </summary>

  15:         /// <param name="task">

  16:         /// The invoked task

  17:         /// </param>

  18:         /// <remarks>

  19:         /// This method is called when a periodic or resource intensive task is invoked

  20:         /// </remarks>

  21:         protected override void OnInvoke(ScheduledTask task)

  22:         {

  23:  

  24:             try

  25:             {

  26:                 ShellTile mainTile = ShellTile.ActiveTiles.First();

  27:                 //Tile has been pinned. First tile is always the main tile

  28:                 StandardTileData data = new StandardTileData();

  29:                 data.Count = DateTime.Now.Minute;

  30:                 data.Title = "Periodic";

  31:                 data.BackTitle = "Periodic back";

  32:                 mainTile.Update(data);

  33:  

  34:                 ShellToast toast = new ShellToast();

  35:                 toast.Title = "Info";

  36:                 toast.Content = "Tile was modified! Tap here to open the app.";

  37:                 toast.NavigationUri = new Uri("/MainPage.xaml?minutes=" + data.Count, UriKind.Relative);

  38:                 toast.Show();

  39:  

  40:                 IsolatedStorageSettings.ApplicationSettings["taskResult"] = "Succes";

  41:                 NotifyComplete();

  42:             }

  43:             catch (Exception)

  44:             {

  45:                 //Unschedule this task....

  46:                 Abort();

  47:                 IsolatedStorageSettings.ApplicationSettings["taskResult"] = "Faillure";

  48:             }

  49:             finally

  50:             {

  51:                 IsolatedStorageSettings.ApplicationSettings.Save();

  52:             }

  53:         }

  54:  

  55:         /// <summary>

  56:         /// Called when the agent request is getting cancelled

  57:         /// </summary>

  58:         protected override void OnCancel()

  59:         {

  60:             base.OnCancel();

  61:  

  62:  

  63:         }

  64:     }

  65: }

The most interesting method is the one on line 21. It’s the OnInvoke  method. This method is called by the OS every time your task is run. The only argument is a ScheduledTask. This argument contains the PeriodicTask object I scheduled in the main application. You really only need this argument if your application schedules both a PeriodicTask and a ResourceIntensiveTask, since then you’ll need an “if(task is PeriodicTask)” statement to determine what code should be executed. In this method I use a couple of new API’s in Windows Phone 7.1:

  • Line 26: I retrieve the main application tile. The first one is always the main tile, even if the application is not pinned, you can still update it and the user will see the update as soon as he pins the application.
  • Line 28: I update the BackTitle. This also new in Windows Phone 7.1. Tiles have a back, and as soon as you update it, Windows Phone will flip the tile in the home screen periodically to show the back.
  • On line 32: I update the tile with new information.
  • Line 34: I create a toast object. This is a notification that is shown to the user.
  • Line 37: A toast can have an Uri. When the user taps the toast, your application is started and your application navigates to this Uri, including the query string parameters. This way you can open your application in the correct state. You can see on line 16 of the main application that I do actually use this information in the OnNavigatedTo method. This is hard in the emulator to test, since the background task is run as soon as it’s added to the ScheduledActionService. When it’s run, my main application is still active and toast’s won’t be shown. So you’ll have to close the application and wait for 30 minutes. After 30 minutes the PeriodicTask will be run again.
  • Line 43: I’ve wrapped all code in a try..catch block. If an Exception occurs I call the Abort method. This let’s Windows Phone know that the task should not be run again until I reschedule it from my main application. If everything went well, I call the NotifyComplete method on line 41. This let’s Windows Phone know that the task can be safely run again.

Conclusion

Wow! Multi tasking in Windows Phone is a real cool feature to have. The ones explained above aren’t the only ways to do some kind of multi tasking. In Windows Phone 7.1 there are also:

  • Scheduled Tile Updates.
  • Background Transfers.
  • Alarms.
  • Reminders.

And they all are really not that difficult to understand and program. Working in the emulator to test a PeriodicTask is a bit of a pain. As soon as I use the Add method to schedule a task, Visual Studio loses the debug connection, because the debugger attaches itself to the background task. Next to that, the scheduled task is invoked immediately while my application is still active, so you won’t see any toasts. To see toasts, you’ll have to wait thirty minutes for the PeriodicTask to be run again. It would be nice for the future that we can configure the interval in which PeriodicTasks are run in the emulator. This would simplify testing. Just for completeness, here is a screenshot which shows the background task in the settings menu, under “Applications” in Windows Phone 7.1:

image

You can see the description coming from my code in the last sentence in the screenshot above. The coming weeks I will be experimenting a lot more with Windows Phone 7.1, so if you find this interesting, keep an eye on this blog! You can find a working example here.

Sharing validation code between a WPF client, a WCF Service and Entity Framework 4.1 using data annotations

Recently Entity Framework 4.1 was released. While most people were very enthusiastic about the code first stuff, code first was the part that impressed me the least. This is because in my line of business we deal with stored procedures a lot and it turns out that mapping to stored procedures isn’t supported with code first in the 4.1 release. What did catch my eye is the new DBContext api. As you’ll probably know, the new DBContext class is largely a wrapper around the ObjectContext class with a simplified API. Now you might think as I did: “But if I’m comfortable with the ObjectContext class and I don’t use code first, why in the world would I need a DbContext?”. The answer is pretty simple. The DbContext has a feature which simply isn’t supported by the ObjectContext: data validation with the attributes from the System.ComponentModel.DataAnnotations namespace. In this article I’ll show you how to decorate your classes with validation attributes and how these classes can be reused by both the client and the server. The client will be a WPF application. If you don’t like WPF or you just don’t care, feel free the skip to the “WCF Service” paragraph. That’s where the Entity Framework 4.1 part is explained.

The Solution

Let’s first start with the two projects that are responsible for my data access classes, including the entities:

image

Both DbContextLibrary and EntitiesLibrary are normal class library projects. I started with the DBContextLibrary and used the new “DbContext Generator” T4 template to generate classes. When you use this template you’ll actually get two T4 templates added to your project. The one with “.Context” in it generates your DbContext class, the other one generates POCO entities. I’ve simply moved the one that generates the entities to it’s own class library. If you do this, you’ll have to add a namespace in the T4 template that generates the DbContext, so that DbContext knows the entity classes. In this article I will only have one entity, namely Product. I’ve added some validation to this class using the buddy class mechanism. This code is contained in the Product.Metadata.cs file in the EntitiesLibrary project:

   1: using System;

   2: using System.Collections.Generic;

   3: using System.Linq;

   4: using System.Text;

   5: using System.ComponentModel.DataAnnotations;

   6:  

   7:  

   8: namespace EntitiesLibrary

   9: {

  10:     [MetadataType(typeof(ProductMetadata))]

  11:     public partial class Product 

  12:     {

  13:         private class ProductMetadata

  14:         {

  15:             [Range(0,Double.MaxValue,ErrorMessage="ListPrice can't be smaller than zero!")]

  16:             public decimal ListPrice { get; set; }

  17:         }

  18:     }

  19: }

You can see that I’ve only added validation for the ListPrice property using the Range attribute. Now let’s take a look at the Adventureworks2008.tt T4 template, since it contains some stuff I had to manually edit:

   1: <#@ template language="C#" debug="false" hostspecific="true"#>

   2: <#@ include file="EF.Utility.CS.ttinclude"#><#@

   3:  output extension=".cs"#><#

   4:  

   5: CodeGenerationTools code = new CodeGenerationTools(this);

   6: MetadataLoader loader = new MetadataLoader(this);

   7: CodeRegion region = new CodeRegion(this, 1);

   8: MetadataTools ef = new MetadataTools(this);

   9:  

  10: string inputFile = @"..\DbContextLibrary\Adventureworks2008.edmx";

  11: EdmItemCollection ItemCollection = loader.CreateEdmItemCollection(inputFile);

  12: string namespaceName = code.VsNamespaceSuggestion();

  13:  

  14: EntityFrameworkTemplateFileManager fileManager = EntityFrameworkTemplateFileManager.Create(this);

  15: WriteHeader(fileManager);

  16:  

  17: foreach (var entity in ItemCollection.GetItems<EntityType>().OrderBy(e => e.Name))

  18: {

  19:     fileManager.StartNewFile(entity.Name + ".cs");

  20:     BeginNamespace(namespaceName, code);

  21: #>

  22: using System;

  23: using System.Collections.Generic;

  24: using System.ComponentModel;

  25: using System.ComponentModel.DataAnnotations;

  26: using System.Linq;

  27: using System.Reflection;

  28:  

  29: <#=Accessibility.ForType(entity)#> <#=code.SpaceAfter(code.AbstractOption(entity))#>partial class <#=code.Escape(entity)#> : IDataErrorInfo

  30: {

  31:     static <#=code.Escape(entity)#>()

  32:     {

  33:         //We need to hook this up in order to make the buddy class mechanism work in WPF, Console Applications etc.....

  34:         //Or the Validator methods won't make use of the metadata class.

  35:  

  36:         Type currentType = MethodBase.GetCurrentMethod().DeclaringType;

  37:         object[] attributes = currentType.GetCustomAttributes(typeof(MetadataTypeAttribute),false);

  38:         if(attributes.Length > 0)

  39:         {

  40:             //MetadataType attribute found!

  41:             MetadataTypeAttribute metaDataAttribute = (MetadataTypeAttribute)attributes[0];

  42:             TypeDescriptor.AddProviderTransparent(

  43:                 new AssociatedMetadataTypeTypeDescriptionProvider(

  44:                     currentType, metaDataAttribute.MetadataClassType),currentType);

  45:         }

  46:            

  47:     }

  48:  

  49:     public string Error

  50:     {

  51:         get 

  52:         {

  53:             ValidationContext vc = new ValidationContext(this, null, null);

  54:             List<ValidationResult> result = new List<ValidationResult>();

  55:             if (!Validator.TryValidateObject(this, vc, result))

  56:             {

  57:                 return result.First().ErrorMessage;

  58:             }

  59:             else

  60:             {

  61:                 return null;

  62:             }

  63:         }

  64:     }

  65:  

  66:     public string this[string columnName]

  67:     {

  68:         get 

  69:         {

  70:             ValidationContext vc = new ValidationContext(this, null, null);

  71:             List<ValidationResult> result = new List<ValidationResult>();

  72:             vc.MemberName = columnName;

  73:             if (!Validator.TryValidateProperty(GetType().GetProperty(columnName).GetValue(this, null), vc, result))

  74:             {

  75:                 return result.First().ErrorMessage;

  76:             }

  77:             else

  78:             {

  79:                 return null;

  80:             }

  81:         }

  82:     }

  83:  

  84: <#

  85:     var propertiesWithDefaultValues = entity.Properties.Where(p => p.TypeUsage.EdmType is PrimitiveType && p.DeclaringType == entity && p.DefaultValue != null);

  86:     var collectionNavigationProperties = entity.NavigationProperties.Where(np => np.DeclaringType == entity && np.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many);

  87:     var complexProperties = entity.Properties.Where(p => p.TypeUsage.EdmType is ComplexType && p.DeclaringType == entity);

  88:  

  89:     if (propertiesWithDefaultValues.Any() || collectionNavigationProperties.Any() || complexProperties.Any())

  90:     {

  91: #>

  92:     public <#=code.Escape(entity)#>()

  93:     {

  94: <#

  95:         foreach (var edmProperty in propertiesWithDefaultValues)

  96:         {

  97: #>

  98:         this.<#=code.Escape(edmProperty)#> = <#=code.CreateLiteral(edmProperty.DefaultValue)#>;

  99: <#

 100:         }

 101:  

 102:         foreach (var navigationProperty in collectionNavigationProperties)

 103:         {

 104: #>

 105:         this.<#=code.Escape(navigationProperty)#> = new HashSet<<#=code.Escape(navigationProperty.ToEndMember.GetEntityType())#>>();

 106: <#

 107:         }

 108:  

 109:         foreach (var complexProperty in complexProperties)

 110:         {

 111: #>

 112:         this.<#=code.Escape(complexProperty)#> = new <#=code.Escape(complexProperty.TypeUsage)#>();

 113: <#

 114:         }

 115: #>

 116:     }

 117:  

 118: <#

 119:     }

 120:  

 121:     var primitiveProperties = entity.Properties.Where(p => p.TypeUsage.EdmType is PrimitiveType && p.DeclaringType == entity);

 122:     if (primitiveProperties.Any())

 123:     {

 124:         foreach (var edmProperty in primitiveProperties)

 125:         {

 126:             WriteProperty(code, edmProperty);

 127:         }

 128:     }

 129:  

 130:     if (complexProperties.Any())

 131:     {

 132: #>

 133:  

 134: <#

 135:         foreach(var complexProperty in complexProperties)

 136:         {

 137:             WriteProperty(code, complexProperty);

 138:         }

 139:     }

 140:  

 141:     var navigationProperties = entity.NavigationProperties.Where(np => np.DeclaringType == entity);

 142:     if (navigationProperties.Any())

 143:     {

 144: #>

 145:  

 146: <#

 147:         foreach (var navigationProperty in navigationProperties)

 148:         {

 149:             WriteNavigationProperty(code, navigationProperty);

 150:         }

 151:     }

 152: #>

 153: }

 154: <#

 155:     EndNamespace(namespaceName);

 156: }

 157:  

 158: foreach (var complex in ItemCollection.GetItems<ComplexType>().OrderBy(e => e.Name))

 159: {

 160:     fileManager.StartNewFile(complex.Name + ".cs");

 161:     BeginNamespace(namespaceName, code);

 162: #>

 163: using System;

 164:  

 165: <#=Accessibility.ForType(complex)#> partial class <#=code.Escape(complex)#>

 166: {

 167: <#

 168:     var complexProperties = complex.Properties.Where(p => p.TypeUsage.EdmType is ComplexType && p.DeclaringType == complex);

 169:     var propertiesWithDefaultValues = complex.Properties.Where(p => p.TypeUsage.EdmType is PrimitiveType && p.DeclaringType == complex && p.DefaultValue != null);

 170:  

 171:     if (propertiesWithDefaultValues.Any() || complexProperties.Any())

 172:     {

 173: #>

 174:     public <#=code.Escape(complex)#>()

 175:     {

 176: <#

 177:         foreach (var edmProperty in propertiesWithDefaultValues)

 178:         {

 179: #>

 180:         this.<#=code.Escape(edmProperty)#> = <#=code.CreateLiteral(edmProperty.DefaultValue)#>;

 181: <#

 182:         }

 183:  

 184:         foreach (var complexProperty in complexProperties)

 185:         {

 186: #>

 187:         this.<#=code.Escape(complexProperty)#> = new <#=code.Escape(complexProperty.TypeUsage)#>();

 188: <#

 189:         }

 190: #>

 191:     }

 192:  

 193: <#

 194:     }

 195:  

 196:     var primitiveProperties = complex.Properties.Where(p => p.TypeUsage.EdmType is PrimitiveType && p.DeclaringType == complex);

 197:     if (primitiveProperties.Any())

 198:     {

 199:         foreach(var edmProperty in primitiveProperties)

 200:         {

 201:             WriteProperty(code, edmProperty);

 202:         }

 203:     }

 204:  

 205:     if (complexProperties.Any())

 206:     {

 207: #>

 208:  

 209: <#

 210:         foreach(var edmProperty in complexProperties)

 211:         {

 212:             WriteProperty(code, edmProperty);

 213:         }

 214:     }

 215: #>

 216: }

 217: <#

 218:     EndNamespace(namespaceName);

 219: }

 220:  

 221: if (!VerifyTypesAreCaseInsensitiveUnique(ItemCollection))

 222: {

 223:     return "";

 224: }

 225:  

 226: fileManager.Process();

 227:  

 228: #>

 229: <#+

 230: string GetResourceString(string resourceName)

 231: {

 232:     if(_resourceManager == null)

 233:     {

 234:         _resourceManager = new System.Resources.ResourceManager("System.Data.Entity.Design", typeof(System.Data.Entity.Design.MetadataItemCollectionFactory).Assembly);

 235:     }

 236:     

 237:     return _resourceManager.GetString(resourceName, null);

 238: }

 239: System.Resources.ResourceManager _resourceManager;

 240:  

 241: void WriteHeader(EntityFrameworkTemplateFileManager fileManager)

 242: {

 243:     fileManager.StartHeader();

 244: #>

 245: //------------------------------------------------------------------------------

 246: // <auto-generated>

 247: // <#=GetResourceString("Template_GeneratedCodeCommentLine1")#>

 248: //

 249: // <#=GetResourceString("Template_GeneratedCodeCommentLine2")#>

 250: // <#=GetResourceString("Template_GeneratedCodeCommentLine3")#>

 251: // </auto-generated>

 252: //------------------------------------------------------------------------------

 253:  

 254: <#+

 255:     fileManager.EndBlock();

 256: }

 257:  

 258: void BeginNamespace(string namespaceName, CodeGenerationTools code)

 259: {

 260:     CodeRegion region = new CodeRegion(this);

 261:     if (!String.IsNullOrEmpty(namespaceName))

 262:     {

 263: #>

 264: namespace <#=code.EscapeNamespace(namespaceName)#>

 265: {

 266: <#+

 267:         PushIndent(CodeRegion.GetIndent(1));

 268:     }

 269: }

 270:  

 271:  

 272: void EndNamespace(string namespaceName)

 273: {

 274:     if (!String.IsNullOrEmpty(namespaceName))

 275:     {

 276:         PopIndent();

 277: #>

 278: }

 279: <#+

 280:     }

 281: }

 282:  

 283: void WriteProperty(CodeGenerationTools code, EdmProperty edmProperty)

 284: {

 285:     WriteProperty(Accessibility.ForProperty(edmProperty),

 286:                   code.Escape(edmProperty.TypeUsage),

 287:                   code.Escape(edmProperty),

 288:                   code.SpaceAfter(Accessibility.ForGetter(edmProperty)),

 289:                   code.SpaceAfter(Accessibility.ForSetter(edmProperty)));

 290: }

 291:  

 292: void WriteNavigationProperty(CodeGenerationTools code, NavigationProperty navigationProperty)

 293: {

 294:     var endType = code.Escape(navigationProperty.ToEndMember.GetEntityType());

 295:     WriteProperty(PropertyVirtualModifier(Accessibility.ForProperty(navigationProperty)),

 296:                   navigationProperty.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ? ("ICollection<" + endType + ">") : endType,

 297:                   code.Escape(navigationProperty),

 298:                   code.SpaceAfter(Accessibility.ForGetter(navigationProperty)),

 299:                   code.SpaceAfter(Accessibility.ForSetter(navigationProperty)));

 300: }

 301:  

 302: void WriteProperty(string accessibility, string type, string name, string getterAccessibility, string setterAccessibility)

 303: {

 304: #>

 305:     <#=accessibility#> <#=type#> <#=name#> { <#=getterAccessibility#>get; <#=setterAccessibility#>set; }

 306: <#+

 307: }

 308:  

 309: string PropertyVirtualModifier(string accessibility)

 310: {

 311:     return accessibility + (accessibility != "private" ? " virtual" : "");

 312: }

 313:  

 314: bool VerifyTypesAreCaseInsensitiveUnique(EdmItemCollection itemCollection)

 315: {

 316:     var alreadySeen = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);

 317:     foreach(var type in itemCollection.GetItems<StructuralType>())

 318:     {

 319:         if (!(type is EntityType || type is ComplexType))

 320:         {

 321:             continue;

 322:         }

 323:  

 324:         if (alreadySeen.ContainsKey(type.FullName))

 325:         {

 326:             Error(String.Format(CultureInfo.CurrentCulture, "This template does not support types that differ only by case, the types {0} are not supported", type.FullName));

 327:             return false;

 328:         }

 329:         else

 330:         {

 331:             alreadySeen.Add(type.FullName, true);

 332:         }

 333:     }

 334:  

 335:     return true;

 336: }

 337: #>

 

In order for entities to support automatic validation in WPF I had to change the following things in this template:

  • Line 10: The path to the .edmx file. The .edmx is contained in another project and the T4 template by default assumes it’s in the same project as the T4 template, so you’ll need to adjust this.
  • Lines 24-27: I’ve added these namespaces because they are necessary for the the rest of my code.
  • Line 29: I’ve changed this line to let my entity implement the IDataErrorInfo interface. You have to understand that in WPF, unlike in Silverlight, the data annotations aren’t automatically read by the components (DataGrid). You’ll have to implement the IDataErrorInfo interface and validate manually using the data annotations.
  • Line 49-82: These are the members you’ll have to implement because of the IDataErrorInfo interface: Error and an indexer. Normally, in the Error property you’ll write code to validate the whole object and construct a string with an error message. In the indexer you’ll write code that validates a single property. The property name is supplied as an argument and you’ll need to construct a string with an error message. In both members I’ve used the Validator class to validate. Whenever you are in a situation that you’ll need to validate using data annotations and this doesn’t happen automatically, you can use the static Validator class to do the validation for you. This isn’t difficult, it’s just something to keep in mind. To make the validation generic for property validation, you’ll have to supply the member name like on line 72. Next to that, you’ll have to use some reflection to get the property value in a generic way. This reflection code is found on line 73, it’s the first argument of the TryValidatePropertyMethod.
  • Line 31-47: I’ve intentionally covered lines 49-82 first. Because now it’s clear that I implement the IDataErrorInfo interface in my entity and I use the Validator class to do the validation for me. If you now create a list of Products, add those to a WPF datagrid and use TwoWay binding with validation enabled for the ListPrice, you would think that validation should kick in. This was at least what I thought. Turns out that the whole buddy metadata mechanism isn’t something that’s supported by the static Validator class. It are the frameworks like WCF RIA Services that add support for the buddy mechanism. Luckily with some googling and reflectoring I came to the conclusion that the Validator class uses .Net’s extensible TypeDescriptor mechanism instead of reflection, which can be seen as a mechanism similar to reflection, only the type information can be extended runtime. I had to extend the type information once for each entity that get’s generated, with the information in the buddy metadata class. I can’t do this in the constructor, because then it would happen way to often. A static constructor seemed a good place to me. The declaration of the static constructor is found on line 31. On line 36 I use the MethodBase class to get a reference to the current type. This is needed since I need to extend the type information of the current type. On line 37-39 I check whether the MetadataTypeAttribute is present. If so, I retrieve it on line 41. This attribute has the property “MetadataClassType”. This property contains the type you supply when you place the MetadataType attribute. On line 42 I extend the type information of the current type with the associated metadata. I do this by calling the AddProviderTransparent method on the TypeDescriptor class and supplying an AssociatedMetadataTypeTypeDescriptionProvider. This provider is used for the buddy class mechanism and it’s constructor takes two arguments. First is the type you wish to extend with extra metadata, second is the metadata class.

So know we have a T4 template, that generates entities with support for WPF validation using data annotations and the buddy mechanism. Of course you can use the generated entities for any technology that doesn’t use the data annotations by default.

The WPF Application

The article is getting quite long, so bare with me :) . Luckily, this paragraph will be short. Here is the XAML:

   1: <Window x:Class="ProductsApp.MainWindow"

   2:         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   3:         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   4:         Title="MainWindow" Height="350" Width="525" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:my="clr-namespace:EntitiesLibrary;assembly=EntitiesLibrary" >

   5:       <Grid >

   6:         <DataGrid AutoGenerateColumns="False" EnableRowVirtualization="True" Name="_dtgProducts" RowDetailsVisibilityMode="VisibleWhenSelected">

   7:             <DataGrid.Columns>

   8:                 <DataGridTextColumn x:Name="classColumn" Binding="{Binding Path=Class}" Header="Class" Width="SizeToHeader" />

   9:                 <DataGridTextColumn x:Name="colorColumn" Binding="{Binding Path=Color}" Header="Color" Width="SizeToHeader" />

  10:                 <DataGridTextColumn x:Name="daysToManufactureColumn" Binding="{Binding Path=DaysToManufacture}" Header="Days To Manufacture" Width="SizeToHeader" />

  11:                 <DataGridTemplateColumn x:Name="discontinuedDateColumn" Header="Discontinued Date" Width="SizeToHeader">

  12:                     <DataGridTemplateColumn.CellTemplate>

  13:                         <DataTemplate>

  14:                             <DatePicker SelectedDate="{Binding Path=DiscontinuedDate, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" />

  15:                         </DataTemplate>

  16:                     </DataGridTemplateColumn.CellTemplate>

  17:                 </DataGridTemplateColumn>

  18:                 <DataGridTextColumn x:Name="errorColumn" Binding="{Binding Path=Error}" Header="Error" IsReadOnly="True" Width="SizeToHeader" />

  19:                 <DataGridCheckBoxColumn x:Name="finishedGoodsFlagColumn" Binding="{Binding Path=FinishedGoodsFlag}" Header="Finished Goods Flag" Width="SizeToHeader" />

  20:                 <DataGridTextColumn x:Name="listPriceColumn" Binding="{Binding Path=ListPrice,Mode=TwoWay,ValidatesOnDataErrors=True,NotifyOnValidationError=True}" Header="List Price" Width="SizeToHeader" />

  21:                 <DataGridCheckBoxColumn x:Name="makeFlagColumn" Binding="{Binding Path=MakeFlag}" Header="Make Flag" Width="SizeToHeader" />

  22:                 <DataGridTemplateColumn x:Name="modifiedDateColumn" Header="Modified Date" Width="SizeToHeader">

  23:                     <DataGridTemplateColumn.CellTemplate>

  24:                         <DataTemplate>

  25:                             <DatePicker SelectedDate="{Binding Path=ModifiedDate, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" />

  26:                         </DataTemplate>

  27:                     </DataGridTemplateColumn.CellTemplate>

  28:                 </DataGridTemplateColumn>

  29:                 <DataGridTextColumn x:Name="nameColumn" Binding="{Binding Path=Name}" Header="Name" Width="SizeToHeader" />

  30:                 <DataGridTextColumn x:Name="productIDColumn" Binding="{Binding Path=ProductID}" Header="Product ID" Width="SizeToHeader" />

  31:                 <DataGridTextColumn x:Name="productLineColumn" Binding="{Binding Path=ProductLine}" Header="Product Line" Width="SizeToHeader" />

  32:                 <DataGridTextColumn x:Name="productModelIDColumn" Binding="{Binding Path=ProductModelID}" Header="Product Model ID" Width="SizeToHeader" />

  33:                 <DataGridTextColumn x:Name="productNumberColumn" Binding="{Binding Path=ProductNumber}" Header="Product Number" Width="SizeToHeader" />

  34:                 <DataGridTextColumn x:Name="productSubcategoryIDColumn" Binding="{Binding Path=ProductSubcategoryID}" Header="Product Subcategory ID" Width="SizeToHeader" />

  35:                 <DataGridTextColumn x:Name="reorderPointColumn" Binding="{Binding Path=ReorderPoint}" Header="Reorder Point" Width="SizeToHeader" />

  36:                 <DataGridTextColumn x:Name="rowguidColumn" Binding="{Binding Path=rowguid}" Header="rowguid" Width="SizeToHeader" />

  37:                 <DataGridTextColumn x:Name="safetyStockLevelColumn" Binding="{Binding Path=SafetyStockLevel}" Header="Safety Stock Level" Width="SizeToHeader" />

  38:                 <DataGridTemplateColumn x:Name="sellEndDateColumn" Header="Sell End Date" Width="SizeToHeader">

  39:                     <DataGridTemplateColumn.CellTemplate>

  40:                         <DataTemplate>

  41:                             <DatePicker SelectedDate="{Binding Path=SellEndDate, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" />

  42:                         </DataTemplate>

  43:                     </DataGridTemplateColumn.CellTemplate>

  44:                 </DataGridTemplateColumn>

  45:                 <DataGridTemplateColumn x:Name="sellStartDateColumn" Header="Sell Start Date" Width="SizeToHeader">

  46:                     <DataGridTemplateColumn.CellTemplate>

  47:                         <DataTemplate>

  48:                             <DatePicker SelectedDate="{Binding Path=SellStartDate, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" />

  49:                         </DataTemplate>

  50:                     </DataGridTemplateColumn.CellTemplate>

  51:                 </DataGridTemplateColumn>

  52:                 <DataGridTextColumn x:Name="sizeColumn" Binding="{Binding Path=Size}" Header="Size" Width="SizeToHeader" />

  53:                 <DataGridTextColumn x:Name="sizeUnitMeasureCodeColumn" Binding="{Binding Path=SizeUnitMeasureCode}" Header="Size Unit Measure Code" Width="SizeToHeader" />

  54:                 <DataGridTextColumn x:Name="standardCostColumn" Binding="{Binding Path=StandardCost}" Header="Standard Cost" Width="SizeToHeader" />

  55:                 <DataGridTextColumn x:Name="styleColumn" Binding="{Binding Path=Style}" Header="Style" Width="SizeToHeader" />

  56:                 <DataGridTextColumn x:Name="weightColumn" Binding="{Binding Path=Weight}" Header="Weight" Width="SizeToHeader" />

  57:                 <DataGridTextColumn x:Name="weightUnitMeasureCodeColumn" Binding="{Binding Path=WeightUnitMeasureCode}" Header="Weight Unit Measure Code" Width="SizeToHeader" />

  58:             </DataGrid.Columns>

  59:         </DataGrid>

  60:     </Grid>

  61: </Window>

The most important part is on line 20. The binding for the ListPrice property is set to TwoWay, ValidatesOnDataErrors is true and NotifyOnValidationError is also true. This will make sure that when the user enters a listprice smaller than zero, validation will kick in:

image

 

 

The WCF Service

Last up is the WCF Service, which uses the new EF 4.1 DbContext api to load from- and update data in the database:

   1: using System;

   2: using System.Linq;

   3: using System.Runtime.Serialization;

   4: using System.ServiceModel;

   5: using System.ServiceModel.Activation;

   6: using EntitiesLibrary;

   7: using DbContextLibrary;

   8: using System.Collections.Generic;

   9: using System.Data.Entity.Validation;

  10: using System.Data;

  11:  

  12: namespace ProductsApp.Web

  13: {

  14:     [ServiceContract(Namespace = "")]

  15:     [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]

  16:     public class ProductService

  17:     {

  18:         [OperationContract]

  19:         public Product[] GetProducts() 

  20:         {

  21:             using (AdventureWorks2008Entities ents = new AdventureWorks2008Entities())

  22:             {

  23:                 return ents.Product.AsNoTracking().ToArray();

  24:             }

  25:         }

  26:  

  27:         [OperationContract]

  28:         [FaultContract(typeof(string[]))]

  29:         public void UpdateProduct(Product toUpdate)

  30:         {

  31:             using (AdventureWorks2008Entities ents = new AdventureWorks2008Entities())

  32:             {

  33:                 //prevent validating before save because I do this manually

  34:                 ents.Configuration.ValidateOnSaveEnabled = false;

  35:  

  36:                 //Prevent detecting changes before save....

  37:                 ents.Configuration.AutoDetectChangesEnabled = false;

  38:  

  39:                 ents.Product.Attach(toUpdate);

  40:                 ents.ChangeTracker.Entries<Product>().

  41:                         Single((entry) => entry.Entity == toUpdate).State = EntityState.Modified;

  42:                 DbEntityValidationResult error = ents.GetValidationErrors().SingleOrDefault();

  43:                 if (error != null)

  44:                 {

  45:                     throw new FaultException<string[]>(

  46:                             error.ValidationErrors.Select((er) => er.PropertyName + ": " + er.ErrorMessage).ToArray()

  47:                         );

  48:                 }

  49:                 else

  50:                 {

  51:                     

  52:                     ents.SaveChanges();

  53:                 }

  54:             }

  55:         }

  56:     }

  57: }

  • Line 19-25: This isn’t that exciting, I just load the data with no tracking from the database. In a service, tracking won’t do you any good.
  • Line 29-55: This is the most interesting part. My web project also references my EntitiesLibrary project, witch contains the Product class with the buddy mechanism and the data annotation on the listprice. The DbContext api will by default automatically validate before saving and will throw an exception if there are errors. I’m disabling this behavior on line 34 since I’m going to validate up front. Because I’m in a service, the DbContext can’t detect any changes since it doesn’t have any original values, so I’m also disabling this behavior on line 37. On line 39 the product is attached. On line 40-41 I’m changing the state of the product to modified. This is necessary, if you forget this, the DbContext won’t validate (even when doing this manually) or save the product. Since I know for certain that the DbContext is only tracking one entity, I retrieve the single DbEntityValidationResult on line 42. If there are no errors, I will get an empty collection and because of the SingleOrDefault method I will get null. Thus, if the error is not null on line 43, I throw a new FaultException and supply it with a string[]. This string[] contains the validation errors for all the properties that caused errors. Of course, this will only be the listprice since it’s the only one with a data annotation. If the validation returned null, I’m saving the changes on line 52.

The Console Application

As you can see above, using the DbContext api means that you don’t have to write validation code on both the client and the server. This problem was already solved for Silverlight by WCF RIA Services, but now we can finally share the data annotations between the server and other client technologies as well. Now let’s test our service with a client that doesn’t do any validation in the UI and tries to submit some illegal values:

   1: using System;

   2: using System.Collections.Generic;

   3: using System.Linq;

   4: using System.Text;

   5: using ProductsConsoleApp.Services;

   6: using EntitiesLibrary;

   7: using System.ServiceModel;

   8: using System.ComponentModel;

   9:  

  10: namespace ProductsConsoleApp

  11: {

  12:     class Program

  13:     {

  14:         static void Main(string[] args)

  15:         {

  16:             ProductServiceClient client = new ProductServiceClient();

  17:             Product first = client.GetProducts()[0];

  18:             first.ListPrice = -1;

  19:             try

  20:             {

  21:                 client.UpdateProduct(first);

  22:             }

  23:             catch (FaultException<string[]> ex)

  24:             {

  25:                 Console.WriteLine("There were validation errors on the server:");

  26:                 foreach (string errorMessage in ex.Detail)

  27:                 {

  28:                     Console.WriteLine(errorMessage);

  29:                 }

  30:             }

  31:             Console.ReadKey();

  32:         }

  33:     }

  34: }

If you’d run the application above you would get the following output:

image

And we can see that our server is protected against bad input.

Conclusion

One of the most overlooked features of the Entity Framework 4.1 is the new ability to validate the entities according to the buddy class mechanism and data annotations. This means that when we write serverside code, we don’t have to write the validation logic ourselves and that we can share the entities between client and server to use the same validation logic on the client. This also works of course when the client is an ASP.NET MVC Controller for example.

I’ve tried to share code this way between a Silverlight client and a WCF Service but this doesn’t work. This is because the EntitiesLibrary project must be a Silverlight class library before it can be referenced by both Silverlight and the server project. In Silverlight the data annotations are defined in a different assembly with a different version than the data annotations in the full .Net framework. The Entity Framework and the Validator class in the full .Net framework will NOT recognize data annotations from Silverlight. It seems that the best way to share validation code with Silverlight is by using WCF RIA Services. You can find the working example here.