Friday, 4 March 2011

A day of WPF paired programming

Here’s a journal of code that was written in a paired programming session last week…

We started by looking at the FranchiseStepPayoutFunction Control. This control has some interesting behavior. Part of the control consists of a table of LowerLimit,UpperLimit and Payout. We would like that the Upper Limit of Row n populates the lower limit of Row n+1. We would also like to style the grid with characters like "-" between the upper and lower limit and a % for the payout.

Starting with the xaml, we decided to use a ItemControl to solve this:

        <ItemsControl ItemsSource="{Binding StepPayouts}" Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="4">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Vertical" />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
                        <TextBox Text="{Binding LowerStepLimit, Mode= TwoWay}" Width="100" Margin="0 0 10 0" />
                        <Label Content="-" Height="23" VerticalAlignment="Top" />
                        <TextBox Text="{Binding UpperStepLimit, Mode= TwoWay}" Width="100" Margin="0 0 10 0"/>
                        <TextBox Text="{Binding Payout, Mode= TwoWay}" Width="100" />
                        <Label Content="%" Height="23" VerticalAlignment="Top" />
                    </StackPanel>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>

This is bound to a List

    public class FranchiseStepPayouts : ModelSettingsBase
    {
        public List<StepPayout> StepPayouts { get; private set; }

        public FranchiseStepPayouts()
        {
            StepPayouts = new List<StepPayout>();

            // Populate 4 columns
            for (int i = 0; i < 4; i++)
            {
                StepPayout s = new StepPayout(0, 0, 0);
                s.UpperStepLimitChangedEvent += new StepPayout.UpperStepLimitChangedHandler(s_UpperStepLimitChangedEvent);
                StepPayouts.Add(s);
            }
        }

...
    }

The StepPayout looks like:

namespace Ccp.Wpf.Infrastructure.Entities
{
    public class StepPayout : NotificationObject
    {

        public delegate void PayoutChangedHandler(object sender);
        public event PayoutChangedHandler PayoutChangedEvent;
        virtual protected void PayoutChangedRaiseEvent()
        {
            if (PayoutChangedEvent != null)
            {
                PayoutChangedEvent(this);
            }
        }

        private double payout;
        public double Payout
        {
            get
            {
                return this.payout;
            }
            set
            {
                payout = value;
                RaisePropertyChanged(()=>Payout);
                PayoutChangedRaiseEvent();
            }
        }
        .. dito for Lower and Upper Step Payout limits

        public StepPayout(double UpperStepLimit, double LowerStepLimit, double Payout)
        {
            this.lowerStepLimit = LowerStepLimit;
            this.upperStepLimit = UpperStepLimit;
            this.payout = Payout;
        }
    }
}

Notice that we used a home made NotificationObject, this is so that we don't need to write a string in the RaisePropertyChanged field. Which means, instead of writing
                RaisePropertyChanged("Payout");
we can write
                RaisePropertyChanged(()=>Payout);

We copied the code that makes this possible from Prism. Our home made class for this looks like:

namespace Ccp.Wpf.Infrastructure.Helpers
{
    public class NotificationObject : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        protected void RaisePropertyChanged<T>(Expression<Func<T>> propertyExpression)
        {
            var propertyName = ExtractPropertyName(propertyExpression);
            this.RaisePropertyChanged(propertyName);
        }

        public static string ExtractPropertyName<T>(Expression<Func<T>> propertyExpression)
        {
            if (propertyExpression == null)
            {
                throw new ArgumentNullException("propertyExpression");
            }
            var memberExpression = propertyExpression.Body as MemberExpression;
            if (memberExpression == null)
            {
                throw new ArgumentException("NotMemberAccessExpression_Exception", "propertyExpression");
            }
            var property = memberExpression.Member as PropertyInfo;
            if (property == null)
            {
                throw new ArgumentException("ExpressionNotProperty_Exception", "propertyExpression");
            }
            var getMethod = property.GetGetMethod(true);
            if (getMethod.IsStatic)
            {
                throw new ArgumentException("StaticExpression_Exception", "propertyExpression");
            }
            return memberExpression.Member.Name;
        }
    }
}

Our application does not need to be localizable so we removed the references to resources.

