Wednesday, 5 December 2012

Simple Metadata Driven Linq To Sql Type Generator

As part of a larger body of work, I implement a “Dynamic” Linq to Sql Type generator that was based on metadata. A number of people have asked about the source code for this generator so I have decided to publish this portion of the code as a stand alone component.

DumpingCoreMemory.Data.Linq.Generation assembly

  • LinqToSqlTypeGenerator: This class generates the types based on metadata provided at runtime.
  • EntityDescriptor: Instances of this class define entities that the LinqToSqlTypeGenerator class will generate concrete runtime types for
  • EntityPropertyDescriptor: Instances of this class define properties of the concrete runtime types that the LinqToSqlTypeGenerator will generate
ClassDiagram

How To Use the Type Generator

Included in the attached source code zip file is a contrived example, which briefly demonstrates how the type generator can be used. The example assumes a database which contains a table called TableA which contains three columns Id, ColumnA and ColumnB. In the example code this table is to be mapped to a Type called EntityA with three properties Identity, PropertyA and PropertyB. The type EntityA is to be derived from an interface IEntity. This is to enable demonstration of one of the ways a generated Type can be manipulated. The code for the mapping is as follows:
private static List<EntityDescriptor> GenerateEntityDescriptors()
{
 var entityDescriptors = new List<EntityDescriptor>
 {
  new EntityDescriptor
   {
    BaseType = typeof (IEntity),
    EntityName = "EntityA",
    TableName = "TableA",
    EntityProperties = new List<EntityPropertyDescriptor>
       {
        new EntityPropertyDescriptor
         {
          ColumnName = "Id",
          Name = "Identity",
          Type = typeof (Int32),
          IsIdentity = true
         },
        new EntityPropertyDescriptor
         {
          ColumnName = "ColumnA",
          Name = "PropertyA",
          Type = typeof (String)
         },
        new EntityPropertyDescriptor
         {
          ColumnName = "ColumnB",
          Name = "PropertyB",
          Type = typeof (Int32)
         }
       },
   }
 };
 return entityDescriptors;
}

The generator is invoked which generates the types, in the example I pass in an assembly file name, this is not necessary but for the purpose of the example it is useful as we can have a look at the generated types.
var entityDescriptors = GenerateEntityDescriptors();
var generator = new LinqToSqlTypeGenerator();
IList<Type> generatedTypes;

#warning Ensure that the process that invokes this method has rights to write to the disk
// Passing the assemblyFileName parameter is not necessary. 
// The generator will write the assembly to the specified filename.
// This allows us to reuse the generated types or just take a look at them with ILSpy
generator.GenerateTypes("LinqToSqlGeneratedTypes", "LinqToSqlGeneratedTypesAssembly.dll",
      entityDescriptors,
      out generatedTypes);

Using ILSpy we can inspect the generated code that was written to the assembly LinqToSqlGeneratedTypesAssembly.dll.

GeneratedCode

As one would expect we see a simple object with mapping attributes to the underlying database table called TableA. The next step is to activate and use the type for this we have a number of options:
  1. Statically reference the type, this is not shown in the test application as it is trivial to reference the assembly and instantiate its types. It also kind of defeats the purpose of generating types dynamically
  2. Cast to a known base type, in the test application the base type of the generated Type was specified as IEntity. The instance of the type is cast to an IEntity type so that properties can be accessed, the EntityDescriptor for the type specified a matching property for the IEntity interfaces specified Identity property
  3. Use a dynamic type to contain the type. This allows bypass of static type checking to allow access to properties of a type at runtime
  4. Use reflection to get or set properties of the underlying instance, using the name of the property for access

The following code snippet shows instantiation of an instance of the generated type and access by options 2,3 and 4.
object instance = Activator.CreateInstance(generatedTypes[0]);

var instanceAsIEntity = (IEntity) instance;
dynamic o = instance;

Console.WriteLine("Accessed as interface: {0}", instanceAsIEntity.Identity);
Console.WriteLine("Accessed as dynamic: {0}", o.Identity);
Console.WriteLine("Accessed by reflection: {0}", GetPropertyValueByReflection(instance, "Identity"));

Persisting instances of the types to a database is straight forward. The method PersistEntity in the test application shows how to insert an instance to a database.
private static void PersistEntity(object instance)
{
 using (var sqlConnection = new SqlConnection("Server=localhost;Database=Test;Trusted_Connection=True;"))
 {
  using (var context = new DataContext(sqlConnection))
  {
   ITable table = context.GetTable(instance.GetType());

   table.InsertOnSubmit(instance);

   context.SubmitChanges();
  }    
 }
}

For simplicity the code sets the properties via the dynamic object reference. In a real world example the instance may be bound to a UI control prior to CRUD operations being performed.

