Building a declarative WCF service using Workflow Foundation 4 and Content Based Correlation

This blog post accompanies my session on Workflow Foundation 4 programming during the Belgian Tech Days (actually developers and IT-pro days :)). During this session I built a WCF service using Workflow Foundation 4, and I want to show you how to do this on your own…

In the first part you’ll learn how to create a simple FlowChart workflow and test it, and then in the second part you’ll learn how to setup correlation so multiple players can play the game…

Preparing the lab

This lab starts with a new project, so start Visual Studio 2010 and create a new workflow service project (call it NumberGuessingGame):

image

This creates a new solution with a workflow project.

image

Remove Service1.xamlx, we’re going to add a new service with a better name.

Right-click the project and add a new item. Select the WCF Workflow Service template and name it GuessIt.xamlx.

Creating the initial FlowChart

This adds a workflow service with a sequential activity containing a Receive and Send activity. Delete the sequential activity leaving the workflow empty. Open the toolbox and drag a FlowChart activity onto the workflow designer. This should look like this now:

image

Next drag a Receive activity onto the designer, below Start. Name it Start A New Game. Select the receive activity and enter following the OperationName, ServiceContractName and CanCreateInstance properties in the properties window:

image

Next right-click on the receive activity and select the Create SendReply option from the drop-down menu. This add a Send activity to the workflow. The Send is coupled to the receive activity through its Request property:

image

Now connect the activities:

image

Adding variables

Now, in the workflow designer open the variables window and add a new variable called player of type String. This will hold the player name received through the “Start A New Game” Receive activity. You will also see a variable of type CorrelationHandle. This is used to connect several receive and send activities through correlation. Rename this to gameHandle.We’ll use this handle later to setup content-based correlation.

Now add two new variables theNumber and guess, both of type Int32. The first is the number the user needs to guess, to you need to initialize it to a random number between 0 and 100. Use the Random type to do this:

image

Go back to the first receive activity. Click on the content property. This opens the Content Definition window. Select the player as the message data (and set the Message type to String):

image

Do the same for the send activity, but now use following expression (of type String):

   1: player + " guess the number between 0 and 100"

You might also get validation errors because you renamed the correlation handle to gameHandle. Change the CorrelationInitilizers property to use gameHandle (click on the … button).

image

Testing the service

Press F5 in Visual Studio. The WCF Test Client will start and automatically fetch meta-data from the service. Double click the Begin method. This opens a new tab allowing you to invoke the Begin operation on the service. Enter your name and click Invoke. In the bottom area you should see the result of invoking the begin method.

image

This concludes the first step.

Adding the data contracts

Let’s add a couple of data contracts to the project, one for a game and another for a guess. Note that both contain the player name, this way our service will be able to distinguish between multiple games, as long as each player uses a unique player name:

   1: [DataContract]
   2:  
   3: public class Game
   4:  
   5: {
   6:  
   7: [DataMember]
   8:  
   9: public string PlayerName { get; set; }
  10:  
  11: [DataMember]
  12:  
  13: public string Message { get; set; }
  14:  
  15: }
  16:  
  17: [DataContract]
  18:  
  19: public class Guess
  20:  
  21: {
  22:  
  23: [DataMember(IsRequired = true)]
  24:  
  25: public string PlayerName { get; set; }
  26:  
  27: [DataMember(IsRequired = true)]
  28:  
  29: public int Try { get; set; }
  30:  
  31: }

Make the “Send Game Started” send activity use a Game instance as the result. To do this you will need to add another variable of type Game, and initialize it to a new instance:

image

Now add to assign activities after the Begin receive activity, and assign appropriate values to the game:

image

Adding the guessing logic

Add another variable, calling it guess of type Guess. Then add another receive activity after the send activity, but now with an operation name called Guess, taking guess variable as its content. Check if the guess was right using a decision shape. If so, congratulate the user. If not, decide whether the guess was too small or large. Confirm this back to the user using three SendReply activities (create each one by right-clicking the Guess receive activity and select Create SendReply).