The next thing that we looked at was the list that we used in the view model

    public class FranchiseStepPayouts : ModelSettingsBase
    {
        public List<StepPayout> StepPayouts { get; private set; }

This works well provided the number of items in the list does not change. If the number of items in the list changes you need to replace List with ObservableCollection and you need to RaisePropertyChanged so that the UI know it needs to update. If the list was very large this would lead to an avalanche of events that would make the UI unresponsive, in that case it is better to create the observable list and set the entire property in one go. In our case we only have a few items. This makes the code look like the following.

    public class FranchiseStepPayouts : ModelSettingsBase
    {

        private ObservableCollection<StepPayout> stepPayouts;
        public ObservableCollection<StepPayout> StepPayouts
        {
            get
            {
                return stepPayouts;
            }
            private set
            {
                stepPayouts = value;
                RaisePropertyChanged(() => StepPayouts);
            }
        }

        private PayOutFunction payoutFunction;

        public PayOutFunction PayoutFunction
        {
            get
            {
                return payoutFunction;
            }
            set
            {
                payoutFunction = value;
                RaisePropertyChanged(() => PayoutFunction);
            }
        }

We register the events in the constructor

        public FranchiseStepPayouts()
        {
            StepPayouts = new ObservableCollection<StepPayout>();

            // Populate 4 columns
            for (int i = 0; i < 4; i++)
            {
                StepPayout s = new StepPayout(0, 0, 0);
                s.UpperStepLimitChangedEvent += new StepPayout.UpperStepLimitChangedHandler(s_UpperStepLimitChangedEvent);
                StepPayouts.Add(s);
            }
        }

We respond to the events by replacing the lower limit of the n+1 column
        void s_UpperStepLimitChangedEvent(object sender)
        {
            for (int i = 0; i < this.StepPayouts.Count - 1; i++)
            {
                this.StepPayouts[i + 1].LowerStepLimit = this.StepPayouts[i].UpperStepLimit;
            }
        }

Next adding an auto hide function with checkbox

    public class FranchiseStepPayouts : ModelSettingsBase
    {

        private bool isPayoutFunctionVisible;

        public bool IsPayoutFunctionVisible
        {
            get
            {
                return isPayoutFunctionVisible;
            }
            set
            {
                isPayoutFunctionVisible = value;
                RaisePropertyChanged(() => IsPayoutFunctionVisible);
            }
        }

<UserControl x:Class="Ccp.Wpf.Infrastructure.Controls.FranchiseStepPayoutsView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:local="clr-namespace:Ccp.Wpf.Infrastructure.Controls"
             xmlns:converter="clr-namespace:Ccp.Wpf.Infrastructure.Converter"
             mc:Ignorable="d"
             d:DesignWidth="500">
    <UserControl.Resources>
        <local:EnumMatchToBooleanConverter x:Key="enumConverter" />
    </UserControl.Resources>

    <StackPanel Orientation="Vertical" Grid.Column="0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
        <CheckBox Content="Japanise Payout Function" IsChecked="{Binding IsPayoutFunctionVisible}"/>
        <GroupBox Header="Japanise Payout Function" Visibility="{Binding IsPayoutFunctionVisible, Converter={converter:BoolToVisibilityConverter FalseValue=Collapsed}}" VerticalAlignment="Top" HorizontalAlignment="Left">
            <Grid>

                <!-- Content -->

            </Grid>
        </GroupBox>
    </StackPanel>
</UserControl>

namespace Ccp.Wpf.Infrastructure.Converter
{
    public class BoolToVisibilityConverter : MarkupExtension, IValueConverter
    {
        public BoolToVisibilityConverter()
        {
            TrueValue = Visibility.Visible;
            FalseValue = Visibility.Collapsed;
        }

        public Visibility TrueValue { get; set; }
        public Visibility FalseValue { get; set; }

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            bool val = System.Convert.ToBoolean(value);
            return val ? TrueValue : FalseValue;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return TrueValue.Equals(value) ? true : false;
        }

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            return this;
        }
    }
}

Next here is the implementation of a radio button

<UserControl x:Class="Ccp.Wpf.Infrastructure.Controls.FranchiseStepPayoutsView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:local="clr-namespace:Ccp.Wpf.Infrastructure.Controls"
             xmlns:converter="clr-namespace:Ccp.Wpf.Infrastructure.Converter"
             mc:Ignorable="d"
             d:DesignWidth="500">
    <UserControl.Resources>
        <local:EnumMatchToBooleanConverter x:Key="enumConverter" />
    </UserControl.Resources>
...

                <StackPanel Orientation="Vertical"  HorizontalAlignment="Left"  Grid.Row="0" Grid.RowSpan="2" Grid.Column="0" Width="100">
                    <StackPanel Orientation="Horizontal"  HorizontalAlignment="Left"  >
                        <RadioButton Content="Franchise" GroupName="Franchise" Height="23"
                             IsChecked="{Binding Path=PayoutFunction, Mode=TwoWay,
                                                 Converter={StaticResource enumConverter},
                                                 ConverterParameter=Franchise}"  />
                        <Label Content=" " Height="23" VerticalAlignment="Top" />
                    </StackPanel>
                    <StackPanel Orientation="Horizontal"  HorizontalAlignment="Left"  >
                        <RadioButton Content="Step Payout" GroupName="Franchise" Height="23"
                             IsChecked="{Binding Path=PayoutFunction, Mode=TwoWay,
                                                 Converter={StaticResource enumConverter},
                                                 ConverterParameter=StepPayout}"  />
                        <Label Content=" " Height="23" VerticalAlignment="Top" />
                    </StackPanel>
                </StackPanel>
...

            </Grid>
        </GroupBox>
    </StackPanel>
</UserControl>

namespace Ccp.Wpf.Infrastructure.Controls
{
    public class EnumMatchToBooleanConverter : IValueConverter
    {
        public object Convert(object value, Type targetType,
                              object parameter, CultureInfo culture)
        {
            if (value == null || parameter == null)
                return false;

            string checkValue = value.ToString();
            string targetValue = parameter.ToString();
            return checkValue.Equals(targetValue,
                     StringComparison.InvariantCultureIgnoreCase);
        }

        public object ConvertBack(object value, Type targetType,
                                  object parameter, CultureInfo culture)
        {
            if (value == null || parameter == null)
                return null;

            bool useValue = (bool)value;
            string targetValue = parameter.ToString();
            if (useValue)
                return Enum.Parse(targetType, targetValue);

            return null;
        }
    }
}

namespace Ccp.Wpf.Infrastructure.Entities
{
    public enum PayOutFunction
    {
        None,
        Franchise,
        StepPayout
    }
}

namespace Ccp.Wpf.Infrastructure.Entities
{
    public class FranchiseStepPayouts : ModelSettingsBase
    {
        private PayOutFunction payoutFunction;

        public PayOutFunction PayoutFunction
        {
            get
            {
                return payoutFunction;
            }
            set
            {
                payoutFunction = value;
                RaisePropertyChanged(() => PayoutFunction);
            }
        }

Next here is how to call the wpf windows with a foriegn key (ExposureDataId)

Use the container to access the modelview of the WPF user control

Public Class frmCatFocusMain
    Implements IDisposable
..
   Private _container As CompositionContainer
..
    Public Sub New()

        'Dim directoryCatalog As New DirectoryCatalog(".")
        Dim iAggregateCatalog As New AggregateCatalog()

        iAggregateCatalog.Catalogs.Add(New AssemblyCatalog(Assembly.GetExecutingAssembly()))
        iAggregateCatalog.Catalogs.Add(New AssemblyCatalog(GetType(ViewFactory).Assembly))
        iAggregateCatalog.Catalogs.Add(New AssemblyCatalog(GetType(ModelSettingsService).Assembly))
        iAggregateCatalog.Catalogs.Add(New AssemblyCatalog(GetType(ModelSettingsForEarthquakeAfricaIndia).Assembly))
        'iAggregateCatalog.Catalogs.Add(New AssemblyCatalog(GetType(CommonModelSettingsView).Assembly))

        Dim batch As New CompositionBatch()
        batch.AddPart(Me)
        _container = New CompositionContainer(iAggregateCatalog)

        ViewFactory = New ViewFactory(_container)
        _container.ComposeExportedValue(Of ViewFactory)(ViewFactory)
        _container.ComposeParts(ViewFactory)
        _container.Compose(batch)
...
        InitializeComponent()
     End Sub
...
    Private Sub BtnNewRunModelWizard_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BtnNewRunModelWizard.Click
        Dim ExposureDataId As Integer = 12123
        Dim iWindow As Windows.Window = ViewFactory.CreateWindow(Of ModelSettingsView)()
        Dim viewModel As ModelSettingsViewModel = _container.GetExportedValueOrDefault(Of ModelSettingsViewModel)()
        viewModel.ExposureDataId = ExposureDataId
        iWindow.ShowDialog()
    End Sub

namespace Ccp.UI.ModelResults.Views.ModelSettings
{
    [Export(typeof(ModelSettingsViewModel))]
    //[PartCreationPolicy(CreationPolicy.NonShared)]
    public class ModelSettingsViewModel : ViewModelBase
    {
        private int exposureDataId;
        public int ExposureDataId
        {
            get
            {
                return exposureDataId;
            }
            set
            {
                exposureDataId = value;
                RaisePropertyChanged("ExposureDataId");
            }
        }

Next we populate the comboboxs by joining some tables using our POCO EF DAL with Linq then creating an observablecollection from the result