Limitations


  • There is no abstraction of the underlying types from the data store. So if the underlying column is of type nvarchar then the property of the generated entity must be a String. The generator does not support type coercion or conversion which can get messy. The WCF service that allows the definition of the types metadata ensures that this cannot occur
  • There is no abstraction from the underlying data stores foreign key relationships. So if a type is mapped to a table that requires a foreign key value to be specified which is not exposed via the generated type then new rows cannot be inserted
  • There is no support for nested relationships. i.e a Thing contains a list of Parts. For the use cases of the overall project this is not a key requirement and can be added with more elaborate metadata and a change to the type generator
  • Thursday, 4 October 2012

    Linq To Entities query with Nullable<Guid> exception

    While developing a WCF service I came across one of those runtime errors where the exception details are obscure and provide no real hint as to what one is doing wrong in the code.  The service was exposing data and the get methods of the service supported a simple paging continuation mechanism based on the previous set of data retrieved from the service.
    Exception: System.NotSupportedException: Unable to create a constant value of type 'System.Object'. Only primitive types ('such as Int32, String, and Guid') are supported in this context.   at System.Data.Objects.ELinq.ExpressionConverter.ConstantTranslator.TypedTranslate(ExpressionConverter parent, ConstantExpression linq)
       at System.Data.Objects.ELinq.ExpressionConverter.BinaryTranslator.TypedTranslate(ExpressionConverter parent, BinaryExpression linq)
       at System.Data.Objects.ELinq.ExpressionConverter.TranslateLambda(LambdaExpression lambda, DbExpression input)
       at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.OneLambdaTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, DbExpression& source, DbExpressionBinding& sourceBinding, DbExpression& lambda)
       at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.OneLambdaTranslator.Translate(ExpressionConverter parent, MethodCallExpression call)
       at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter parent, MethodCallExpression linq)
       at System.Data.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)
       at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.UnarySequenceMethodTranslator.Translate(ExpressionConverter parent, MethodCallExpression call)
       at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter parent, MethodCallExpression linq)
       at System.Data.Objects.ELinq.ExpressionConverter.Convert()
       at System.Data.Objects.ELinq.ELinqQueryState.GetExecutionPlan(Nullable`1 forMergeOption)
       at System.Data.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)
       at System.Data.Objects.ObjectQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator()

    The method that the client invokes is the following:
    public IList<DataContracts.TBL_Incident> GetIncidents(Guid? skipToken)
    {
        List<DataContracts.TBL_Incident> result = new List<DataContracts.TBL_Incident>();
    
        ExceptionHandledOperation(delegate
        {
            using (IContextProxy context = _contextFactory.CreateObjectContext())
            {
                IQueryable<Domain.EntityModel.TBL_Incident> incidents;
    
                if (!skipToken.HasValue)
                {
                    incidents = (from i in context.TBL_Incident
                                 orderby i.IncidentId
                                 select i).Take(EntityModelServiceSettings.Current.EntitySetPageSize);
                }
                else
                {
                    incidents = (from i in context.TBL_Incident
                                 orderby i.IncidentId
                                 where i.IncidentId.CompareTo(skipToken) > 0
                                 select i).Take(EntityModelServiceSettings.Current.EntitySetPageSize);
                }
    
                foreach (var i in incidents)
                {
    #warning optimise generated method so that this can be done in less LOC
                    var mappedIncident = new DataContracts.TBL_Incident();
                    DataContracts.TBL_Incident.MapTBL_Incident(i, mappedIncident);
                    result.Add(mappedIncident);
                }
            }
        });
    
        return result;
    }
    

    The skipToken parameter allows the client to pass the last identifier from the previous page retrieved from the service.
    sw.Start();
    
    var incidents = client.GetIncidents(null);
    
    Console.WriteLine("Set: {0} Time: {1}", incidents.Count(), sw.Elapsed);
    
    incidents = client.GetIncidents(incidents.Last().IncidentId);
    
    Console.WriteLine("Set: {0} Time: {1}", incidents.Count(), sw.Elapsed);

    The cause of the exception is the service side statement that appends the skipToken to the query.
    incidents = (from i in context.TBL_Incident
                orderby i.IncidentId
                where i.IncidentId.CompareTo(skipToken) > 0
                select i).Take(EntityModelServiceSettings.Current.EntitySetPageSize);

    The problem is that the compiler does not have a problem with the fact that the call passes the skipToken which is of type Nullable<Guid>. The problem is when the LINQ to Entity classes attempt to map the expression to a SQL expression.

    To fix the problem it is simply a case of passing the skipToken.Value to the CompareTo() method.
    incidents = (from i in context.TBL_Incident
                orderby i.IncidentId
                where i.IncidentId.CompareTo(skipToken.Value) > 0
                select i).Take(EntityModelServiceSettings.Current.EntitySetPageSize);

    Tuesday, 7 August 2012

    WCF Data Services NullReferenceException browsing metadata

    I have recently discovered an issue with malformed Uri base addresses and WCF Data Services when querying the metadata for the service.
    The issue causes an exception in the System.Data.Services.HttpContextServiceHost class which causes a http 500 in the client browser. Searching the internet did not yield much additional information in this problem.


    wcfdataservicesexception

    The offending line in the HttpContextServiceHost is the when the code accesses the UriTemplateMatch property, which is null, a NullReferenceException is thrown.

    internal void VerifyQueryParameters()
           {
               HashSet<string> set = new HashSet<string>(StringComparer.Ordinal);
              NameValueCollection queryParameters = this.operationContext.IncomingRequest.UriTemplateMatch.QueryParameters;
    
    
    To discover the reason why this property is null, I need to debug much further back in the request processing phase of the WCF Data Services stack.

    Problem has its root in the the public string SelectOperation(ref Message message) of the System.ServiceModel.Dispatcher.WebHttpDispatchOperationSelector class. This operation is called during the http request that is made to the base address. You can see from the call stack below:

    image

    From what I understand from stepping through the code the method public string SelectOperation(ref Message message) is attempting to determine the operation to invoke from the request message. The matched operation is then assigned to the message properties collection which is accessed later, via the OperationContext.IncomingRequest.UriTemplateMatch. The method public string SelectOperation(ref Message message) makes a call to the method  protected virtual string SelectOperation(ref Message message, out bool uriMatched) which in turn calls an internal private method private bool CanUriMatch(UriTemplateTable methodSpecificTable, Uri to, HttpRequestMessageProperty prop, Message message, out string operationName) it is this method where the failure to match occurs and thus the OperationContext.IncomingRequest.UriTemplateMatch property is null.
    public string SelectOperation(ref Message message)
    {
        bool flag;
        if (message == null)
        {
            throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("message");
        }
        string property = this.SelectOperation(ref message, out flag);
        message.Properties.Add("UriMatched", flag);
        if (property != null)
        {
            message.Properties.Add("HttpOperationName", property);
            if (DiagnosticUtility.ShouldTraceInformation)
            {
                TraceUtility.TraceEvent(TraceEventType.Information, 0xf0025, SR2.GetString(SR2.TraceCodeWebRequestMatchesOperation, new object[] { message.Headers.To, property }));
            }
        }
        return property;
    }
    protected virtual string SelectOperation(ref Message message, out bool uriMatched)
    {
        if (message == null)
        {
            throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("message");
        }
        uriMatched = false;
        if (this.methodSpecificTables != null)
        {
            UriTemplateTable table;
            if (!message.Properties.ContainsKey(HttpRequestMessageProperty.Name))
            {
                return this.catchAllOperationName;
            }
            HttpRequestMessageProperty requestProp = message.Properties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty;
            if (requestProp == null)
            {
                return this.catchAllOperationName;
            }
            string method = requestProp.Method;
            Uri to = message.Headers.To;
            if (to == null)
            {
                return this.catchAllOperationName;
            }
            if (this.helpUriTable != null)
            {
                UriTemplateMatch match = this.helpUriTable.MatchSingle(to);
                if (match != null)
                {
                    uriMatched = true;
                    this.AddUriTemplateMatch(match, requestProp, message);
                    if (method == "GET")
                    {
                        return "HelpPageInvoke";
                    }
                    WebHttpDispatchOperationSelectorData property = new WebHttpDispatchOperationSelectorData {
                        AllowedMethods = new List<string> { "GET" }
                    };
                    message.Properties.Add("HttpOperationSelectorData", property);
                    return this.catchAllOperationName;
                }
            }
            if (this.methodSpecificTables.TryGetValue(method, out table))
            {
                string str2;
                uriMatched = this.CanUriMatch(table, to, requestProp, message, out str2);
                if (uriMatched)
                {
                    return str2;
                }
            }
            if (this.wildcardTable != null)
            {
                string str3;
                uriMatched = this.CanUriMatch(this.wildcardTable, to, requestProp, message, out str3);
                if (uriMatched)
                {
                    return str3;
                }
            }
            if (this.ShouldRedirectToUriWithSlashAtTheEnd(table, message, to))
            {
                return "";
            }
            List<string> list2 = null;
            foreach (KeyValuePair<string, UriTemplateTable> pair in this.methodSpecificTables)
            {
                if (((pair.Key != method) && (pair.Key != "*")) && (pair.Value.MatchSingle(to) != null))
                {
                    if (list2 == null)
                    {
                        list2 = new List<string>();
                    }
                    if (!list2.Contains(pair.Key))
                    {
                        list2.Add(pair.Key);
                    }
                }
            }
            if (list2 != null)
            {
                uriMatched = true;
                WebHttpDispatchOperationSelectorData data2 = new WebHttpDispatchOperationSelectorData {
                    AllowedMethods = list2
                };
                message.Properties.Add("HttpOperationSelectorData", data2);
            }
        }
        return this.catchAllOperationName;
    }
    private void AddUriTemplateMatch(UriTemplateMatch match, HttpRequestMessageProperty requestProp, Message message)
    {
        match.SetBaseUri(match.BaseUri, requestProp);
        message.Properties.Add("UriTemplateMatchResults", match);
    }
    private bool CanUriMatch(UriTemplateTable methodSpecificTable, Uri to, HttpRequestMessageProperty prop, Message message, out string operationName)
    {
        operationName = null;
        UriTemplateMatch match = methodSpecificTable.MatchSingle(to);
        if (match != null)
        {
            operationName = match.Data as string;
            this.AddUriTemplateMatch(match, prop, message);
            return true;
        }
        return false;
    }

    When the Uri is matched the matched property is assigned to the “UriTemplateMatchResults” property of the request message. It is this property that is accessed by the OperationContext.IncomingRequest.UriTemplateMatch property and is the reason that it is returned as null and the cause of the exception.

    Wednesday, 18 July 2012

    WIX Registry Key Exists Custom Action

    The RegistrySearch Element in WIX has a bug where by you cannot check the existence of a Key with out a value. ClickOnce installers with a custom bootstrapper manifest also inherits this issue as I believe that it is a problem in the underlying Windows Installer.
    For a deployment component that I am currently building for an application I have a requirement to check if the .Net Platform Update 1 is installed as per the instructions here.

    The key in question is HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v4.0.30319\SKUs\.NETFramework,Version=v4.0.1, which has no default value.

    After taking a look around on the internet I could not find a code snippet that was flexible and reusable. Most where simple hard coded examples on how to work around the problem. So I decided to build my own Custom Action and add it to an assembly of custom actions that I share and reuse between deployment components.

    The Custom Action

    The code is pretty straight forward. A key name, as specified by the session property REGKEY, is opened from the registry hive as specified by REGHIVE session property. The session property REGKEYEXISTS is used to store the result of the check.

    Using the Custom Action


    To use the custom action in an installer first embed the custom action as a Binary Element.
    < SourceFile="$(var.CustomActions.TargetDir)\Installer.CustomActions.CA.dll" CustomActions?>Then define the Custom Action and sequence it for execution, in this case it is before LaunchConditions.
    
    
    <CustomAction Id="CheckRegistryKeyExists" BinaryKey="CustomActions" DllEntry="CheckRegistryKeyExists" Execute="immediate" Return="check" />
    <InstallUISequence>
      <Custom Action="CheckRegistryKeyExists" Before="LaunchConditions">NOT Installed</Custom>
    </InstallUISequence>
    
    
    Then specify the required properties and setup the condition and message.
    <Property Id="REGHIVE">HKLM</Property>
    <Property Id="REGKEYEXISTS">0</Property>
    <Condition Message='!(loc.Update401Missing)'>Installed OR REGKEYEXISTS="1"</Condition>
    
    

    When the custom action is run with logging msiexec /i Workflow.Designer.Installer.msi /lv out.txt the following output is displayed to aid with debugging.

    Action start 14:38:41: CheckRegistryKeyExists.
    MSI (c) (A0:FC) [14:38:41:385]: Invoking remote custom action. DLL: C:\MSIA543.tmp, Entrypoint: CheckRegistryKeyExists
    MSI (c) (A0:24) [14:38:41:387]: Cloaking enabled.
    MSI (c) (A0:24) [14:38:41:387]: Attempting to enable all disabled privileges before calling Install on Server
    MSI (c) (A0:24) [14:38:41:387]: Connected to service for CA interface.
    SFXCA: Extracting custom action to temporary directory: C:\MSIA543.tmp-\
    SFXCA: Binding to CLR version v4.0.30319
    Calling custom action Emex.Installer.CustomActions!Emex.Installer.CustomActions.CustomActions.CheckRegistryKeyExists
    CheckRegistryKeyExists: Begin
    CheckRegistryKeyExists: Looking up key SOFTWARE\Microsoft\.NETFramework\v4.0.30319\SKUs\.NETFramework,Version=v4.0.1 in Hive HKLM
    MSI (c) (A0!F4) [14:39:09:498]: PROPERTY CHANGE: Modifying REGKEYEXISTS property. Its current value is '0'. Its new value: '1'.
    CheckRegistryKeyExists: End


    Debugging

    The statement Debugger.Launch() statement launches and attaches the debugger to the installer when the Custom Action is executed. In the above code it is surrounded with the #if DEBUG to prevent the debugger being launched in release mode.

    When the debug version of the installer is launched the following dialog is displayed. You can attach the VS project that contains the source for the Custom Action and simply step through the code as you normally would.

    JITD

    Tuesday, 17 July 2012

    WIX Light.exe LGHT0204: ICE03: Error

    Recently I have been developing a  set of deployment components for the various system components of a workflow designer and execution subsystem. One of the deployment components required is to deploy a workflow and domain model designer to an end users PC.
    WorkflowDesigner
    Since there can be a wide variance as to what .net runtime components an end user has installed on their PC it was therefore a requirement to perform some up front checks as a prerequisite to an install on a given target PC.
    The application has three required components that must be deployed to  a candidate client PC, these are as follows:

    • .Net Framework 4.0
    • Multi-Targeting Pack for Microsoft .NET Framework 4.0.1 (KB2495638)
    • WCF Data Services 5.0 for OData V3

    A WIX installer was created, the Conditions.wxi contains obviously enough the prerequisite conditions for the deployment. The Product.wxs contains all of the assembly references for the application files. The Strings_en-us.wxl obviously contains localised strings for the installer messages etc..

    image
     So the conditions where defined as shown in the following snippet:

    <Property Id="UPDATE401">
        <RegistrySearch Id="Update401x32" Type="raw" Root="HKLM" Key="SOFTWARE\Microsoft\.NETFramework\v4.0.30319\SKUs\.NETFramework,Version=v4.0.1" Win64="no" />
    </Property>
    <Property Id="UPDATE401X64">     <RegistrySearch Id="Update401x64" Type="raw" Root="HKLM" Key="SOFTWARE\Microsoft\.NETFramework\v4.0.30319\SKUs\.NETFramework,Version=v4.0.1" Win64="yes" /> </Property>
    <Property Id="ODATA">     <RegistrySearch Id="ODataRegistry32" Type="raw" Root="HKLM" Key="SOFTWARE\Microsoft\Microsoft WCF Data Services\5.0" Name="Version" Win64="no" /> </Property>
    <Property Id="ODATAX64">     <RegistrySearch Id="ODataRegistry64" Type="raw" Root="HKLM" Key="SOFTWARE\Microsoft\Microsoft WCF Data Services\5.0" Name="Version" Win64="yes" /> </Property>
    <Condition Message='!(loc.Update401Missing)'><![CDATA[(UPDATE401 <> "" OR UPDATE401X64 <> "") OR Installed]]></Condition>
    <Condition Message='!(loc.ODataMissing)'><![CDATA[(ODATA <> "" OR ODATAX64 <> "") OR Installed]]></Condition>

    The corresponding message strings are shown in the following snippet:
    <String Id="ODataMissing" Overridable="yes">WCF Data Services 5.0 for OData V3 missing [http://www.microsoft.com/en-ie/download/details.aspx?id=29306] </String>
    <String Id="Update401Missing" Overridable="yes">Multi-Targeting Pack for Microsoft .NET Framework 4.0.1 (KB2495638) [http://www.microsoft.com/en-ie/download/details.aspx?id=27757]</String>

    In some deployments the end user will install the application I decided to add references to the download pages for the .Net framework components that this application requires to be deployed to the PC before the application will execute on the PC. In larger client environments the application and the dependant components will be  deployed using automated deployment systems.

    On compiling the WIX application the following errors where reported.

    Emex.Workflow.Designer.Installer\Conditions.wxi(20,0): error LGHT0204: ICE03: Invalid format string; Table: LaunchCondition, Column: Description, Key(s): (UPDATE401 <> "" OR UPDATE401X64 <> "") OR Installed
    Emex.Workflow.Designer.Installer\Conditions.wxi(22,0): error LGHT0204: ICE03: Invalid format string; Table: LaunchCondition, Column: Description, Key(s): (ODATA <> "" OR ODATAX64 <> "") OR Installed


    At first this looks like the error is due to the condition expression being incorrect. But this is not the case. The problem is actually the message strings, the [ ] delimiters that I had used around the links, for no obvious reason, where the cause of the problem. To resolve the errors it was simply a case of escaping the delimiters as per the rules here.
    <String Id="ODataMissing" Overridable="yes">WCF Data Services 5.0 for OData V3 missing [\[]http://www.microsoft.com/en-ie/download/details.aspx?id=29306]</String>

    Thursday, 14 June 2012

    Windows 8 Release Preview

    I have been reading the interweb chatter about Windows 8 since it was released as beta so I decided to check it out myself and see what all of the fuss was about.

    So I finally got some time to download the Windows 8 release preview and install it on a VM. For the VM I used VirtualBox which in my opinion is pretty good, I actually have a preference for it over the VMWare tools, but that is a different discussion.

    screenshot_1

    Well what can I  say I can definitely see why the new interface has been divisive. Its a radical change, more so than the changes from Windows 3.1 to Windows 95. From Windows 95 until Windows 7 we have been presented with evolutionary changes to the Start button, Start menu task bar combination. That's 17 years of relative familiarity, with Windows 8 we now have a a complete departure from this familiarity.

    Windows 8 is a derivation of the Metro interface that we have seen on Windows Phone and in terms of look and feel has some similarity to the Xbox 360 user interface.

    I can see where Microsoft are going with the UI and the integration with online services, Maps, Weather, Music, Xbox LIVE, Sky Drive etc.. Windows 8 is integrated with more online services than Windows 7, similar to the integration previously seen on Windows Phone.

    The fundamental question is does the UI work? In my opinion based on the limited exposure that I have had with the OS the answer is …… maybe. Depending on the device that you intend using the OS on and for what purpose.

    For general content consumption on a touch enabled tablet or laptop I think, with the caveat of not having used such a configuration, it looks like the right UI for this type of human device interaction.
    Another configuration that I think this OS will work well with is for a HTPC. Having used Windows 7 for a HTPC OS and tried several of the media centre application like XBMC, I have found the results some what mixed. When using the media centre interfaces its a generally workable solution. When you have to step outside and use native windows applications, for scenarios where plugins don't exist you end up having to scale the fonts and tweak the display settings so that you can see the text from the normal TV to couch distances. These tweaks are never a very satisfactory solution and its possibly the reason that HTPC have never really caught on.

    The Windows 8 UI I believe alleviates most if not all of the problems for HTPC usage. Using a HTPC with a Kinect running Windows 8 OS could potentially be a Killer combination once the input gestures where useable and not to extreme, it would be super to flicking through the music or changing channel with a simple wave of a hand.

    Lazy Minority Report fantasies aside there is a lot of debate and discussion around the usability of Windows 8 in the traditional PC environment of a keyboard and mouse. And I have to say from my experience of using Windows 8 I would say its detractors have a point, I do not believe that it is just a problem with familiarity or learning the curve. There are a few things that don't work so well with Windows 8 with a keyboard and a mouse:

    More mouse movement

    The landscape orientated screen real-estate in Windows 8 is much larger in some apps, notably Media Player. This leads you to have to scroll left and right quite a bit. With a mouse this is not much fun.

    More interaction required

    Seemingly simple operations like shutting down the PC or closing applications from the Metro Start menu screen take more interaction clicks than in windows 7. See here for shut down

    Mouse accuracy

    I found launching some of the menu items from the lower left hand corner to be hit and miss, this may be down to the fact that i was running in a VM or just that I’m an idiot Smile

    Cluttered Start

    When all of the applications are enabled on the Metro start screen it can get a bit cluttered looking. I put this down too the fact that there is no hierarchy available for nesting as with the old Windows start menu

    Monday, 30 April 2012

    Configurable OData Service - Part 5 – End To End Example

    This is the final post in the series on the configurable OData service. In this post I will cover an end to end example of how the Domain Model Service and be configured and used by an OData client. For the sake of simplicity I am going to expose a simple database with only one table, the table is called Employees. The script below shows the layout of the table.

    CREATE TABLE [dbo].[Employees](
        [EmployeeID] [uniqueidentifier] NOT NULL,
        [LastName] [nvarchar](20) NOT NULL,
        [FirstName] [nvarchar](10) NOT NULL,
        [Title] [nvarchar](30) NULL,
        [BirthDate] [datetime] NULL,
        [HireDate] [datetime] NULL,
        [Address] [nvarchar](60) NULL,
        [City] [nvarchar](15) NULL,
        [Region] [nvarchar](15) NULL,
        [PostalCode] [nvarchar](10) NULL,
        [Country] [nvarchar](15) NULL,
        [HomePhone] [nvarchar](24) NULL,
        [Extension] [nvarchar](4) NULL
     CONSTRAINT [PK_Employees] PRIMARY KEY CLUSTERED 
    (
        [EmployeeID] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    
    
    GO

    The Domain Model Service is deployed to IIS via its WIX based installer which takes care of configuring the service to execute under IIS.

    DomainModelIIS

    There are two services exposed from the Domain Model Service

    • DefinitionService.svc
      • Implements the functionality to define the shape and structure of the exposed Domain Model Service
    • ManagementService.svc
      • Implements functionality to start and stop instances of the Domain Model Service

    Before jumping into the client console application I will just mention the configuration settings that are required to configure the service.

    <?xml version="1.0" encoding="utf-8"?>
    <domainModel 
      tablePrefixFilter="" 
      connectionStringName="DomainModelMetadata" 
      targetStoreConnectionStringName="TargetDatabase" 
      domainModelServiceBaseAddress="http://127.000.000.001:8080"/>

    The previous configuration fragment contains the following elements:
    • tablePrefixFilter
      • A prefix that is applied by the service when enumerating tables from the database
    • connectionStringName
      • The connection string element name for the store that contains the Domain Model metadata
    • targetStoreConnectionStringName
      • The connection string element name for the target database that will be exposes as an OData service
    • domainModelServiceBaseAddress
      • The base address that a Domain Model Service will be exposed relative too. Notice that the service base address is http:// not https:// more on this later
    Listing the Target Schema

    After creating the proxy to the service. The first step is to retrieve the table metadata from the Domain Model Service, this is used as reference information to define a domain model.
    DefinitionServiceClient client = new DefinitionServiceClient();
    
    
    client.ClientCredentials.UserName.UserName = "xxxxxx";
    client.ClientCredentials.UserName.Password = "xxxxxx";
    client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.None;
    
    
    client.Open();
    
    
    var tableMetadata = client.GetTableMetadata();
    
    
    foreach (var item in tableMetadata)
    {
        Console.WriteLine(item.Name);
    
    
        foreach (var column in item.Columns)
        {
            Console.WriteLine("\t" + column.Name);
        }
    }

    For the example database this produces the following output:

    schemalist

    We now have the list of the tables and columns from the target database. This information is intended for consumption in a designer that will allow for a Domain Model Service to be defined by an end user.

    Defining and Activating Domain Model Service

    Now that we can query the table metadata the next step is to create a Domain Model Definition. This is achieved by creating a proxy to the definition service and calling the CreateDomainModelDefinition
    DefinitionServiceClient client = new DefinitionServiceClient();
    
    
    client.Open();
    
    
    
    ...
    
    
    domainModelDefinition = client.CreateDomainModelDefinition(domainModelDefinition);

    Then the Domain Model needs to be activated. This is achieved by calling the ActivateDomainModel method of the management service proxy.

    ManagementServiceClient managmentServiceClient = new ManagementServiceClient();
    managmentServiceClient.ActivateDomainModel(domainModelDefinition.Identifier);

    The queried metadata is mapped to the entities that are to be exposed by instances of a Domain Model service. In this example I will expose two versioned “views” of the Employees entity. As an example of how the exposed Domain Model Service entity can diverge from the underlying database I will expose the Employees entity as an entity called People.

    Version 1
    DomainModelEntity domainModelEntity = new DomainModelEntity();
    domainModelEntity.TableName = "Employees";
    domainModelEntity.TypeName = "People";
    domainModelEntity.Properties = new List<DomainModelProperty>();
    domainModelEntity.Properties.Add(new DomainModelProperty()
        {
            ColumnName = "EmployeeID",
            PropertyName = "Identifier",
            IsIdentity = true
        });
    
    
    domainModelEntity.Properties.Add(new DomainModelProperty()
    {
        ColumnName = "FirstName",
        PropertyName = "Givename"
    });
    
    
    domainModelEntity.Properties.Add(new DomainModelProperty()
    {
        ColumnName = "LastName",
        PropertyName = "Surname"
    });
    
    
    DomainModelDefinition domainModelDefinition = new DomainModelDefinition()
        {
            Entities = new List<DomainModelEntity>(),
            Comments = "Version 1"
        };
    
    
    domainModelDefinition.Entities = new List<DomainModelEntity>();
    domainModelDefinition.Entities.Add(domainModelEntity);

    For version one  of the Domain Model the Employee table is exposed as an entity called People. The three required fields are exposed as aliases of the underlying columns. The Employee is mapped to a field called Identifier. After the definition is created we can query the service at the address “http://localhost:8081/V1/DomainModelService” which will describe the atom for the “Peoples” entity set.

    version1

    The metadata can be queried from this OData service at “http://localhost:8081/V1/DomainModelService/$metdata”, which shows only the three fields that where mapped.

    version1metadata

    Using the ODataExplorer tool we can perform some query and updates to the data exposed by the service.

    OdataV1

    Unfortunately the ODataExplorer does not allow you to insert entities, so for the example I pre seeded the table with a number of rows. And yes i am that unoriginal to come up with the names of people.

    OdataV1Data

    The data can be modified using the ODataExplorer

    OdataV1DataChange

    We can see the changes reflected in the database

    RawDatachanged

    Just to prove that this is a fully functioning OData service you can see that the data can also be queried.

    OdataV1DataQuery

    Version 2
    For Version 2 of the Domain Model we can add a more of the underlying fields to the entities. For the sake of brevity I will add only one the BirthDate.

    DomainModelEntity domainModelEntity = new DomainModelEntity();
    domainModelEntity.TableName = "Employees";
    domainModelEntity.TypeName = "People";
    domainModelEntity.Properties = new List<DomainModelProperty>();
    domainModelEntity.Properties.Add(new DomainModelProperty()
        {
            ColumnName = "EmployeeID",
            PropertyName = "Identifier",
            IsIdentity = true
        });
    
    
    domainModelEntity.Properties.Add(new DomainModelProperty()
    {
        ColumnName = "FirstName",
        PropertyName = "Firstname"
    });
    
    
    domainModelEntity.Properties.Add(new DomainModelProperty()
    {
        ColumnName = "LastName",
        PropertyName = "Lastname"
    });
    
    
    domainModelEntity.Properties.Add(new DomainModelProperty()
    {
        ColumnName = "BirthDate",
        PropertyName = "DateOfBirth"
    });
    
    
    DomainModelDefinition domainModelDefinition = new DomainModelDefinition()
        {
            Entities = new List<DomainModelEntity>(),
            Comments = "Version 2"
        };
    
    
    domainModelDefinition.Entities = new List<DomainModelEntity>();
    domainModelDefinition.Entities.Add(domainModelEntity);
    
    

    Again the metadata can be queried from the instance of the service that exposes this version of the Domain Model. For the second version the Url is “http://localhost:8081/V2/DomainModelService/$metdata”.

    version2metadata

    Again the ODataExplorer tool can be used to query data.

    OdataV2Data

    We can also update the entities to change the value of the underlying data in the database.

    OdataV2DataChange

    RawDatachangedV2

    Multiple versions of Domain Models can be exposed using this service, they can contain multiple entities.

    Further Improvements

    This version of the Domain Model service satisfies the initial requirements but there are a number of areas in which improvements and enhancements can be made. The following is a brief discussion of these enhancements:
    • Entity Identity
      • At the moment the implementation makes the assumption that all entities exposed from the Domain Model have an identifier of type of System.Guid. This is fine for the intended target schema that this component will expose, but it is not a truly flexible approach. A better approach would be to allow for the data type  of the identity field to be specified when creating the Domain Model. The DynamicDataContext class would then use a different mechanism to generate and manipulate the  identity field.

    • Security
      • The DefinitionService and the ManagementService exposed by the Domain Model Service are secured using message level security. The Domain Model Service instances that are instantiated and exposed are not secure. They are exposed as http endpoints. With some additional configuration they can be exposed as https and use any of the following methods of security.

    • Relationships
      • The current implementation supports only exposing entities that do not have relationships to other entities defined in the domain model. It is possible to enhance the service to support relationships between entity types by extending the IDataServiceMetadataProvider and IDataServiceUpdateProvider derived classes.

    Hopefully this series of posts has given a good overview of the implementation of a configurable OData service and given a good example of how a Custom Data provider can be implemented to source data.

    Tuesday, 24 April 2012

    Configurable OData Service - Part 4 – WCF Service Host

    In the last post in this series, Part 3 – Custom Data Service Provider, I described the implementation of the Custom Data Service Provider. At this point we now have an OData Service that can be configured via metadata to expose an underlying data store. The next challenge is now to get an instance of this custom OData service up and running. This post will delve into the details on how this is achieved.

    Overview

    ServiceHost
    The core idea is to host the OData services from within a WCF service. In the above diagram each of the Domain Model Service instances, in green, are listening at an address relative to a configured base address. For example http://localhost:port/Vx/DomainModelService, where Vx refers to the version of the Domain Model that the service is exposing, for example V1.

    WCF hosting challenge


    Each instance of a DomainModelService type that is to be exposed from the WCF service host, expects an instance of a DomainModelDescriptor  to be passed to the constructor.
    /// <summary>
    /// Initializes a new instance of the <see cref="DomainModelService"/> class.
    /// </summary>
    /// <param name="domainDescriptor">The <see="DomainModelDescriptor"> that this service has to represent.</param>
    public DomainModelService(DomainModelDescriptor domainDescriptor) : this(domainDescriptor, DynamicTypeGenerator.Instance)
    {
    }

    This non default constructor presents a challenge when using the WebServiceHost class to host an instance/instances of the DomainModelService. The WebServiceHost class is used, as opposed to the ServiceHost class, is due to the fact that the DomainModelService is an OData service and cannot be hosted using the ServiceHost class. The WebServiceHost class supports two modes of instantiation.
    //
    // Summary:
    //     Initializes a new instance of the System.ServiceModel.Web.WebServiceHost
    //     class with the specified singleton server instance and base address.
    //
    // Parameters:
    //   singletonInstance:
    //     A service instance to be used as the singleton instance.
    //
    //   baseAddresses:
    //     The base address of the service.
    public WebServiceHost(object singletonInstance, params Uri[] baseAddresses);
    //
    // Summary:
    //     Initializes a new instance of the System.ServiceModel.Web.WebServiceHost
    //     class with the specified service type and base address.
    //
    // Parameters:
    //   serviceType:
    //     The service type.
    //
    //   baseAddresses:
    //     The base address of the service.
    public WebServiceHost(Type serviceType, params Uri[] baseAddresses);

    The constructor public WeServiceHost(Type serviceType, params Uri[] baseAddresses) cannot be used due to the fact that the DomainModelService does not have a non default constructor. Invoking this constructor will throw the following exception:

    System.InvalidOperationException: The service type provided could not be loaded as a service because it does not have a default (parameter-less) constructor. To fix the problem, add a default constructor to the type, or pass an instance of the type to the host.

    The second constructor public WebServiceHost(object singletonInstance, params Uri[] baseAddresses) can be used to host a instance of a DomainModelService. There is however one drawback to using this method of instantiation and that is the instance of the hosted service is a singleton. Having one instance to service all requests for data could potentially be a bottleneck, where by requests queue on the server side.

    Solution


    The solution to enabling the WCF framework to instance DomainModelService types is to control the instancing behaviour of the framework ourselves. This is done by implementing an IInstanceProvider derived type and an IServiceBehavior derived type to apply the IInstanceProvider.

    The implementation of the IInstanceProvider derived DomainModelInstanceProvider, below, is pretty straight forward. It is passed an instance of an IDomainModelServiceMetadataProvider derived type. invokes the GetDomainModelMetadata method and stores the result. When the WCF framework invokes one of the GetInstance method overloads the DomainModelInstanceProvider constructs an instance of an DomainModelService passing the DomainModelDescriptor to the constructor.
    /// <summary>
    /// The instance provider for instances of <see cref="DomainModelServices"/>
    /// </summary>
    public class DomainModelInstanceProvider : IInstanceProvider
    {
        private DomainModelDescriptor _domainModelDescriptor;
        
        /// <summary>
        /// Constructor
        /// </summary>
        /// <remarks>Retrieves an instance of a <see cref="DomainModelDescriptor"/> from the <see cref="IDomainModelServiceMetadataProvider"/> and stores it.</remarks>
        /// <param name="domainModelServiceMetadataProvider">The <see cref="IDomainModelServiceMetadataProvider"/> to retrieve a <see cref="DomainModelDescriptor"/> from</param>
        public DomainModelInstanceProvider(IDomainModelServiceMetadataProvider domainModelServiceMetadataProvider)
        {
            _domainModelDescriptor = domainModelServiceMetadataProvider.GetDomainModelMetadata(DomainModelServiceSettings.Current.DomainModelServiceActivationTimeout);
        }
    
    
        /// <summary>
        /// Get an instance of a <see cref="DomainModelService"/>
        /// </summary>
        /// <param name="instanceContext">The context for the instance</param>
        /// <param name="message">The message</param>
        /// <returns>An instance of a <see cref="DomainModelService"/></returns>
        public object GetInstance(InstanceContext instanceContext, Message message)
        {
            return new DomainModelService(_domainModelDescriptor);
        }
        /// <summary>
        /// Get an instance of a <see cref="DomainModelService"/>
        /// </summary>
        /// <param name="instanceContext">The context for the instance</param>
        /// <returns>An instance of a <see cref="DomainModelService"/></returns>
        public object GetInstance(InstanceContext instanceContext)
        {
            return GetInstance(instanceContext, null);
        }
        /// <summary>
        /// Release instance.
        /// <remarks>
        /// Nothing for this provider to do for this type
        /// </remarks>
        /// </summary>
        /// <param name="instanceContext"></param>
        /// <param name="instance"></param>
        public void ReleaseInstance(InstanceContext instanceContext, object instance)
        {
            return;
        }
    }
    
    
    /// <summary>
    /// Defines methods for retrieving <see cref="DomainModelDescriptor"/> metadata
    /// </summary>
    public interface IDomainModelServiceMetadataProvider
    {
        /// <summary>
        /// Retrieve an instance of a <see cref="DomainModelDescriptor"/>
        /// </summary>
        /// <param name="timeout">The time out for retreiving the metadata.</param>
        /// <returns>An instance of a <see cref="DomainModelDescriptor"/></returns>
        DomainModelDescriptor GetDomainModelMetadata(TimeSpan timeout);
    }
    
    
    
    /// <summary>
    /// A custom instancing behaviour to apply to a service.
    /// </summary>
    public class DomainModelServiceInstancingBehaviour : IServiceBehavior
    {
        private DomainModelInstanceProvider _instanceProvider;
    
    
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="domainModelServiceMetadataProvider">An instance of an <see cref="IDomainModelServiceMetadataProvider"/></param>
        public DomainModelServiceInstancingBehaviour(IDomainModelServiceMetadataProvider domainModelServiceMetadataProvider)
        {
            _instanceProvider = new DomainModelInstanceProvider(domainModelServiceMetadataProvider);
        }
    
    
        /// <summary>
        /// Provides the ability to pass custom data to binding elements to support the contract implementation.
        /// </summary>
        /// <param name="serviceDescription">The service description of the service.</param>
        /// <param name="serviceHostBase">The host of the service.</param>
        /// <param name="endpoints">The service endpoints.</param>
        /// <param name="bindingParameters">Custom objects to which binding elements have access.</param>
        public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
        {
            return;
        }
    
    
        /// <summary>
        /// Provides the ability to change run-time property values or insert custom extension objects such as error handlers, message or parameter interceptors, security extensions, and other custom extension objects.
        /// </summary>
        /// <remarks>
        /// This <see cref="IServiceBehavior"/> type applies an instance of an <see cref="DomainModelInstanceProvider"/> to each of the <see cref="EndpointDispatcher"/> for the service host.
        /// </remarks>
        /// <param name="serviceDescription">The service description.</param>
        /// <param name="serviceHostBase">The host that is currently being built.</param>
        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
            foreach (ChannelDispatcherBase cdb in serviceHostBase.ChannelDispatchers)
            {
                ChannelDispatcher cd = cdb as ChannelDispatcher;
                if (cd != null)
                {
                    foreach (EndpointDispatcher ed in cd.Endpoints)
                    {
                        ed.DispatchRuntime.InstanceProvider = _instanceProvider;
                    }
                }
            }
        }
    
    
        /// <summary>
        /// Provides the ability to inspect the service host and the service description to confirm that the service can run successfully.
        /// </summary>
        /// <param name="serviceDescription">The service description.</param>
        /// <param name="serviceHostBase">The service host that is currently being constructed.</param>
        public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
            return;
        }
    }

    The DomainModelInstanceProvider is applied to the service through the use of a behaviour. Again the behaviour is pretty straight forward implementation. It constructs and instance of an DomainModelInstanceProvider type and applies this instance to the EndpointDispatcher .DispatchRuntime.InstanceProvider property for each of the endpoints.
    /// <summary>
    /// A custom instancing behaviour to apply to a service.
    /// </summary>
    public class DomainModelServiceInstancingBehaviour : IServiceBehavior
    {
        private DomainModelInstanceProvider _instanceProvider;
    
    
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="domainModelServiceMetadataProvider">An instance of an <see cref="IDomainModelServiceMetadataProvider"/></param>
        public DomainModelServiceInstancingBehaviour(IDomainModelServiceMetadataProvider domainModelServiceMetadataProvider)
        {
            _instanceProvider = new DomainModelInstanceProvider(domainModelServiceMetadataProvider);
        }
    
    
        /// <summary>
        /// Provides the ability to pass custom data to binding elements to support the contract implementation.
        /// </summary>
        /// <param name="serviceDescription">The service description of the service.</param>
        /// <param name="serviceHostBase">The host of the service.</param>
        /// <param name="endpoints">The service endpoints.</param>
        /// <param name="bindingParameters">Custom objects to which binding elements have access.</param>
        public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
        {
            return;
        }
    
    
        /// <summary>
        /// Provides the ability to change run-time property values or insert custom extension objects such as error handlers, message or parameter interceptors, security extensions, and other custom extension objects.
        /// </summary>
        /// <remarks>
        /// This <see cref="IServiceBehavior"/> type applies an instance of an <see cref="DomainModelInstanceProvider"/> to each of the <see cref="EndpointDispatcher"/> for the service host.
        /// </remarks>
        /// <param name="serviceDescription">The service description.</param>
        /// <param name="serviceHostBase">The host that is currently being built.</param>
        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
            foreach (ChannelDispatcherBase cdb in serviceHostBase.ChannelDispatchers)
            {
                ChannelDispatcher cd = cdb as ChannelDispatcher;
                if (cd != null)
                {
                    foreach (EndpointDispatcher ed in cd.Endpoints)
                    {
                        ed.DispatchRuntime.InstanceProvider = _instanceProvider;
                    }
                }
            }
        }
    
    
        /// <summary>
        /// Provides the ability to inspect the service host and the service description to confirm that the service can run successfully.
        /// </summary>
        /// <param name="serviceDescription">The service description.</param>
        /// <param name="serviceHostBase">The service host that is currently being constructed.</param>
        public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
            return;
        }
    }

    The behaviour is applied to the service host through the use of a WebServiceHostFactory derived type. The DomainModelServiceHostFactory type adds the DomainModelServiceInstancingBehaviour to the host. The DomainModelServiceHost type is derived from WebServiceHost and an interface IServiceHost, the interface is to abstract the underlying implementation to facilitate testing.
    public class DomainModelServiceHostFactory : WebServiceHostFactory, IServiceHostFactory
    {
        private readonly IDomainModelServiceMetadataProvider _domainModelServiceMetadataProvider;
    
    
        static DomainModelServiceHostFactory()
        {
            IoCContainer.Current = new IocContainerProxy();
        }
    
    
        /// <summary>
        /// Initializes a new instance of the <see cref="DomainModelServiceHostFactory"/> class.
        /// </summary>
        /// <param name="domainModelServiceMetadataProvider">The domain model service metadata provider.</param>
        public DomainModelServiceHostFactory(IDomainModelServiceMetadataProvider domainModelServiceMetadataProvider)
        {
            _domainModelServiceMetadataProvider = domainModelServiceMetadataProvider;
        }
    
    
        /// <summary>
        /// Creates an instance of the specified <see cref="T:System.ServiceModel.Web.WebServiceHost"/> derived class with the specified base addresses.
        /// </summary>
        /// <param name="serviceType">The type of service host to create.</param>
        /// <param name="baseAddresses">An array of base addresses for the service.</param>
        /// <returns>
        /// An instance of a <see cref="T:System.ServiceModel.ServiceHost"/> derived class.
        /// </returns>
        protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
        {
            var host = new DomainModelServiceHost(serviceType, baseAddresses);
    
    
            host.Description.Behaviors.Add(new DomainModelServiceInstancingBehaviour(_domainModelServiceMetadataProvider));
    
    
            return host;
        }
    
    
        /// <summary>
        /// Creates the service host.
        /// </summary>
        /// <param name="serviceType">Type of the service.</param>
        /// <param name="baseAddresses">The base addresses.</param>
        /// <returns></returns>
        IServiceHost IServiceHostFactory.CreateServiceHost(Type serviceType, Uri[] baseAddresses)
        {
            return CreateServiceHost(serviceType, baseAddresses) as IServiceHost;
        }
    }

    At this point we now have the ability to host and instantiate instances of the DomainModelService. The final piece that is missing is a mechanism to orchestrate and manage the hosted DomainModelService instances. This responsibility falls to the DomainModelServiceManager class. It is responsible for the managing of the host instances and providing the metadata for each of the host instances that are started. It is not responsible for the validation and verification of the DomainModelMetadata, that is the responsibility of the containing WCF service.
    public class DomainModelServiceManager : IDomainModelServiceManager, IDomainModelServiceMetadataProvider, IDisposable
    {
    
    ….
    }

    The DomainModelServiceManager derives from the IDomainModelServiceManager and IDomainModelServiceMetadataProvider interfaces.

    /// <summary>
    
    /// An interface to define the methods and properties for a domain model service manager
    
    /// </summary>
    
    public interface IDomainModelServiceManager
    
    {
    
        /// <summary>
    
        /// The event that is raised when a <see cref="DoaminModelService"/> is opened
    
        /// </summary>
    
        event EventHandler<DomainModelServiceOpenedEventArgs> OnDomainModelServiceOpened;
    
        /// <summary>
    
        /// The event that is raised when a <see cref="DoaminModelService"/> is closed
    
        /// </summary>
    
        event EventHandler<DomainModelServiceClosedEventArgs> OnDomainModelServiceClosed;
    
        /// <summary>
    
        /// The event that is raised when a <see cref="DoaminModelService"/> is closed
    
        /// </summary>
    
        event EventHandler<DomainModelServiceFaultedEventArgs> OnDomainModelServiceFaulted;
    
        /// <summary>
    
        /// Deacivate a <see cref="DoaminModelService"/> for the given idenitfier.
    
        /// </summary>
    
        /// <param name="identifier">The identifier of the <see cref="DomainModelDescriptor"/></param>
    
        void DeactivateDomainModelService(Guid identifier);
    
        /// <summary>
    
        /// Activate a <see cref="DoaminModelService"/> for a <see="DomainModelDescriptor"/>
    
        /// </summary>
    
        /// <param name="domainModelDescriptor">The descriptor that describes the structure of the entites of the domain model</param>
    
        /// <param name="baseAddress">The base address that the hosted <see cref="DoaminModelService"/> should be bound too</param>
    
        /// <param name="servicePath">The relative service path for the bound address. For example baseaddress/servicePath</param>
    
        /// <param name="activationTimeout">The amount of time to wait for the service host to be activated.</param>
    
        void ActivateDomainModelService(DomainModelDescriptor domainModelDescriptor, Uri baseAddress, String servicePath, TimeSpan activationTimeout);
    
        /// <summary>
    
        /// Gets a list of active <see cref="DoaminModelService"/>
    
        /// </summary>
    
        /// <returns>A <see cref="IDictionary<Guid, Uri>"/> the <see cref="Guid"/> is a unique identifier for the instance. The <see cref="Uri"/> is the address that the </returns>
    
        IDictionary<Guid, Uri> GetActiveDomainModelServices();
    
        /// <summary>
    
        /// Indicates if this instance has been initalised.
    
        /// </summary>
    
        bool IsInitalised { get; }
    
        /// <summary>
    
        /// Initalise the <see cref="IDomainModelServiceManager"/> instance
    
        /// </summary>
    
        /// <param name="domainModelDescriptors">The list of <see cref="DoaminModelService"/> to initalise</param>
    
        /// <param name="baseAddress">The base address that the hosted <see cref="DoaminModelService"/> should be bound too</param>
    
        /// <param name="servicePath">The relative service path for the bound address. For example baseaddress/servicePath</param>
    
        /// <param name="activationTimeout">The amount of time to wait for a given service host to be activated</param>
    
        void Initalise(IList<DomainModelDescriptor> domainModelDescriptors, Uri baseAddress, String servicePath, TimeSpan activationTimeout);
    
    }

    The key part of the DomainModelServiceManager is the activation and deactivation of DomainModelService instances. There are other functions that the DomainModelServiceManager performs such as logging, handling faulted Service Host instances, but these are ancillary to its core function of managing instances of hosted DomainModelService instances. Discussion of these features are excluded for the sake of brevity. The following code snippets describe the activation process in more detail.
    private BlockingCollection<DomainModelDescriptor> _activatableDomainModels;
    private List<DomainModelServiceInstance> _activatedDomainModels;
    private IServiceHostFactory _serviceHostFactory;
    
    
    public DomainModelServiceManager()
    {
        ......
        
        // the DomainModelServiceManager is an IDomainModelServiceMetadataProvider derived type and can provide the metadata
        _serviceHostFactory = new DomainModelServiceHostFactory(this);
    }
            
    /// <summary>
    /// Activate a <see cref="DoaminModelService"/> for a <see="DomainModelDescriptor"/>
    /// </summary>
    /// <param name="domainModelDescriptor">The descriptor that describes the structure of the entites of the domain model</param>
    /// <param name="baseAddress">The base address that the hosted <see cref="DoaminModelService"/> should be bound too</param>
    /// <param name="servicePath">The relative service path for the bound address. For example baseaddress/servicePath</param>
    /// <param name="activationTimeout">The amount of time to wait for the service host to be activated.</param>
    public void ActivateDomainModelService(DomainModelDescriptor domainModelDescriptor, Uri baseAddress, String servicePath, TimeSpan activationTimeout)
    {
        _activatableDomainModels.Add(domainModelDescriptor);
    
    
        lock (_activatedDomainModels)
        {
            var domainModelService = CreateDomainModelServiceInstance(baseAddress, servicePath, domainModelDescriptor);
    
    
            _activatedDomainModels.Add(domainModelService);
    
    
            _logger.Debug("Domain model activation started");
    
    
            domainModelService.ServiceHostInstance.Open(activationTimeout);
       }
    }
    /// <summary>
    /// Create a hosted instance of a <see cref="DomainModelService"/>
    /// </summary>
    /// <param name="domainModelDescriptor">The descriptor that describes the structure of the entites of the domain model</param>
    /// <param name="baseAddress">The base address that the hosted <see cref="DoaminModelService"/> should be bound too</param>
    /// <param name="servicePath">The relative service path for the bound address. For example baseaddress/servicePath</param>
    /// <returns>A <see cref="DomainModelServiceInstance"/></returns>
    private DomainModelServiceInstance CreateDomainModelServiceInstance(Uri baseAddress, String servicePath, DomainModelDescriptor domainModelDescriptor)
    {
        UriBuilder builder = new UriBuilder(baseAddress);
        builder.Path = String.Format("V{0}/{1}", domainModelDescriptor.Version, servicePath);
        
        // The service host factory adds the instanceing behavior
        var host = _serviceHostFactory.CreateServiceHost(typeof(DomainModelService), new Uri[] { builder.Uri });
    
    
        host.Faulted += HandleHostFaulted;
        host.Opened += HandleHostOpened;
        host.Closed += HandleHostClosed;
    
    
        DomainModelServiceInstance instance = new DomainModelServiceInstance(domainModelDescriptor, host);
    
    
        return instance;
    }
    
    
    public DomainModelDescriptor GetDomainModelMetadata(TimeSpan timeout)
    {
        DomainModelDescriptor descriptor = null;
    
    
        if(_activatableDomainModels.TryTake(out descriptor, timeout) == false)
        {
            throw new TimeoutException(String.Format("Unable to get domain model metadata within timeout '{0}'", timeout));
        }
    
    
        _logger.Debug("Retrived metadata for DomainModel {0} Version {1}", descriptor.Identifier, descriptor.Version);
        
        return descriptor;
    }
    
    
    /// <summary>
    /// Handle the host opened event
    /// </summary>
    /// <remarks>
    /// This removes the entry in the pending list and moves it to the activated list.
    /// Rasies an event to signal that the open has occured
    /// </remarks>
    /// <param name="sender">The event sender</param>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    protected internal void HandleHostOpened(object sender, EventArgs e)
    {
        IServiceHost serviceHost =  ((IServiceHost)sender);
    
    
        _logger.Debug("Service host started {0}", serviceHost.BaseAddresses[0]);
    
    
        DomainModelServiceInstance openedDomainModel = null;
    
    
        lock (_activatedDomainModels)
        {
            openedDomainModel = (from dm in _activatedDomainModels where dm.ServiceHostInstance == sender select dm).FirstOrDefault();
        }
    
    
        if (openedDomainModel != null)
        {
            EventHelpers.RaiseEvent<DomainModelServiceOpenedEventArgs>(
            new DomainModelServiceOpenedEventArgs()
            {
                DomainModel = openedDomainModel.DomainModelMetadata
            }, OnDomainModelServiceOpened, this);
        }
        else
        {
            _logger.Warn("Faulted {0} could not be found for address {1}", typeof(DomainModelServiceInstance), serviceHost.BaseAddresses[0]);
        }
    }

    Deactivation of a DomainModelService is a far less involved process. The host simply has to be closed and the event handlers cleaned up.
    /// <summary>
    /// Deacivate a <see cref="DoaminModelService"/> for the given idenitfier.
    /// </summary>
    /// <param name="identifier">The identifier of the <see cref="DomainModelDescriptor"/></param>
    public void DeactivateDomainModelService(Guid identifier)
    {
        DomainModelServiceInstance domainModelServiceInstance = null;
    
    
        lock (_activatedDomainModels)
        {
            domainModelServiceInstance = _activatedDomainModels.Find(
                delegate(DomainModelServiceInstance instance)
                {
                    return instance.DomainModelMetadata.Identifier == identifier;
                });
        }
        if (domainModelServiceInstance != null)
        {
            // close the service and detach event handlers
            DeactivateDomainModelService(domainModelServiceInstance);
    
    
            lock (_activatedDomainModels)
            {
                _activatedDomainModels.Remove(domainModelServiceInstance);
            }
        }
    }

    In the next post in the series Part 5 - End To End Example I will put together a detailed end to end example of how all of these component pieces fit together. Hopefully it will aid in the solidification of how the various ideas and concepts hang together.