Here is an example of the result:

image

Adding Content-based Correlation

Of course we want to make a single player play the same game, but what if multiple players are playing on the same server? We need correlation. In this part we’re going to correlate the guess activity to the Begin activity using the player’s name. That is why our data contract both contain the player’s name (by coincidence the properties have the same name, but this is not required).

To do correlation we need a correlation handle. This handle will act like a key to a workflow. If a request comes in, we’re going to find this key through part of the message, in our case the player’s name. So, if you haven’t done so, add a new variable to the workflow called gameHandle of type CorrelationHandle. The make sure that all the first sendReply activity is set to initialize this handle by ensuring the CorrelationInitializer is set like this:

image

When the workflow sends this message, we’re saying that the key of the gameHandle is the player’s name. So when another message arrives, the workflow runtime can then see is the message contains a valid key (again the player’s name), use this key to find the right workflow instance, and then send the message to it. So next step is to set the Guess receive activity’s Correlates On like this:

image

Now you should be able to play a game, making sure that the first and following messages all have the same player name. You can also start two or more games, each with their own player name!

ObservableCollection<T> now part of .NET 4 (No need to reference WPF)

ObservableCollection<T> is a generic collection added as part of WPF and Silverlight. WinForms has BindingList<T>. So writing code that targets both WinForms and WPF would mean using BindingList<T> (the common thing) and writing code targetting WPF and Silverlight would mean ObservableCollection<T>. So there would be no way to write code that targets all three platforms. Luckily now (in .NET 4) we can use ObservableCollection<T> anywhere because Microsoft made it part of System.dll. Nice! Two others were also moved here: ReadOnlyObservableCollection<T> and INotifyCollectionChanged.

To double check if I could use these collections outside WPF projects I created a simple console application using them:

   1: class Program
   2: {
   3:   static void Main(string[] args)
   4:   {
   5:     ObservableCollection<string> noWpf = new ObservableCollection<string> { "Hello", "World" };
   6:     INotifyCollectionChanged watchCollection = noWpf as INotifyCollectionChanged;
   7:  
   8:     
   9:  
  10:     if (watchCollection != null)
  11:     {
  12:       watchCollection.CollectionChanged += (sender, e) => { Console.WriteLine("Collection action = {0}", e.Action); };
  13:     }
  14:  
  15:     noWpf.Add("Love it!");
  16:   }
  17: }

Compiles. Runs.

Could I use it in WinForms? So I created a simple WinForms application like this:

   1: public partial class Form1 : Form
   2: {
   3:   ObservableCollection<string> noWpf;
   4:  
   5:   public Form1()
   6:   {
   7:     InitializeComponent();
   8:  
   9:     noWpf  = new ObservableCollection<string> { "Hello", "World" };
  10:     var bs = new BindingSource() { DataSource = noWpf };
  11:     bs.ListChanged += (sender, e) => { MessageBox.Show(e.ListChangedType.ToString()); };
  12:     listBox1.DataSource = bs;
  13:   }
  14:  
  15:   private void button1_Click(object sender, EventArgs e)
  16:   {
  17:     noWpf.Add("Test");
  18:   }
  19: }

But when I click the button, which adds a new element to the observable collection, the listbox doesn’t update. It looks like winforms databinding doesn’t support ObservableCollection…

Fixing Application Pool not starting problem by editing ApplicationHost.config

While playing around with Windows Server AppFabric I created a new Application pool set for .NET 4. However this application pool would immediately throw an error when starting;

“The worker process failed to pre-load .Net Runtime version v4.0.21006.”

A little experimentation showed that changing to the built in application pool worked. So it looks like IIS, when creating a new application pool, configures for the wrong .NET version.

I then found that this kind of information is stored in ApplicationHost.config, but I couldn’t find it anywhere on my system (except backups in history). Hmmm. And I wasn’t the only one.

So using notepad (!) I could open this file in “C:\Windows\System32\inetsrv\config”. Best of course is to first stop IIS and make a backup of the file.