                var result = from av in this.databaseContext.GetAll<CatModel>()
                                 .Where(z => z.PerilId.Value.Equals(selectedModelPeril.PERIL_ID))
                                 .Where(z => ListOfImportedCatModels.Contains(z.Id))
                             join vf in this.databaseContext.GetAll<ModelRegion>()
                             on av.RegionId equals vf.RegionId
                             select vf;

                ModelRegions = new ObservableCollection<ModelRegion>(result);

Here's how joining the Lazy loaded collection of controls (via MEF) with meta data containing an enumeration that has a foriegn key to the corresponding model in our database. This is done within a setter….

                selectedModelRegion = value;
                CatModel Selected = databaseContext
                                    .Query<CatModel>()
                                    .Where(p => p.RegionId == selectedModelRegion.RegionId)
                                    .Where(p => p.PerilId == selectedModelPeril.PERIL_ID)
                                    .FirstOrDefault<CatModel>();

                var result = (from av in this.ModelSettings
                                 .Where(z => (int)z.Metadata.ModelType == Selected.Id)
                             select av).FirstOrDefault();

                SelectedModelSetting = result;

                RaisePropertyChanged("SelectedModelRegion");

Finally here is how we persist data

namespace Ccp.Contracts.Model
{
    public abstract class ModelSettingsBase : NotificationObject
    {
        public string Name
        {
            get { return this.GetType().Name; }
        }

        public abstract void Save(int ModelRunId);
        public abstract bool Validate();
    }
}

namespace Ccp.UI.ModelResults.Views.ModelSettings
{
    [Export(typeof(ModelSettingsViewModel))]
    //[PartCreationPolicy(CreationPolicy.NonShared)]
    public class ModelSettingsViewModel : ViewModelBase
    {
        public RelayCommand<ModelSettingsBase> SaveModelSettingsCommand
        {
            get
            {
                if (saveModelSettingsCommand == null)
                {
                    saveModelSettingsCommand = new RelayCommand<ModelSettingsBase>((ms) =>
                    {
                        // Save
                        int ModelRunId = 123;

                        ms.Save(ModelRunId);
                    }
                    , (ms) =>
                    {
                        // CanSave
                        return ms != null && ms.Validate();
                    });
                }

                return saveModelSettingsCommand;
            }
        }

namespace Ccp.Wpf.Infrastructure.Entities
{
    [CatModelExport(ModelType.EarthquakeAfricaIndia, typeof(ModelSettingsBase))]
    public class ModelSettingsForEarthquakeAfricaIndia : ModelSettingsBase
    {
        public CreditDeductible CreditDeductible { get; set; }
        public ZonalDeductibleByLOB ZonalDeductible3 { get; set; }

        public ModelSettingsForEarthquakeAfricaIndia()
        {
            CreditDeductible = new CreditDeductible();
            ZonalDeductible3 = new ZonalDeductibleByLOB();
        }
        /// <summary>
        /// Dummy implementation
        /// </summary>
        public override void Save(int ModelRunId)
        {
            CreditDeductible.Save(ModelRunId);
            ZonalDeductible3.Save(ModelRunId);
        }

        public override bool Validate()
        {
            return CreditDeductible.Validate() && ZonalDeductible3.Validate();
        }
    }
}

namespace Ccp.Wpf.Infrastructure.Entities
{
    public class CreditDeductible : ModelSettingsBase
    {
        public double Limit { get; set; }
        public double Deductible { get; set; }