Then I edited the <applicationPools> section, looking for v4.0 and replacing it with v4.0.30128.

And yes! That fixed it.

Using Model-View-ViewModel with WPF

In this blog post I want to show my way of implementing the Model-View-ViewModel pattern for WPF. I hope it serves as a simple example for those of you who want to start using it.

The advantage of MVVM is that the view, which is a WPF thing, doesn’t contain any code. Instead the view uses a lot of data binding to bind itself to the data, but also to the functionality through commands. Because the model itself should not be dependent on any specific technology, we use a viewmodel, which is an adapter, to add the model things like extra data and commands. So again, the view doesn’t contain any code, the viewmodel does. This means that it is possible to download the view from a database, so you can vary the view per company/user, or make it very easy to update the view. Second advantage is that is makes it very easy to test your functionality using unit tests, which I think is the most important advantage…

Use INotifyPropertyChanged

So let’s get started. First of all you should understand INotifyPropertyChanged.

To better understand the importance of INotifyPropertyChanged, you should understand how databinding works, for example in WPF.

image

In WPF any control can data bind any of its dependency properties to any data through its data binding mechanism. The control doesn’t need to know about the data object (actually it can’t know the type of the data object because the control is usually written several years before the data object :)

image

Dependency properties have this special feature, namely that you can register for the changed event of the dependency property. So when someone changes the control’s property, the databinding object will be notified and it can then update the data object’s property.

image

INotifyPropertyChanged does the same thing. A databinding object from WPF knows about this interface and will query the data object for it. When it has this interface, the databinding object registers itself for any changed events, and updates the control’s property. This way you get two-way data binding, when one side changes, the other side gets updated as well. Likewise should you use ObservableCollection<T> for any collections, so these can notify any controls that the list has changed.

Implementing INotifyPropertyChanged is simple. Start by defining a base class that implements the interface:

   1: public class Entity : INotifyPropertyChanged
   2: {
   3:   public event PropertyChangedEventHandler PropertyChanged;
   4:  
   5:   public virtual void RaisePropertyChanged(string propName)
   6:   {
   7:     if (PropertyChanged != null)
   8:       PropertyChanged(this, new PropertyChangedEventArgs(propName));
   9:   }
  10: }

INotifyPropertyChanged requires you to implement the PropertyChanged event, and trigger it each time a property changes. This base class does it all… Then any object requiring it can derive from this base class; both model and viewmodel should derive and raise the PropertyChanged event when they change. In this example I’m going to use a Person class:

   1: public class Person : Entity
   2: {
   3:   public class Properties
   4:   {
   5:     public const string Name = "Name";
   6:     public const string Age = "Age";
   7:   }
   8:  
   9:   private string name;
  10:  
  11:   public string Name
  12:   {
  13:     get { return name; }
  14:     set
  15:     {
  16:       if (name != value)
  17:       {
  18:         name = value;
  19:         RaisePropertyChanged(Person.Properties.Name);
  20:       }
  21:     }
  22:   }
  23:  
  24:   private int age;
  25:  
  26:   public int Age { 
  27:     get { return age; } 
  28:     set { 
  29:       if (age != value) { 
  30:         age = value; 
  31:         RaisePropertyChanged(Person.Properties.Age); 
  32:       } 
  33:     } 
  34:   }
  35: }

There has been much discussion going on on how to implement the setter of your property, mainly in how to pass the property name to the event. I like to use a nested “Properties” class that contains a const string for each property name. This way I find it easy to refactor my property since there are no more strings. Other people like to use reflection but I hate the runtime overhead this brings. This technique also makes is easier to register for PropertyChanged events from other objects. If each class has a nested Properties class, you can easily code find the name of each property using intelli-sense.

The Model.