        public override void Save(int ModelRunId)
        {
            // Update database here
        }

Monday, 14 February 2011

Swapping WPF controls using MVVMC aka MVVM+Controller

We have an application that uses WPF User Controls that we would like to dynamically change using a combobox within a pluggable architecture. The solution is based on MVVMC sometimes called MVVM+Controller.

We did this by using a SpecificViewContentProvider which as the name suggests provides a view model for a ContentPresenter that has been bound to a view model with a user control as an observable property. In our case the application is very specific therefore we did not mind coupling the View coupled to the controller. If we wanted to break this dependency we would need to use MVVMLite or Prism. Again in this case this would be an overkill, therefore we decided to leave this dependency. 

We where thinking of using MVVMLite in this application and there are some traces left, for this example it is not necessary. But frameworks like Prism and MVVMLite are very useful in simplifying applications that have complex controls. The idea is that the controls produce relay events that broadcast to anyone who is interested in there status. For example a complex tree view to complex controls to view different aspects of the application

We looked at how Research would like to build the individual controls. For reasons described in day 3 we cannot inherit xaml code, therefore if we wanted to have a base control we would have to only use code behind. In windows forms this was possible with visual inheritance. Since this is not possible within xaml the visual befit of inheritance is lost. Therefore we decided to take a different approach:

Most models different sets of controls. We decided a better approach would be to setup some custom controls like CreditDecductible, ZonalDeductibles etc and compose these within the control that is to be exported into the RunModelWizard.

Here is how we achieved this:

1. We create a user control within ArchitectureExample.PresentationLayer.WPF.Common
We make some binding eg {Binding Deductible, Mode= TwoWay}

<UserControl x:Class="ArchitectureExample.PresentationLayer.WPF.Common.Controls.CreditDeductibleView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             mc:Ignorable="d"
             d:DesignWidth="300">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Label Content="Deductible :" Grid.Column="0" Grid.Row="0"/>
        <TextBox Text="{Binding Deductible, Mode= TwoWay}" Grid.Column="1" Grid.Row="0"/>
        <Label Content="Limit :" Grid.Column="0" Grid.Row="1"/>
        <TextBox Text="{Binding Limit, Mode= TwoWay}" Grid.Column="1" Grid.Row="1"/>
    </Grid>
</UserControl>

We don't make separate ModelViews because this would be an overkill

2. Next we make our first injectable control ModelSettingsForEarthquakeAlaskaView.xaml within the Views/ModelSettings directory of ArchitectureExample.PresentationLayer.WPF.Client
The interesting line is
   <my:CreditDeductibleView Name="creditDeductibleView1" DataContext="{Binding CreditDeductible}" />

We bind the ScreditDeductible view to CreditDeducble

<UserControl x:Class="ArchitectureExample.PresentationLayer.WPF.Client.Views.ModelSettings.ModelSettingsForEarthquakeAlaskaView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             mc:Ignorable="d"
             d:DesignHeight="300" d:DesignWidth="300" xmlns:my="clr-namespace:ArchitectureExample.PresentationLayer.WPF.Common.Controls;assembly=ArchitectureExample.PresentationLayer.WPF.Common">
    <StackPanel>
        <my:CreditDeductibleView Name="creditDeductibleView1" DataContext="{Binding CreditDeductible}" />
    </StackPanel>
</UserControl>

3. In the code behind we this export this. In this way we make this available to the combo box via MEF as a dependency injection container

using System.ComponentModel.Composition;
using System.Windows.Controls;
using ArchitectureExample.BusinessLayer.Entities;

namespace ArchitectureExample.PresentationLayer.WPF.Client.Views.ModelSettings
{
    /// <summary>
    /// Interaction logic for ModelSettingsForModel2Control.xaml
    /// </summary>
    [CatModelExport(ModelType.EarthquakeAlaska, typeof(IModelSettingView))]
    public partial class ModelSettingsForEarthquakeAlaskaView : UserControl, IModelSettingView
    {
        public ModelSettingsForEarthquakeAlaskaView()
        {
            InitializeComponent();
        }
    }
}

4. The CatModelExport attribute is defined as:

namespace ArchitectureExample.BusinessLayer.Entities
{
    [MetadataAttribute]
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
    public class CatModelExportAttribute : ExportAttribute
    {
        public CatModelExportAttribute(ModelType modelType, Type type)
            : base(type)
        {
            this.ModelType = modelType;
        }
        public ModelType ModelType { get; private set; }
    }
}

(Here we had some problems in getting MEF to work because originally we used (Type type, ModelType modelType) resulting in nothing being exported into the container.

5. The ModelType is also defined in this assembly as
namespace ArchitectureExample.BusinessLayer.Entities
{
    public enum ModelType
    {
        None = 0,
        ...
        EarthquakeAlaska = 6,
        ...
    }
}

6. This is imported in ModelSettingsView

The interesting lines are the binding that is made to the SelectedModelSetting
<ContentPresenter x:Name="SpecificModelSetting" DataContext="{Binding SelectedModelSetting}" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"/>

This is set with the combobox control
<ComboBox x:Name="cmbModel" Grid.Column="1" Grid.Row="0" ItemsSource="{Binding ModelSettings}" SelectedItem="{Binding SelectedModelSetting, Mode=TwoWay}" DisplayMemberPath="Value.Name"/>

The OK button is bound to the Command SaveModelSettingsCommand. By the way, if we where programming in Silverlight we would need MVVMLite or Prism to do this because Silverlight does not support ICommand. Actually the code needed is quite small so you could role your own, but the easiest way is to take a widely used third party library like MVVMLight
<Button x:Name="btnOk" Content="OK" Margin="0 0 5 0" Command="{Binding SaveModelSettingsCommand}" CommandParameter="{Binding SelectedModelSetting.Value}"/>

<UserControl x:Class="ArchitectureExample.PresentationLayer.WPF.Client.Views.ModelSettings.ModelSettingsView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             mc:Ignorable="d"
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <Label Content="Model" Grid.Column="0" Grid.Row="0"/>
        <ComboBox x:Name="cmbModel" Grid.Column="1" Grid.Row="0" ItemsSource="{Binding ModelSettings}" SelectedItem="{Binding SelectedModelSetting, Mode=TwoWay}" DisplayMemberPath="Value.Name"/>

        <ContentPresenter x:Name="SpecificModelSetting" DataContext="{Binding SelectedModelSetting}" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"/>
        <StackPanel Orientation="Horizontal" Grid.Column="1" Grid.Row="2" HorizontalAlignment="Right">
            <Button x:Name="btnOk" Content="OK" Margin="0 0 5 0" Command="{Binding SaveModelSettingsCommand}" CommandParameter="{Binding SelectedModelSetting.Value}"/>
            <Button x:Name="btnCancel" Content="Cancel"/>
        </StackPanel>    
    </Grid>
</UserControl>

7. The code behind this imports the ViewFactory

namespace ArchitectureExample.PresentationLayer.WPF.Client.Views.ModelSettings
{
    [Export(typeof(ModelSettingsView))]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public partial class ModelSettingsView : UserControl
    {
        private ModelSettingsController controller;

        [Import(typeof(ViewFactory))]
        public ViewFactory ViewFactory { get; set; }

        [Import]
        [SuppressMessage("Microsoft.Design", "CA1044:PropertiesShouldNotBeWriteOnly", Justification = "Needs to be a property to be composed by MEF")]
        public ModelSettingsViewModel ViewModel
        {
            set
            {
                if (this.DataContext != value)
                {
                    this.DataContext = value;
                    controller = new ModelSettingsController(ViewFactory, value, this);
                }
            }
        }
        public ModelSettingsView()
        {
            InitializeComponent();
        }
    }
}

8. The View Factory contains and enumerable of Lazy<IModelSettingView, IModelSettingMetadata>

namespace ArchitectureExample.PresentationLayer.WPF.Client.Infrastructure
{
    public class ViewFactory
    {
        [ImportMany(typeof(IModelSettingView))]
        public IEnumerable<Lazy<IModelSettingView, IModelSettingMetadata>> ModuleSettingsViews { get; set; }

        private readonly CompositionContainer container;

        public ViewFactory(CompositionContainer container)
        {
            this.container = container;
        }

        public T GetView<T>(string viewName)
        {
            var view = this.container.GetExportedValueOrDefault<T>(viewName);
            if (view == null)
            {
                throw new InvalidOperationException(string.Format("Unable to locate view with name {0}.", viewName));
            }

            return view;
        }

        public IModelSettingView GetView(ModelType modelType)
        {                   
            //var view = this.container.GetExportedValues<Lazy<T, TMetaData>>().Where<Lazy<T, TMetaData>>(a => a.Metadata.ModelType == modelType).First();
            var view = ModuleSettingsViews.Where(a => a.Metadata.ModelType == modelType).First();
            if (view == null)
            {
                throw new InvalidOperationException(string.Format("Unable to locate view with type {0}.", modelType));
            }

            return view.Value;
        }

        public T GetView<T>()
        {
            var view = this.container.GetExportedValueOrDefault<T>();
            if (view == null)
            {
                throw new InvalidOperationException(string.Format("Unable to locate view with type {0}.", typeof(T).Name));
            }

            return view;
        }

        public Window CreateWindow<T>()
        {
            var view = this.GetView<T>();

            return CreateWindow<T>(view); ;
        }

        public Window CreateWindow<T>(T content)
        {
            var window = new Window();
            // window.DataContext = dataContext;

            window.Content = content;

            return window;
        }

        public ModelSettingsViewWithRegions CreateModelSettingsViewWithRegions()
        {
            IRegionManager regionManager = this.container.GetExportedValueOrDefault<IRegionManager>();
            ModelSettingsViewWithRegions view = new ModelSettingsViewWithRegions();// { DataContext = viewModel };
            this.container.ComposeParts(view);

            RegionManager.SetRegionManager(view, regionManager);
            RegionManager.UpdateRegions();
            return view;
        }
    }
}

Lets take a closer look ate the
        [ImportMany(typeof(IModelSettingView))]
        public IEnumerable<Lazy<IModelSettingView, IModelSettingMetadata>> ModuleSettingsViews { get; set; }

ImportMany asks MEF to populate the IEnumerable with exported objects that implement IModelSettingView 
If we take a look into the defintion of Lazy we see...

    [Serializable]
    public class Lazy<T, TMetadata> : Lazy<T>
...
        //
        // Summary:
        //     Initializes a new instance of the System.Lazy<T,TMetadata> class with the
        //     specified metadata that uses the specified function to get the referenced
        //     object.
        //
        // Parameters:
        //   valueFactory:
        //     A function that returns the referenced object.
        //
        //   metadata:
        //     The metadata associated with the referenced object.
        [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
        public Lazy(Func<T> valueFactory, TMetadata metadata);
...

So what this is saying is that this function provides an interface to the meta data that is added in our Attribute.

In our case the interface to the meta data is IModelSettingMetadata

namespace ArchitectureExample.BusinessLayer.Entities
{
    public interface IModelSettingMetadata
    {
        ModelType ModelType { get; }
    }
}

This meta data is needed to identify the control we want to import. Within the function GetView we use a linq expression to find the modelview that we are interested in. Since this is an enumeration of type lazy we need to use .value to instantiate the view model.

        public IModelSettingView GetView(ModelType modelType)
        {                   
            var view = ModuleSettingsViews.Where(a => a.Metadata.ModelType == modelType).First();
            if (view == null)
            {
                throw new InvalidOperationException(string.Format("Unable to locate view with type {0}.", modelType));
            }
            return view.Value;
        }

This is used in the ModelSettings Controller...

9. Here is the ModelSettingsController used in the MVVMC pattern

namespace ArchitectureExample.PresentationLayer.WPF.Client.Views.ModelSettings
{
    public class ModelSettingsController
    {
        private ViewFactory viewFactory;
        private ModelSettingsViewModel viewModel;
        private ModelSettingsView view;
        public ModelSettingsController(ViewFactory viewFactory,ModelSettingsViewModel viewModel, ModelSettingsView view)
        {
            this.viewFactory = viewFactory;
            this.viewModel = viewModel;
            this.view = view;
            //this.view.DataContext = viewModel;
//This listens to events created when the combobox changes
            this.viewModel.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(viewModel_PropertyChanged);
            UpdateSpecificModelSettingsView();
        }

        void viewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "SelectedModelSetting")
            {
                UpdateSpecificModelSettingsView();
            }
        }

        private void UpdateSpecificModelSettingsView()
        {
            if (this.viewModel.SelectedModelSetting != null)
            {
//==Here is where the Imported Enumeration of Lazy IModelSettingView are used
                var specificView = viewFactory.GetView(this.viewModel.SelectedModelSetting.Metadata.ModelType) as UserControl;
//Here we have to set the data context because we are changing the control
                specificView.DataContext = this.viewModel.SelectedModelSetting.Value;
//Here we populate the place holder with our view (tightly coupled)
                this.view.SpecificModelSetting.Content = specificView;

            }
        }

    }
}

10. The View model belonging to ModelSettingsView.xaml is ModelSettingsViewModel.cs
Inside this we expose Lazy Observable collections and selected values. Here we are using MVVMLite and the ViewModelBase. Actually we don't need to do this because WPF has an implementation of ICommand.

using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;

namespace ArchitectureExample.PresentationLayer.WPF.Client.Views.ModelSettings
{
    [Export(typeof(ModelSettingsViewModel))]
    //[PartCreationPolicy(CreationPolicy.NonShared)]
    public class ModelSettingsViewModel : ViewModelBase
    {
        private IModelSettingsService moduleSettingsService;
        private ObservableCollection<Lazy<ModelSettingsBase, IModelSettingMetadata>> modelSettings;
        private Lazy<ModelSettingsBase, IModelSettingMetadata> selectedModelSetting;