Your model should be exactly that. The representation of your business data, such as lists of things. In my example the model is very simple; it contains a list of Person objects. In real life these would the several lists of interrelated objects, such as products, customers, their orders, etc… The model can also have methods implementing business functionality. Any changes to the model should trigger events notifying any controls of changes…

   1: public class PeopleModel /* : Entity */
   2: {
   3:   private ObservableCollection<Person> people
   4:     = new ObservableCollection<Person>()
   5:     { // Let's add some data to make it easier to verify data binding in view
   6:       new Person { Name = "Wesley", Age = 31 },
   7:       new Person { Name = "Dimitri", Age = 28 },
   8:       new Person { Name = "Gert", Age = 24 },
   9:       new Person { Name = "Peter", Age = 24 }
  10:     };
  11:  
  12:   public ObservableCollection<Person> People
  13:   {
  14:     get { return people; }
  15:   }
  16:  
  17:   /* and many more other collections and objects */
  18: }

Please note that normally the model would also implement INotifyPropertyChanged, but because this model doesn’t need it, I haven’t gone to the trouble… Uncommenting the Entity base class will not change any functionality in this example so if you want, go right ahead!

The ViewModel

For me the ViewModel is an adapter, that only exposes stuff so the view can only access what is necessary. For example the view will contain a list of people, will have a current selected person and two fields so you can create a new person. The ViewModel will use data binding to couple itself to the view, but doesn’t know any specific things about the controls used. It does however implement INotifyPropertyChanged so changes to the ViewModel will update the view:

   1: public class PersonVM : Entity
   2: {
   3:   private PeopleModel model;
   4:  
   5:   public PersonVM(PeopleModel m) { model = m; }
   6:  
   7:   public ObservableCollection<Person> People
   8:   {
   9:     get { return model.People; }
  10:   }
  11:  
  12:   private string name;
  13:   public string Name
  14:   {
  15:     get { return name; }
  16:     set
  17:     {
  18:       if (name != value)
  19:       { name = value; RaisePropertyChanged("Name"); }
  20:     }
  21:   }
  22:  
  23:   private int age;
  24:   public int Age
  25:   {
  26:     get { return age; }
  27:     set
  28:     {
  29:       if (age != value)
  30:       { age = value; RaisePropertyChanged("Age"); }
  31:     }
  32:   }
  33:   
  34:   private Person current;
  35:  
  36:   public Person Current
  37:   {
  38:     get { return current; }
  39:     set
  40:     {
  41:       if (current != value)
  42:       {
  43:         current = value;
  44:         RaisePropertyChanged("Current");
  45:       }
  46:     }
  47:   }
  48:  
  49:   public void DeleteCurrentPerson()
  50:   {
  51:     model.People.Remove(Current);
  52:     Current = model.People[0];
  53:   }
  54:  
  55:   public ICommand DeleteCommand
  56:   {
  57:     get { return new RelayCommand(DeleteCurrentPerson); }
  58:   }
  59:  
  60:   public ICommand AddCommand
  61:   {
  62:     get { return new RelayCommand(AddPerson); }
  63:   }
  64:  
  65:   public void AddPerson()
  66:   {
  67:     Person newPerson = new Person { Name = this.Name, Age = this.Age };
  68:     model.People.Add(newPerson);
  69:     Current = newPerson;
  70:   }
  71: }

So this ViewModel has a People property, which is the list we’re going to work with, a Current property to allow us to access the currently selected person (we’ll databind the selected item property of the list control to it), and a Name and Age property for entering new people. These properties will be data bound to two text boxes, so the user can enter stuff in the text boxes, but the command (which is on the viewmodel level) can access these properties, again not knowing which controls are being used.

NOTE: the RaisePropertyChanged is not implemented here without the PersonVM.Properties.Property technique. That is because for this demo I also created a code snippet to make it easier to type in properties that implement INotifyPropertyChanged. It’s very easy to create your own, I’ve actually uploaded a little video on how to do this.

The View