        private RelayCommand<ModelSettingsBase> saveModelSettingsCommand;

        public ObservableCollection<Lazy<ModelSettingsBase, IModelSettingMetadata>> ModelSettings
        {
            get
            {
                return modelSettings;
            }
            private set
            {
                if (modelSettings != value)
                {
                    modelSettings = value;

                    RaisePropertyChanged("ModelSettings");
                }
            }
        }

        public Lazy<ModelSettingsBase, IModelSettingMetadata> SelectedModelSetting
        {
            get
            {
                return selectedModelSetting;
            }
            set
            {
                if (selectedModelSetting != value)
                {
                    selectedModelSetting = value;

                    RaisePropertyChanged("SelectedModelSetting");
                    SaveModelSettingsCommand.RaiseCanExecuteChanged();
                }
            }
        }

        public RelayCommand<ModelSettingsBase> SaveModelSettingsCommand
        {
            get
            {
                if (saveModelSettingsCommand == null)
                {
                    saveModelSettingsCommand = new RelayCommand<ModelSettingsBase>((ms) =>
                    {
                        // Save
                        ms.Save();
                    }
                    , (ms) =>
                    {
                        // CanSave
                        return ms !=null && ms.Validate();
                    });
                }

                return saveModelSettingsCommand;
            }
        }

        [ImportingConstructor]
        public ModelSettingsViewModel(IModelSettingsService moduleSettingsService)
        {
            this.moduleSettingsService = moduleSettingsService;

            ModelSettings = new ObservableCollection<Lazy<ModelSettingsBase, IModelSettingMetadata>>(this.moduleSettingsService.GetModuleSettings());
            foreach (Lazy<ModelSettingsBase, IModelSettingMetadata> modelsettings in ModelSettings)
            {
                var test= modelsettings.Value;
            }
        }
   }
}

The interesting parts of the above are
         public RelayCommand<ModelSettingsBase> SaveModelSettingsCommand
Notice that in the can Execute Func we first chack if Ms !=null. Without this check first the function will throw an exception
                    , (ms) =>
                    {
                        // CanSave
                        return ms !=null && ms.Validate();
                    });

The ms.Validate part is invoking an implementation of an abstract class:

namespace ArchitectureExample.BusinessLayer.Entities
{
    /// <summary>
    /// This classes could be generated from a T4 template (pocos)
    /// </summary>
    public abstract class ModelSettingsBase
    {
        /// <summary>
        /// Just an example of a field
        /// </summary>
        public string Name
        {
            get { return this.GetType().Name; }
        }
        public abstract void Save();
        public abstract bool Validate();
    }
}

11. Here is where we have implemented this within
namespace ArchitectureExample.BusinessLayer.Entities
{
    public class CreditDeductible : ModelSettingsBase
    {
        public double Limit { get; set; }
        public double Deductible { get; set; }