If you’d ask me what is the best thing in WPF, then I would say DataTemplate! Our UI is going to databind to the ViewModel and we’re going to associate the View using a DataTemplate. WPF will automatically select our view when it databinds to our ViewModel. You can do this as follows:

   1: <Window x:Class="ModelViewViewModelLab.Window1"
   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:     xmlns:viewModels="clr-namespace:ModelViewViewModelLab.ViewModels" 
   5:     xmlns:views="clr-namespace:ModelViewViewModelLab.Views"
   6:     Title="Window1" Height="300" Width="300">
   7:     <Window.Resources>
   8:         <!-- voor elk soort van viewmodel mappen we dit naar een view -->
   9:         <DataTemplate DataType="{x:Type viewModels:PersonVM }">
  10:             <views:PersonView />
  11:         </DataTemplate>
  12:     </Window.Resources>
  13:     <Grid>
  14:         <ContentControl Content="{Binding}" />
  15:     </Grid>
  16: </Window>

This way the view will be created with its DataContext set to the view model, so we can use DataContext relative data binding:

   1: <UserControl x:Class="ModelViewViewModelLab.Views.PersonView"
   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:     xmlns:model="clr-namespace:ModelViewViewModelLab.Models"
   5:     Height="300" Width="300">
   6:     <UserControl.Resources>
   7:         <DataTemplate DataType="{x:Type model:Person}">
   8:             <StackPanel Orientation="Vertical">
   9:                 <StackPanel Orientation="Horizontal">
  10:                     <TextBox Text="{Binding Name}" />
  11:                     <TextBlock Text=" - " />
  12:                     <TextBox Text="{Binding Age}" />
  13:                 </StackPanel>
  14:                 <ProgressBar Width="100" Height="16" Value="{Binding Age}" />
  15:             </StackPanel>
  16:         </DataTemplate>
  17:     </UserControl.Resources>
  18:     <Grid>
  19:         <Grid.ColumnDefinitions>
  20:             <ColumnDefinition />
  21:             <ColumnDefinition />
  22:         </Grid.ColumnDefinitions>
  23:         <!-- People listbox -->
  24:         <ListBox ItemsSource="{Binding People}" 
  25:                  Name="theList"
  26:                  SelectedItem="{Binding Current}" />
  27:         <!-- Command part -->
  28:         <StackPanel Orientation="Vertical" Grid.Column="1">
  29:             <ContentControl Content="{Binding Current}" />
  30:             <!-- New person -->
  31:             <TextBox Text="{Binding Name}" />
  32:             <TextBox Text="{Binding Age}" />
  33:             <Button Content="Add" Command="{Binding AddCommand, Mode=OneWay}" />
  34:             <Button Content="Delete" Command="{Binding DeleteCommand, Mode=OneWay}"/>
  35:         </StackPanel>
  36:     </Grid>
  37: </UserControl>

Note the buttons in the view; these are data bound to the RelayCommand instances on the view model. Clicking these will execute the associated command.

   1: public class RelayCommand : ICommand
   2: {
   3:   Action action;
   4:  
   5:   public RelayCommand(Action execute)
   6:   {
   7:     action = execute;
   8:   }
   9:  
  10:   public bool CanExecute(object parameter)
  11:   {
  12:     return true;
  13:   }
  14:  
  15:   public event EventHandler CanExecuteChanged;
  16:  
  17:   public void Execute(object parameter)
  18:   {
  19:     action();
  20:   }
  21: }

The Commands

RelayCommand is a (too) simple implementation of the command pattern in WPF, but it allows us to easily execute a method on the model or viewModel. Our viewModel uses it to expose two commands: add and delete:

   1: public ICommand DeleteCommand
   2: {
   3:   get { return new RelayCommand(DeleteCurrentPerson); }
   4: }
   5:  
   6: public ICommand AddCommand
   7: {
   8:   get { return new RelayCommand(AddPerson); }
   9: }

Thanks to delegates this is easy!

The commands each execute a method on the viewModel:

   1: public void AddPerson()
   2: {
   3:   Person newPerson = new Person { Name = this.Name, Age = this.Age };
   4:   model.People.Add(newPerson);
   5:   Current = newPerson;
   6: }