        public CreditDeductible()
        {
            Limit = 100;
            Deductible = 0;
        }

        public override void Save()
        {
        }

        public override bool Validate()
        {
            return Limit <= 100 && Limit >= 0 && Deductible <= 100 && Deductible >= 0;
        }
    }
}

Notice that we decided to use a boolean to return validation. The alternative would have been to use an exception. We choose boolean because exceptions are slow because they need to serialize the stack trace.

There is a validation enterprise building block that uses attributes to set validation rules. We will look into using this because it provides a tidy way to associate validation rules to properties and will remove the untidy code in the Validate() function

We tested this with 2 imported controls with 1 and 2 of these user controls. The OK button of the main control was properly enabled and disabled according to the validation rules. Also as we changed the combo box the values from one custom control to another where correctly persisted...

Thursday, 30 December 2010

Improvements in number crunching speeds from .Net 3.5 to .Net 4

Here's something interesting: In a previous blog entry we found a 2 times speedup in the performance of a C# version of our Cat Models from .Net 3.5 to .Net 4.0. I followed up with Microsoft on this and got a very helpfull feedback from Surupa Biswas and Stephen Toub:

Hello again Nigel,

Someone on my team took a deeper look at this and was able to deterministically reproduce a ~2x speed up on his box. It looks like the primary wins are coming from the CRT, not the JIT. The 8.0/3.5 CRT was using x87 floating point instructions, but the 10.0/4.0 CRT is using SSE. The JIT uses the CRT for the Log/ Log10 and Exp calls. It seems like the SSE instructions used by the C runtime are the primary source of the wins although the JIT-ed code was better too.

.NET 3.5 also had the CRT installed in a global location (WinSxS) and hence could be affected by other applications that updated the CRT, which could explain the differences in our observations.

Thanks again for sharing your test case and reporting this to us.

Best,
Surupa


For the non technical:

JIT = Just In Time (it is the compiler that converts the IL Intermediate code (what we see as .exe file) into a native executable)
CRT = Common Runtime Library (It is all the libraries that the native code uses to interact with the hardware) This is a libray that is delivered with the framework and therefore has different versions:
.NET 2.0 -> CRT 8.0.50727.42
.NET 2.0 SP1 -> CRT 8.0.50727.762
.NET 3.5 -> CRT 9.0.21022.8
.NET 3.5 SP1 -> CRT 9.0.30729.1

I believe SSE means Streaming SIMD Extensions which are a set of processor extensions for Intel processors

From this web site http://neilkemp.us/src/sse_tutorial/sse_tutorial.html I found the following description of what SSE is
"First what the heck is SSE? Basically SSE is a collection of 128 bit CPU registers. These registers can be packed with 4 32 bit scalars after which an operation can be performed on each of the 4 elements simultaneously."

If I understand this correctly the .Net 4 takes advantage of certain processor extensions on the Intel processor via an improved version of the Common Runtime Library

Here's a great article over the CLR improvements on .Net 3.5 http://msdn.microsoft.com/en-us/magazine/dd569747.aspx

Tuesday, 21 December 2010

A WCF Hosting story

I have a VS2010 project that has a WCF service that is ready to be deployed. I now want to setup IIS7 to use WAS to host the WCF components. Here are the steps needed to do this

1. Goto Control Panel/Administrative Tools/Internet Information Services (IIS) Manager
2. Browse to Sites/Default Website
3. Right mouse click and "Add Virzual Directory..."
4. In the Add Virtual Directory
   - Alias : 05
   - Physical path: C:\InetPub\wwwroot\wmi\2010\12\05

(The objective is: To have a simple URL. Have the ability to version both the service and the namespaces. Monitor when decommissioning a service so as to prevent breaking applications [In our case done via logging in a base class])

5. Browse to Application Pools
6. Right mouse click on the list box and Add Application Pool....
7. Add Application Pool
   - Name :Wmi
   - .Net Framework v4.0.30319
   - Managed pipeine mode : Integrated
8. Right mouse click on the newly created WMI service account and select Advanced Settings
9. Under Process Model click on the "..." button next to Identity
10. Select Custom account and enter the service account details

At this point you could try and publish...
i Right mouse click on the ASP.NET project containing the WCF service
ii Enter
   - Publish profile: BulsburgProfile
   - Publish method: File Sysetm
   - Target location \\chbbpresxxx\wwwroot$\wmi\2010\12\05
Then if you enter the url to the service http://chbbpresxxx/wmi/Disk.svc you will get the following error

Server Error in '/' Application.
________________________________________
Runtime Error
Description: An application error occurred on the server. The current custom error settings for this application prevent the details of the application error from being viewed remotely (for security reasons). It could, however, be viewed by browsers running on the local server machine.

Details: To enable the details of this specific error message to be viewable on remote machines, please create a <customErrors> tag within a "web.config" configuration file located in the root directory of the current web application. This <customErrors> tag should then have its "mode" attribute set to "Off".

<!-- Web.Config Configuration File -->

<configuration>
    <system.web>
        <customErrors mode="Off"/>
    </system.web>
</configuration>

Notes: The current error page you are seeing can be replaced by a custom error page by modifying the "defaultRedirect" attribute of the application's <customErrors> configuration tag to point to a custom error page URL.

<!-- Web.Config Configuration File -->

<configuration>
    <system.web>
        <customErrors mode="RemoteOnly" defaultRedirect="mycustompage.htm"/>
    </system.web>
</configuration>

So now we add the following to Web.Config and republish
    <system.web>
        <customErrors mode="Off"/>
    </system.web>

Then you will get the following error:


Server Error in '/' Application.
________________________________________
The type 'Ccp.Wcf.Wmi.Disk', provided as the Service attribute value in the ServiceHost directive, or provided in the configuration element system.serviceModel/serviceHostingEnvironment/serviceActivations could not be found.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

The solution is to
11. Go back to the Internet Information Services (IIS) Manager
12. Right mouse click on the newly created virtual directory and select "Convert to Application"
13. - Alias: wmi
    - Application pool: wmi
    - Physical path: C:\InetPub\wwwroot\wmi\2010\12\05
Then it works...


Next I want to add the finishing touches to the web.config
    <system.serviceModel>
      <services>
        <service behaviorConfiguration="Ccp.Wcf.Wmi.DiskBehavior"
          name="Ccp.Wcf.Wmi.Disk">
          <endpoint address="" binding="wsHttpBinding" contract="Ccp.Wcf.Wmi.IDisk">
            <identity>
              <dns value="localhost" />
            </identity>
          </endpoint>
          <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
          <host>
            <baseAddresses>
              <!-- We don't need a base address when deploying to production -->
              <!--add baseAddress="http://localhost:8731/Design_Time_Addresses/Ccp.Wcf.Wmi/Disk/" /-->
            </baseAddresses>
          </host>
        </service>
      </services>

If you happen to try the same thing on IIS6 there are some differences:

1. Inside the Internet Information Services (IIS) Manager
2. Browse to Web Service Extentions and enable ASP.NET v4.0.30319
3. Repeat the excersize of creating the application pool and virtual directory
4. Copy the bin and the web.config file from C:\InetPub\wwwroot\wmi\2010\12\05 to C:\InetPub\wwwroot\

Then when you try to do some special WMI calls you will end up with some errors like : Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED)). In our case the IIS6 Server is a fringe server that will be updated to Server 2008

So now taking our system administrator hat off and putting our developer hat back on. We have an client app.config file that looks like:
            <endpoint address="http://chbbpresxxx.global.partnerre.net/Wmi/2010/12/05/Disk.svc"
                binding="wsHttpBinding" bindingConfiguration="DiskwsHttp"
                contract="WmiDeployedServiceReference.IDisk" name="DiskwsHttpBalsburg">
                <identity>
                    <dns value="localhost" />
                </identity>
            </endpoint>

NB the dns entry is necessary otherwise the service will not be found

The corresponding code is as follows:


        [TestMethod]
        public void GetFreeSpaceInGBWCfDeployed_CheckDiskCapacityOnC_StringContainingDiskCapacity()
        {
            WmiDeployedServiceReference.DiskClient proxy = new WmiDeployedServiceReference.DiskClient("DiskwsHttpBalsburg");

            string diskCapacityString = "";
            string serverName = Environment.MachineName;
            string driveLetter = "C";

            diskCapacityString = proxy.GetFreeSpaceInGB(serverName, driveLetter);

            long AvailableSpaceOnC = 0;

            DriveInfo d = new DriveInfo(driveLetter);
            AvailableSpaceOnC = d.AvailableFreeSpace;
            AvailableSpaceOnC = AvailableSpaceOnC / 1024 / 1024 / 1024;

            long diskCapacityLong = Convert.ToInt64(Convert.ToDouble(diskCapacityString));

            Assert.IsFalse(diskCapacityString == "");
            Assert.IsTrue(diskCapacityLong == AvailableSpaceOnC);

        }

Now I want to use NetTcp because it is more efficient than wsHttp.
In some early iterations after adding the netTcp binding when I try http://chbbpresxxx/wmi/2010/12/05/Disk.svc
I get the error like an error like:


Server Error in '/Wmi/2010/12/05' Application.
--------------------------------------------------------------------------------

Could not find a base address that matches scheme net.tcp for the endpoint with binding NetTcpBinding. Registered base address schemes are [http].
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

To fix this error you need to add the net.tcp binding to the binding of the application in IIS.
1. Right click the virtual directory/application in IIS -> Manage application -> Advanced settings.
2. On the Enabled Protocols : http,net.tcp

I tried out the WCF configuration editor to setup a simple net-Tcp binding to the existing contract and I publish it. Then when I open the http://chbbpresxxx/wmi/2010/12/05/Disk.svc I got the error:


Cannot load the X.509 certificate identity specified in the configuration.

The solution in my case was to comment out the certificate in the web.config


          <endpoint binding="wsHttpBinding" name="DiskwsHttp" contract="Ccp.Wcf.Wmi.IDisk"
            listenUriMode="Explicit">
            <identity>
              <dns value="localhost" />
              <!--certificateReference storeName="My" storeLocation="LocalMachine"
                x509FindType="FindBySubjectDistinguishedName" /-->
            </identity>
          </endpoint>
          <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"
            listenUriMode="Explicit">
            <identity>
              <!--certificateReference storeName="My" storeLocation="LocalMachine"
                x509FindType="FindBySubjectDistinguishedName" /-->
            </identity>
          </endpoint>

Alternatively you can follow the instructions in the following url to setup the certificate

http://wcfsecurity.codeplex.com/wikipage?title=How%20To%20-%20Create%20and%20Install%20Temporary%20Certificates%20in%20WCF%20for%20Message%20Security%20During%20Development&ProjectName=wcfsecurity


After some other edits for the wsHttp binding works but the net-tcp binding gives an error like

Could not connect to net.tcp://chbbpresxxx.global.partnerre.net:8731/Wmi/2010/12/05/Disk.svc. The connection attempt lasted for a time span of 00:00:01.1986602. TCP error code 10061: No connection could be made because the target machine actively refused it 10.102.65.150:8731.

This error had me stuck for a while, I tried a lot of things, all failed. Here is a list:
- Look at the Advanced settings of wwwroot and add http,net.tcp to the enabled protocols (as in the Virtual directory)
- Right mouse click on wwwroot and add Binding.
   - Modified existing binging from 808:* to 9* to 9001 and back
   - Adding net-tcp with 9001
- Under Server Manager/Configuration/Microsoft Fire Wall with.../ look at the properties and set Firewall status to off at doamin, private and public levels

The problem was the setup of Features where different. To fix this we have to put on our system administrator hat on and do the following:

1. Open the Server Manager
2. Browse to Server Manager/features
3. Add Under .Net Framework 3.0 Features (Installed)
       Under WCF Activation
       + HTTP Activation
       + Non HTTP Activations
4. The installation took some time

Now if we try the test client by:
1. D:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\WcfTestClient.exe
2. File/ Add Service
3. http://chbbpresxxx.global.partnerre.net/Wmi/2010/12/05/Disk.svc
We get the error


Error: Cannot obtain Metadata from http://chbbpresxxx.global.partnerre.net/Wmi/2010/12/05/Disk.svc
If this is a Windows (R) Communication Foundation service to which you have access, please check that you have enabled metadata publishing at the specified address.  For help enabling metadata publishing, please refer to the MSDN documentation at http://go.microsoft.com/fwlink/?LinkId=65455.WS-Metadata Exchange etc etc

I found a link that describes what is happening

http://blogs.msdn.com/b/webtopics/archive/2010/04/28/system-typeloadexception-for-system-servicemodel-activation-httpmodule-in-asp-net-4.aspx

Installation of .NET 3.5.1 WCF HTTP activation feature adds a global module for the 3.0 framework’s 'System.ServiceModel’ assembly for the type 'System.ServiceModel.Activation.HttpModule'. Since the application pool’s runtime version is v4.0, this assembly is tried to be loaded from the .NET 4 assemblies folder. Since, the definition of the 'System.ServiceModel.Activation.HttpModule’ is now moved to the “System.ServiceModel.Activation” assembly, it fails.

Following the instructions the to fix this open a command prompt:

 
C:\>cd C:\Windows\Microsoft.NET\Framework\v4.0.30319
C:\Windows\Microsoft.NET\Framework\v4.0.30319>aspnet_regiis -iru
Start installing ASP.NET (4.0.30319).
..................................
Finished installing ASP.NET (4.0.30319).

Then reboot the server...
By the way the following error happens when I tried adding a Binding in the IIS Manager for net-tcp port 9001

The protocol binding '9001' does not conform to the syntax for 'net.tcp'. The following is an example of valid 'net.tcp' protocol bindings: '808:*'.

The solution is to remove the added net-tcp binding from the IIS Server Manager.


The Final Solution with our developer hat on


We use baseAddress="net.tcp://localhost:8080/Wmi/2010/12/05/Disk.svc" in the Web.config that looks like:

<?xml version="1.0"?>
<configuration>
    <system.web>
        <compilation debug="true" targetFramework="4.0" />
      <customErrors mode="Off"/>
    </system.web>