AddPerson requires a couple of inputs, the name and age of the new person to add; its gets these from the Name and Age properties on the ViewModel. How did these get filled in? The view has a Textbox data bound to each!

   1: public void DeleteCurrentPerson()
   2: {
   3:   model.People.Remove(Current);
   4:   Current = model.People[0];
   5: }

DeleteCurrentPerson will remove the currently selected person from the list of people. Again the Current property is data bound to the selectedItem property of the listbox, so when you select something from the listbox, the current property will be automatically updated. After deleting the current person, we select the first person from the list. Carefull, this will give a nice bug when the last person is removed from the list, but fixing this should be easy…

So, MVVM. That’s it. Of course you could add a lot using other patterns, but that is for another time…

Configuring your WFC and WF4 services using AppFabric

Configuring your services

Normally I configure my services using Visual Studio (and type-ing in the configuration as Xml) or using the WCF Service Configuration tool. AppFabric also allows you to configure your services, directly from IIS (making it a nice integrated experience!). The difference is in that AppFabric exposes the stuff an it-pro needs to look at the health of an application more… Developers are more interested in making it work, productions is more interested in keeping it working… <grin>

You can setup a persistance and tracking store (actually databases) to make your services trackable and durable. This will also make it easier (or less hard) to see why your service is no longer functioning the way it should. Of course you can still setup the System.Diagnostics tracing, but this again is more for developers.

Some preparations are needed

AppFabric uses the net.pipe protocol to manage your services (through standard endpoints), so you might need to enable this on IIS. Select your site, then select Edit Bindings…

image

The following window should open:

 image

If net.pipe is not listed, hit the Add… button and select net.pipe. Use * for Binding information.

Then go to your service and select Advanced Settings… The dialog should open:

image

Add net.pipe to the list of Enabled Protocols.

You might also need to run the AppFabric system-level configuration. To do this, go to Start->All Programs->Windows Server AppFabric->Configure AppFabric. The configuration utility should launch:

image

Hit Next:

image