    <system.serviceModel>
      <services>
        <service behaviorConfiguration="Ccp.Wcf.Wmi.DiskBehavior" name="Ccp.Wcf.Wmi.Disk">
          <clear />
          <endpoint binding="wsHttpBinding" name="DiskwsHttp" contract="Ccp.Wcf.Wmi.IDisk"
            listenUriMode="Explicit">
            <identity>
              <dns value="localhost" />
            </identity>
          </endpoint>
          <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"
            listenUriMode="Explicit">
            <identity>
            </identity>
          </endpoint>
          <endpoint address=""
            binding="netTcpBinding"  name="DisknetTcp" contract="Ccp.Wcf.Wmi.IDisk" >
            <identity>
              <dns value="localhost" />
            </identity>
          </endpoint>
          <host>
            <baseAddresses>
              <!-- We don't need a base address when deploying to production -->
              <add baseAddress="net.tcp://localhost:8080/Wmi/2010/12/05/Disk.svc" />
            </baseAddresses>
          </host>

        </service>
      </services>
      <behaviors>
        <serviceBehaviors>
          <behavior name="Ccp.Wcf.Wmi.DiskBehavior">
            <!-- To avoid disclosing metadata information,
          set the value below to false and remove the metadata endpoint above before deployment -->
            <serviceMetadata httpGetEnabled="True"/>
            <!-- To receive exception details in faults for debugging purposes,
          set the value below to true.  Set to false before deployment
          to avoid disclosing exception information -->
            <serviceDebug includeExceptionDetailInFaults="true" />
          </behavior>
        </serviceBehaviors>
      </behaviors>
      <bindings>
        <netTcpBinding>
          <binding name="ReliableSessionBinding">
            <reliableSession ordered="false" inactivityTimeout="00:10:00" enabled="true" />
          </binding>
          <binding name ="DisknetTcp">
          </binding>
        </netTcpBinding>
      </bindings>
      <client>
        <endpoint address="net.tcp://services-tst.global.partnerre.net/Group/Common/Logging/2009/02/11/LogService.svc"
             binding="netTcpBinding" bindingConfiguration="ReliableSessionBinding"
             contract="LogServiceReference.ILogService" >
          <identity>
            <servicePrincipalName value="host/CHBBPRES563.global.partnerre.net" />
          </identity>
        </endpoint>
      </client>
    </system.serviceModel>
</configuration>

We use address="net.tcp://chbbpresxxx.global.partnerre.net/Wmi/2010/12/05/Disk.svc"in the App.config, that ends up looking like:


<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <client>
            <endpoint address="http://chbbpresxxx.global.partnerre.net/Wmi/2010/12/05/Disk.svc"
                binding="wsHttpBinding" bindingConfiguration="DiskwsHttp"
                contract="WmiDeployedServiceReference.IDisk" name="DiskwsHttpBalsburg">
                <identity>
                    <dns value="localhost" />
                </identity>
            </endpoint>
            <endpoint address="http://localhost:8732/Design_Time_Addresses/Ccp.Wcf.Wmi/Disk/"
                binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IDisk"
                contract="WmiServiceReference.IDisk" name="WSHttpBinding_IDisk">
                <identity>
                    <dns value="localhost" />
                </identity>
            </endpoint>
            <endpoint address="net.tcp://localhost:8731/Wmi/2010/12/05/Disk"
                binding="netTcpBinding" contract="WmiServiceReference.IDisk"
                name="NetTcpBinding_IDisk">
                <identity>
                    <dns value="localhost" />
                </identity>
            </endpoint>
            <endpoint address="http://chbbpresxxx.global.partnerre.net/Wmi/2010/12/05/Disk.svc"
                binding="wsHttpBinding" bindingConfiguration="DiskwsHttp1"
                contract="WmiDeployedServiceReference.IDisk" name="DiskwsHttp">
                <identity>
                    <dns value="localhost" />
                </identity>
            </endpoint>
            <endpoint address="net.tcp://chbbpresxxx.global.partnerre.net/Wmi/2010/12/05/Disk.svc"
                binding="netTcpBinding"
                contract="WmiDeployedServiceReference.IDisk" name="DisknetTcp">
                <identity>
                    <dns value="localhost" />
                </identity>
            </endpoint>
        </client>
    </system.serviceModel>
</configuration>

And the unit test looks like:
        [TestMethod]
        public void GetFreeSpaceInGBWCfDeployedTcp_CheckDiskCapacityOnC_StringContainingDiskCapacity()
        {
            WmiDeployedServiceReference.DiskClient proxy = new WmiDeployedServiceReference.DiskClient("DisknetTcp");

            string diskCapacityString = "";
            string serverName = Environment.MachineName;
            string driveLetter = "C";

            diskCapacityString = proxy.GetFreeSpaceInGB(serverName, driveLetter);

            long AvailableSpaceOnC = 0;

            DriveInfo d = new DriveInfo(driveLetter);
            AvailableSpaceOnC = d.AvailableFreeSpace;
            AvailableSpaceOnC = AvailableSpaceOnC / 1024 / 1024 / 1024;

            long diskCapacityLong = Convert.ToInt64(Convert.ToDouble(diskCapacityString));

            Assert.IsFalse(diskCapacityString == "");
            Assert.IsTrue(diskCapacityLong == AvailableSpaceOnC);

        }