Here you can configure the monitoring and persistance databases. Check the Set Monitoring configuration check-box, select the account you want to use and the provider (there is one default, which will store everything in a SQL server database:

image

Hit the Configure… button. Configure as follows (replacing Peter-PC with your domain/machine name):

image

Hit Ok. Check the results. You might get an ‘the database already exists’ kind of warning. Simply continue…

Continue through the wizard…

Configuring a WCF service

In IIS, select your site or service (and most of this can also be done at other levels), and then in the actions pane select “Manage WCF and WF Service->Configure…”

image

This opens the “Configure WCF and WF for Site” dialog:

image

Check the “Enable metadata over HTTP” to set the ServiceMetadata behavior.

Over to the Monitoring tab:

image 

Keep the checkbox checked if you want monitoring records written to the monitoring database. Using the level you can change from monitoring everything to nothing…

You can also configure the usual WCF tracing and message logging here.

The throttling tab allows you to limit the number of requests and service instances, while the security tab allows you to set/change the service certificate.

A later post will be about configuring WCF and Workflow services…

Windows Server AppFabric Beta 2: Deploying services

Microsoft released Visual Studio 2010 RC a while ago, but unfortunately this broke Windows Server AppFabric beta 1. Luckily march 1 MS released beta 2, which works with VS 2010 RC. I’ve installed it and will now try to show you a couple of things.

So what is AppFabric? To be honest, there is another AppFabric, the one for Azure, and that is not the one I am talking about.

What is Windows Server AppFabric?

AppFabric makes installing, administering, monitoring and fixing problems in WCF 4 (!Yes, only starting at .NET 4) services a lot easier by extending IIS and WAS (Windows Activation Services, which are used to host non-HTTP WCF services in IIS). It also adds a distributed caching mechanism (also known as Project Velocity) to make it easier to scale ASP.NET and WCF services. If you’re familiar with BizTalk 2006/2009, you’ll know that the BizTalk Administration application shows you each BizTalk application’s health, what went wrong, how many were executed, etc… AppFabric gives you the same but now for WCF and WF 4 services.

Look at this screen shot:

image

As you can see, after installing AppFabric IIS is now showing these new icons: AppFabric Dashboard, Endpoints and Services. The dashboard will show you the current status of your services (running, stopped, with errors, etc…). Endpoints and Services allow you to list and configure the endpoints and services.

Deploying using AppFabric

AppFabric Hosting Services provides easier deployment of services:

First thing you need to do is to package your WCF service. To do this go to the project properties and select the new Package/Publish tab:

image

You can now select where to create the package (and if your want it as a .zip file) and how to deploy it in IIS.

Now you need to create the deployment package in Visual Studio 2010:

image

Now we can import the application using IIS:

image

This will open the Import Application Package dialog. Use the browse button to open the package .zip file:

image

Hit next:

image

And Next again:

image

Note that the service name is taken from the package properties. Hit next again, hopefully your services will deploy successfully.

image

To verify this, you can go to your site in IIS:

image

And click on Services. You should see your service listed (for example I have three services running here):

image

You can also click on Endpoints to see the list of endpoints:

image

Because of WCF default endpoints you get 4 different endpoints per service; you can modify which types of default endpoints you want, but that is now what I’ll be showing you here.

 

A note on using your own application pool with AppFabric

During my experiments I created a new AppPool for my services. When testing my service, I would always get the following error:

HTTP Error 503. The service is unavailable.

First I thought the solution would be easy. My application pool was stopped. Starting it should fix the problem. But it didn’t.

So I investigated a little further. Seems that my new application pool tries to use .NET 4 version 21006 (beta 2?). I could see this in the Event Viewer:

The worker process failed to pre-load .Net Runtime version v4.0.21006.

I think something didn’t (un)install during my migration to .NET 4 RC. So I’m now using the ASP.NET 4 application pool…

Team System 2010: Easier project management with Team Project Collections

Team System 2010 introduces the concept of team project collections (TPC). A team project collection is, as it says, a collection of team projects, which can be managed individually. You can backup, move, delete, etc… each collection individually. Each collection will also have its unique work item ids, check sets, etc… Team project collections also change the way team foundation stores its stuff. Before it would use a bunch of databases, now everything connected is stored in a single database. One database per collection. You can easily find the database because it’s called Tfs_<CollectionName>. You ‘ll also find the Tfs_Configuration database containing all configured project collections (and depending on your installation a database for the analysis services).:

image

Project collections also solve a problem some of you might have encountered; TFS 2008 has an upper limit of 255 team projects. Now with TPC you just add another TPC when you reach the limit (I don’t know the limit of projects per collection, but I would assume it would be around the same…).

A TPC can also easily be moved to another team server/farm, or to another SQL server on the same farm, as long as you keep it on the same type of SQL server (enterprise, express, …). Documentation states you cannot move it to another kind. The way to do this is to first open the Team Foundation Administration Console, and select the Team Projects Collections tree item. To the right you should see all your TPCs.

image

Here you can also create new TPC's, but that should be obvious.

So to move a TPC you should first stop the collection. You’ll be asked for a reason:

image

And then you detach the collection:

image

Next you go through a verification step:

image

And then you click Complete:

image

Now the TPC is no longer connected to TFS, but is still there in SQL server.

image

So now you detach the database in SQL server, move it to another SQL server or TFS farm. You might first need to restart a couple of services, such as the build service.

So after attaching the database in SQL server, we now need to attach the database to TFS; go back to Team Foundation Administration Console, and click the “Attach Collection” button. Now choose your SQL server instance, and you’ll see all candidate databases:

image

Hit Next if you want to change properties such as the name/description:

image

And next again to see an overview.

So complete attaching, hit Verify to make sure everything is in order:

image

And then hit attach.

image 

Eh voila!

image

Now the TPC should be in the list:

image

You can also split the projects in a single TPC to multiple TPCs (but not merge them, so be careful), but that will be for a later post.