Microsoft "Oslo" – May 2009 CTP Release

It’s a busy month 😉

Overview

"Oslo" is the code name for Microsoft’s next generation modeling platform. This CTP includes:

  • "Quadrant" – a visual modeling tool
  • "M" – a modeling language
  • Repository – a SQL Server 2008 database to store models
  • UML domain models and a loader to import UML diagrams in XMI format into the repository
  • CLR domain models and a loader to import .NET assemblies into the repository

New in this CTP:

  • The "Quadrant" modeling tool. Use Quadrant to browse and edit models in a repository database.
  • Domain models for the UML 2.1 specification encompassing Use Case, Activity, Class, Sequence, Component diagrams, profiles and templates.
  • An XMI importer supporting the 2.1 specifications, and covering the diagrams identified above.
  • A domain model and loader for System.Runtime.

http://www.microsoft.com/downloads/details.aspx?FamilyID=827122a5-3ca0-4389-a79e-87af37cbf60d&displaylang=en

BizTalk Cache Adapter Samples

[Source: http://geekswithblogs.net/EltonStoneman]

The sample BizTalk application provided with the BizTalk Cache Adapter on CodePlex illustrates three approaches for using the cache:

  • Simple Messaging – routes all messages configured for caching to the cache adapter, and sends cache-misses on to the service provider;
  • Orchestration – explicitly routes messages to either the cache adapter or service provider in orchestration logic;
  • Complex Messaging – routes messages configured for caching either to the cache adapter or to the service provider.

All the samples use FILE locations for the originating request and ultimate response. The expected locations will be created in the install, with sample request files in the receive locations. Enable the relevant receive location to run the sample, then copy the request file to the receive location again to re-run it – from the second run onwards, the responses should be the cached versions.

Installation

To use the samples, you’ll need to install and configure a cache provider, the cache adapter, cache adapter sample, sample service, and the cache viewer (if you want to see the contents of the cache).

Both the Cache Adapter and Sample BizTalk MSIs use PowerShell scripts for their post-processing steps. If you want to install from the MSIs, you’ll need to have PowerShell installed and set up to enable script execution (Set-ExecutionPolicy RemoteSigned is fine).

1. Cache Provider.

Download and install NCache Express (this is a free edition, you’ll have a product key emailed to you), and configure a cache instance for the samples by modifying the configuration file (config.ncconf – by default in C:\Program Files\NCache Express\config):

<configuration>

<cache-config name=Sixeyed.CacheAdapter.NCacheExpressProvider.Tests inproc=false>

<cleanup interval=1sec/>

<log trace-errors=true trace-debug=false enabled=true/>

<storage cache-size=5mb/>

<eviction-policy default-priority=normal eviction-ratio=10% eviction-enabled=true/>

<perf-counters enabled=false/>

</cache-config>

</configuration>

This creates a single-node cache on the local machine, limited to 5Mb of system memory. Start the cache by running the startcache tool (C:\Program Files\NCache Express\bin\tools):

startcache Sixeyed.CacheAdapter.NCacheExpressProvider.Tests

– and verify it’s there with listcaches. You should see the cache listed as Running:

2. Cache Adapter.

Sixeyed.CacheAdapter.msi is the BizTalk MSI which installs the adapter and artifacts. Import the application into BizTalk and run the installer. Verify the Sixeyed.CacheAdapter application is listed, and add the adapter in the Administration Console through Platform Settings…Adapters…New.

Note: the installer adds the necessary adapter files to the GAC and sets up the registry keys. If you don’t use the MSI, manual installation steps are: add the files from the Binaries release to a local directory and to the GAC; modify run the .REG command to specify assembly paths and import the .REG file; add the BizTalk artifact resources to your own application.

2. Cache Adapter Sample.

Sixeyed.CacheAdapterSample.msi is the BizTalk MSI which installs the sample application and artifacts, and configures the ports. Import the application into BizTalk and run the installer. Verify the Sixeyed.CacheAdapterSample application is listed, and that the message types are configured in SSO (check the contents of SSO application Sixeyed.CacheAdapter).

Note: the installer creates FILE send and receive locations, copies sample messages, and sets up SSO configuration for the cached message types. If you don’t use the MSI, manual installation should follow the steps in: Source\Sixeyed.CacheAdapterSample\Deployment\Sixeyed.CacheAdapterSample.Install.ps1.

4. Sample Service.

Sixeyed.CacheAdapterSample.Service.msi installs a WCF service for the samples to call. Verify the service has deployed correctly by navigating to http://localhost/Sixeyed.CacheAdapterSample/SampleService.svc?wsdl.

5. Cache Viewer.

Sixeyed.CacheAdapter.CacheViewer.msi installs a Winforms app for viewing cache contents. Run the application and configure it to use the running cache instance, by navigating to the NCacheExpressProvider assembly and selecting the NCacheExpressProvider:

– and specifying the ID of the cache instance:

(This is the same management UI used for configuring cache adapter ports in the BizTalk Administration Console. For the samples the Cache Id is Sixeyed.CacheAdapter.NCacheExpressProvider.Tests).

Simple Messaging

Enable the receive location ReceiveRequest_SimpleMessaging.FILE and you should see the following workflow:

  1. Message is picked up by the receive location, which is using the CacheXMLReceive pipeline. This checks the cache configuration in SSO, where the message type is configured for caching, so context property IsMessageCacheEnabled is set to true;
  2. Send port SimpleMessaging_GetCache picks up the message and sends it to the cache adapter, using the request message to build a cache key, and checking for a response existing in the cache. There is no cached response, so the message returned from the cache adapter is the original request message, with context property IsCached set to false;
  3. Send port SimpleMessaging_SendServiceRequest picks up the message and sends it to the service;
  4. Send port SimpleMessaging_PutCache picks up the service response and adds it to the cache, using the cache key from the original request;
  5. Send port SimpleMessaging_SendServiceResponse picks up the service response and copies it to the output directory.

Check the cache viewer and you will see a byte array cached with a GUID key:

The GUID is the hash of the request message, and the byte array is the response message. Subsequent drops of the same request into the Requests folder will find the cached response at step 2, and the response will be the cached message.

This workflow is suitable for any simple messaging solution, where static ports are used and where the original request and ultimate response can be auctioned by different ports. Configuration of the cache instance is contained in the send ports.

Orchestration

The orchestration sample follows the same workflow as the Simple Messaging sample, and uses the same CacheXMLReceive pipeline to add the caching properties to the incoming message. The orchestration sample makes the cache access with explicit send and receives, and configuration of the cache instance is still contained in the send ports.

Enable the receive location ReceiveRequest_Orchestration.FILE to run the sample. This is suitable for solutions where finer grained control is needed over the caching mechanism, and an orchestration is a viable option.

Complex Messaging

Both the simple implementations use the cache adapter as a passthrough when there is no matching response in the cache – the incoming message is returned by the cache adapter, and a send port picks it up and routes it on the service. This is not suitable for more complex solutions:

  • where the service is invoked through a dynamic port, as the outbound transport and location set on the original message are not reset by the cache adapter on the passed-through message;
  • where the originating receive is from a request-response port, as the interchange will accept the passed-through message as a response, and not return the actual service request.

For these scenarios, the cache checking can be moved forward into the originating receive, so the cache adapter is only called if the response is known to exist in the cache. Added complexity here is that the receive pipeline needs to have the cache instance configuration, along with the send ports. This is shown in the Complex Messaging sample – run by enabling the receive location ReceiveRequest_ComplexMessaging.FILE:

  1. Message is picked up by the receive location, which is using a custom pipeline – CheckCacheReceive. This consists of the SetMessageCacheProperties component which checks SSO to see if the message type is configured for caching, followed by the CheckIsCached component which checks is the message response is actually in the cache, and sets the IsCached property:

    Note that the cache instance is configured in the pipeline. Using a custom pipeline means you can configure the instance using the Cache Adapter UI in Visual Studio, which is easier and applies validation. While you could use a generic pipeline and modify the configuration per-instance on receive locations, that means manually hacking the XML;

    1. If the message response is cached, send port ComplexMessaging_GetCache picks up the message and sends it to the cache adapter. The adapter is configured in the same way as other samples, and uses the same logic – but in this case the response is known to be cached, so it will be returned and the request message should never be passed-through;
    2. If the message response is not cached, send port ComplexMessaging_SendServiceRequest calls the service provider passing the original request message;
    3. Send port ComplexMessaging_PutCache picks up the service response and adds it to the cache, using the cache key from the original request;
    4. Send port ComplexMessaging _SendServiceResponse picks up the service response and copies it to the output directory.

There is a risk in this scenario that the object will exist in cache at the point of checking, but been removed by the time the cache is actually read. In this case the response from step 2 will be a passthrough of the original request – in the sample, this means the originating request will be copied to the output directory. Suspending the message may be a better option, but depending on the solution you may be able to cope with this differently.

BizTalk Cache Adapter

[Source: http://geekswithblogs.net/EltonStoneman]

In a recent project we had a requirement for a configurable cache, residing on a BizTalk host and storing responses from WCF services which the BizTalk app had brokered. Producing this as a generic cache adapter was the preferred option, but project timescales didn’t allow for it – instead I’ve written the adapter as an open source component which is available on CodePlex: BizTalkCacheAdapter, and which we’re now making use of in the project.

It’s a simple design suitable for any situation where BizTalk is brokering services to consumers. The incoming request from the consumer is hashed to generate a cache key, and the response is stored in the cache against the request key. When future requests exactly match, they will receive the cached response; if the response doesn’t exist in the cache, the service provider is invoked and the response is added to the cache. The adapter is independent of the cache store being used – currently the only option provided is NCache Express, but extending it to use memcached or Velocity will be straightforward.

Overview

The adapter uses context properties to store cache configuration, so it’s suitable for orchestration or messaging solutions. Alongside the adapter on CodePlex is a sample project which demonstrates the approaches. The workflow is the same in both cases:

  • The consumer sends a service request via the CacheXMLReceive pipeline, which checks if the message type is configured for caching, and promotes the IsMessageCacheEnabled property;
  • If caching is enabled, a two-way message is sent to the cache adapter. This is a GET request, so the adapter checks the cache using the MessageCacheKey context property – if the context property is not available, the adapter writes it by hashing the contents of the service request in the message body;
  • The response from the cache adapter promotes the IsCached property, which identifies whether the response is in cache – if so, the body of the response message will be the cached service response, if not the body is the original service request which can be passed on to the service;
  • If IsCached is false, the service is invoked and a one-way message containing the response is sent to the cache adapter. This is a PUT request, so the adapter adds the message body to the cache using the MessageCacheKey;
  • The service response (either cached or from the provider) is returned to the consumer.

With the messaging solution, the same workflow is carried out using subscriptions to the promoted cache configuration properties, and the various send ports. This workflow may not be suitable for more complex messaging solutions, where services are invoked through dynamic send ports – there is an alternative workflow which I’ll cover in a separate post.

The only real complexity in the adapter is in putting the service response into the cache – the outgoing service request message has the cache configuration properties promoted, but the incoming response does not. In orchestration solutions this isn’t a problem, as the cache properties can be stored as state in the orchestration instance. In messaging solutions, the cache properties are retained by temporarily adding them to the cache, keyed by the interchange ID of the service instance, and removing them when the response is added to the cache.

Configuration

The cache adapter can be used with messages of any type, but with XML messages it can employ different cache configurations for different message types – e.g. a service to get current tax rates may configured to live for several days in the cache, while a service to get current exchange rates may use the same cache store, but be configured to expire after an hour. The CacheReceive and CacheReceiveXml pipelines contain properties for configuring the cache – it can be enabled/disabled for all messages, or (for the XML pipeline) only for configured message types:

Message-level configuration uses an SSO application store, which holds a MessageCacheConfigurationCollection object in XML:

<messageCacheConfigurationCollection xmlns=http://schemas.sixeyed.com/CacheAdapter/2009>

<messageCacheConfigurations>

<messageCacheConfiguration>

<messageType>http://schemas.sixeyed.com/CacheAdapterSample/2009#GetServerDateTime</messageType>

</messageCacheConfiguration>

<messageCacheConfiguration>

<messageType>http://schemas.xyz.com/2009#GetXYZ</messageType>

<cacheLifespan>PT10M</cacheLifespan>

</messageCacheConfiguration>

Caching is enabled for a message if:

  • IsCacheEnabled is true on the pipeline AND
    • IsMessageTypeConfigurationEnabled is false on the pipeline OR
    • IsMessageTypeConfigurationEnabled is true on the pipeline AND
      • the incoming message type has an entry in the MessageCacheConfigurationCollection in SSO.

The lifespan of the object put into cache will be either the cacheLifespan specified in the MessageCacheConfiguration in SSO, or the defaultLifespan specified in the cache send port:

(The point at which the object is removed from cache will depend on the provider, some will remove it when its lifespan expires, others only when its lifespan expires and the cache is full or the cleanup schedule runs).

Installation

For version 1.0.0.0, the CodePlex project comes with three project releases, which can be used independently or together:

  • Sixeyed.CacheAdapter.msi – a BizTalk application MSI which can be imported and installed to your BizTalk server(s). The application contains the configuration schema and pipelines, so it can be used as-is, or the relevant artifacts can be moved to your own application;
  • Sixeyed.CacheAdapter.Binaries.zip – a ZIP file of the adapter binaries you can deploy manually. Use instead of the CacheAdapter MSI, if you don’t want to deploy the whole BizTalk application;
  • Sixeyed.CacheAdapter.CacheViewer.msi – a Windows forms application which lets you view the contents of a cache store (the app uses the configuration components from the adapter management assembly, so it is also cache-provider agnostic):

– a documentation release:

  • Sixeyed.CacheAdapter.chm – documents the .NET assemblies of the adapter

– and two sample releases which should be deployed together:

  • Sixeyed.CacheAdapterSample.msi – a BizTalk application MSI which has sample usage of the cache adapter, demonstrating orchestration and messaging approaches;
  • Sixeyed.CacheAdapterSample.Service.msi – a WCF MSI which provides a service which the BizTalk app can cache.

Pre-requisite for the initial release is the non-commercial NCache Express to use as the cache provider.

To add the sample message-level cache configuration to SSO, the SSO Config Tool can import the provided .ssoconfig file into SSO.

I’ll update the project to add a memcached provider, and write an updated post when it’s available – and the same when Velocity is released. One advantage in having multiple providers would be in evaluating their performance against your expected caching load, so I’ll look at extending the sample solution and adding some LoadGen scripts.

And as Michael Stephenson commented, a nice alternative would be to move the caching up to the WCF layer as a behavior, so WCF requests would check the cache first. Two options for this – it can either be a client behaviour using a local cache store (which could be more performant and would have less impact on server resources, but requires the cache provider to be deployed client-side), or as an operation behaviour using a shared server-side cache (which could be more performant, depending on the type of messages being cached, would impact on server and network resource, but would make the caching transparent to consumers). The complexity is on caching the response message if not already cached – the cache key from the original message will have been lost, so there needs to be a different approach for maintaining state to correlate the WCF service request and response.

Interview Series: Four Questions With  Charles Young

Interview Series: Four Questions With Charles Young

This month’s chat in my ongoing series of discussions with “connected systems” thought leaders is with Charles Young.  Charles is a steady blogger, Microsoft MVP, consultant for Solidsoft Ltd,  and all-around exceptional technologist. 
Those of you who read Charles’ blog regularly know that he is famous for his articles of staggering depth which leave the […]

May 30th Links: ASP.NET, AJAX, ASP.NET MVC, Visual Studio

Here is the latest in my link-listing series.  Also check out my ASP.NET Tips, Tricks and Tutorials page and Silverlight Tutorials page for links to popular articles I’ve done myself in the past. 

You can also now follow me on twitter (@realscottgu) where I also post links and small posts.

ASP.NET

  • Using ASP.NET 3.5’s ListView and DataPager Controls to Delete Data: Scott Mitchell continues his excellent tutorial series on the ASP.NET ListView control. In this article he discusses how to handle deleting data with it.

  • ASP.NET ListView: Displaying Hierarchical Data: Adam Pooler writes about how to use the ASP.NET ListView control to display hierarchical data within a web page.

  • ELMAH: Error Logging Module and Handlers for ASP.NET: ELMAH is a really cool open source error logging module for ASP.NET that can help you figure out what is going wrong with a site in production (and it enables you to diagnose things remotely in a browser).  This post from Scott Hanselman nicely summarizes some of the things you can do with it.  Visit the ELMAH home page to learn more and download it.  Using ELMAH with ASP.NET MVC describes how to use it within ASP.NET MVC applications.

  • Examining ASP.NET 2.0’s Membership, Roles and Profile API Part 14: Scott Mitchell continues his excellent series on ASP.NET’s security features with an article that discusses how to create a page that permits users to update their security question and answer settings to reset passwords.

  • ASP.NET Tip/Trick: Use a Base Page Class for All Application Pages: A nice article that discusses a good best practice with ASP.NET applications – which is to create a helper base class that encapsulates common functionality that you can use across pages within your applications.

AJAX

  • Automatically Minify and Combine JavaScript in Visual Studio: Dave Ward has a great article that describes how you can add a build command to Visual Studio that enables you to automatically compress and combine client-side JavaScript files.  This makes your pages load faster on the client and improves the perceived performance of your sites.

  • Using Complex Types to Make Calling Services lessComplex: Dave Ward has a great post that discusses strategies on how to pass complex types to the server from client-side JavaScript.

  • Client-side Data Binding in ASP.NET AJAX 4.0: Fritz Onion has a great article about the new client-side templating features of ASP.NET AJAX 4.0 (which you can download and use today in .NET 3.5 projects).  This enables powerful client data-binding scenarios against JSON based data.  Also check out Politian’s Blog to find some great tutorials on how to use it.

ASP.NET MVC

  • jQuery Auto-Complete Text Box with ASP.NET MVC: Ben Scheirman has a really nice tutorial (taken from his upcoming ASP.NET MVC in Action book) that describes how to implement an auto-complete textbox using jQuery and ASP.NET MVC.

  • ASP.NET MVC Forms Authentication with Active Directory: Mike has a nice post that shows how to setup an ASP.NET MVC application with Forms Authentication that uses Active Directory as the username/password credential store instead of a database.  Also check out his post on ASP.NET MVC Forms Authentication with SQL Membership to learn more about how to setup forms authentication using a SQL Server database (instead of the default SQL Express one).

  • Visual Studio NUnit Templates for ASP.NET MVC: The VS Web Tools team has released updated NUnit templates that work with ASP.NET MVC 1.0.  This enables you to automatically create a test project that uses NUnit instead of MSTest when you do a File->New Project and select the ASP.NET MVC 1.0 Project item.

  • 13 ASP.NET MVC Extensibility Points You Have to Know: Simone Chiaretta has a post that nicely summarizes 13 extensibility points in ASP.NET MVC and how you can use them to customize your applications.  Also check out the free chapter of his new ASP.NET MVC book.

  • Custom Route Constraints in ASP.NET MVC: Keyvan Nayyeriu has a nice post that discusses how to create a custom route constraint in ASP.NET MVC (one of the extensibility points in Simone’s list above).  You can use these to control whether a route rule is used or not, and they can enable some pretty rich routing scenarios.  Note that in addition to creating route constraint classes, ASP.NET MVC also supports using Regular Expressions and HTTP Method filters to constrain routes as well. Keyvan is the co-author with Simone of the Beginning ASP.NET MVC Book (free chapter available).

Visual Studio

Hope this helps,

Scott

Exposing Custom WCF Headers through WCF Behaviors

Since the WCF Publishing Wizard in BizTalk does not support adding custom headers defined at the server, we need to programmatically modify what gets created by the wizard to add custom headers.  However, from the client you have the option to pass in header values at will.  If you are passing in headers generated at the client BizTalk will take them and map them to the context.  However, they show up as an XML fragment and not as individual data items.  It becomes annoying to constantly parse the fragment each and every time you want to get to the data.


What we are really interested in is the ability to expose the end point with the header values already defined, accept the header values from the client and either promote or write the values to the context and lastly, be able to create a behavior that you can attach to your WCF endpoint that exposes the properties through configuration to let you dynamically, per end point, set the header items and what you want to do with them as they are submitted.  This will be a three part posting with a post covering each of these features.


For this first post, we will focus on the ability to expose the end point with the header values already defined.  What makes this even more interesting is that there is no WSDL file as this gets generated dynamically when you access the SVC file.  If you wish you can create a static WSDL file and then use the externalMetadataLocation attribute of the element in the Web.config file that the wizard generates to specify the location of the WSDL file.  Then the static WSDL file will be sent to the user in response to WSDL and metadata exchange (MEX) requests instead of the auto-generated WSDL. 


In our solution, we did not want to have to create WSDL files for each of our endpoints, nor did we want to maintain them.  We needed a way to hook in to the dynamic WSDL creation process.


There are a number of posts out there that talk about this but after reviewing them I found that none of them gave the whole picture.  They were all very good and they provided enough information to fill in many missing pieces but there was enough missing that I though it warranted looking at the whole picture.


We are going to start by creating our own EndPointBehavior.  The EndPointBehavior allows us to inject custom functionality in the WCF execution pipeline. 


To create the EndPointBehavior we need to create a solution that references System.ServiceModel.dll and includes a class that derives from BehaviorExtensionElement, IWsdlExportExtension and IEndpointBehavior.  We need the functionality of the BehaviorExtensionElement to implement the configuration of the behavior, the functionality of the IWsdlExportExtension to change the generated WSDL and the functionality of the IEndPointBehavior to define the endpoint and its behavior.


Lets add a class file to our solution called SoapHeaderEndpointBehavior.  After we create the class and inherit from our objects we need to add the following line of code to the ExportEndPoint method


SoapHeaderWsdlExport.ExportEndpoint(exporter,context);


and we need to add the following two lines of code to the ApplyDispatchBehavior method.


SoapHeaderMessageInspector headerInspector = new SoapHeaderMessageInspector();
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(headerInspector);


Our code should look like this:


using System;
using System.Collections.Generic;
using System.Collections;
using System.Configuration;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Configuration;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.Text;
using System.Xml;
using System.Xml.Schema;
using System.Web.Services;
using System.Web.Services.Description;
using WsdlDescription = System.Web.Services.Description.ServiceDescription;

namespace Services.WCF.ServiceBehavior
{
    public class SoapHeaderEndpointBehavior : BehaviorExtensionElement, IWsdlExportExtension, IEndpointBehavior
   
{
        #region BehaviorExtensionElement Members

            public override Type BehaviorType
           
{
                get
               
{
                    return typeof(SoapHeaderEndpointBehavior);
               
}
           
}

            protected override object CreateBehavior()
           
{
                return new SoapHeaderEndpointBehavior();
           
}
       
#endregion

        #region IWsdlExportExtension Members

            public void ExportContract(WsdlExporter exporter, WsdlContractConversionContext context)
           
{
                //throw new NotImplementedException();
           
}

            public void ExportEndpoint(WsdlExporter exporter, WsdlEndpointConversionContext context)
           
{
                SoapHeaderWsdlExport.ExportEndpoint(exporter,context);
           
}

       
#endregion

        #region IEndpointBehavior Members

            public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
           
{
                //throw new NotImplementedException();
           
}

            public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
           
{
                //throw new NotImplementedException();
           
}

            public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
           
{
                SoapHeaderMessageInspector headerInspector = new SoapHeaderMessageInspector();
                endpointDispatcher.DispatchRuntime.MessageInspectors.Add(headerInspector);
           
}

            public void Validate(ServiceEndpoint endpoint)
           
{
               //throw new NotImplementedException();
           
}

       
#endregion
   
}
}


When we added code to the ExportEndpoint method, we utilized a custom object.  Let’s add another class to our solution to implement the SoapHeaderWsdlExport.  This class will add a header schema and its namespace, create and add a header message description and finally add the header to the operation.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Schema;
using System.Reflection;
using System.Web.Services.Description;
using System.Xml;
using System.ServiceModel.Description;
using WsdlDescription = System.Web.Services.Description.ServiceDescription;

namespace Services.WCF.ServiceBehavior
{
    class SoapHeaderWsdlExport
   
{
        public static void ExportEndpoint(WsdlExporter exporter, WsdlEndpointConversionContext context)
       
{
            // Read the schema of the custom header message
           
XmlSchema customSoapHeaderSchema = XmlSchema.Read(Assembly.GetExecutingAssembly().GetManifestResourceStream(“Services.WCF.ServiceBehavior.SoapHeader.xsd”),
                new ValidationEventHandler (SoapHeaderWsdlExport.ValidationCallBack));

            // Create the HeaderMessage to add to wsdl:message AND to refer to from wsdl:operation
           
System.Web.Services.Description.Message headerMessage = CreateHeaderMessage();

           
foreach (WsdlDescription wsdl in exporter.GeneratedWsdlDocuments)
           
{
                // Add the schema of the CustomSoapHeader to the types AND add the namespace to the list of namespaces
               
wsdl.Types.Schemas.Add(customSoapHeaderSchema);
               
wsdl.Namespaces.Add(“sh”, SoapHeaderNames.SoapHeaderNamespace);

                // The actual adding of the message to the list of messages
               
wsdl.Messages.Add(headerMessage);
           
}

           
addHeaderToOperations(headerMessage, context);
       
}

        private static System.Web.Services.Description.Message CreateHeaderMessage()
       
{
            // Create Message
           
System.Web.Services.Description.Message headerMessage = new System.Web.Services.Description.Message();

            // Set the name of the header message
           
headerMessage.Name = SoapHeaderNames.SoapHeaderName;

            // Create the messagepart and add to the header message
           
MessagePart part = new MessagePart();
           
part.Name = “Header”;
           
part.Element = new XmlQualifiedName(SoapHeaderNames.SoapHeaderName, SoapHeaderNames.SoapHeaderNamespace);
           
headerMessage.Parts.Add(part);

            return headerMessage;
       
}

        private static void addHeaderToOperations(System.Web.Services.Description.Message headerMessage, WsdlEndpointConversionContext context)
       
{
            // Create a XmlQualifiedName based on the header message, this will be used for binding the header message and the SoapHeaderBinding
           
XmlQualifiedName header = new XmlQualifiedName(headerMessage.Name, headerMessage.ServiceDescription.TargetNamespace);

           
foreach (OperationBinding operation in context.WsdlBinding.Operations)
           
{
                // Add the SoapHeaderBinding to the MessageBinding
               
ExportMessageHeaderBinding(operation.Input, context, header, false);
               
ExportMessageHeaderBinding(operation.Output, context, header, false);
           
}
       
}

        private static void ExportMessageHeaderBinding(MessageBinding messageBinding, WsdlEndpointConversionContext context, XmlQualifiedName header, bool isEncoded)
       
{
            // For brevity, assume Soap12HeaderBinding for Soap 1.2
           
SoapHeaderBinding binding = new Soap12HeaderBinding();
           
binding.Part = “Header”;
           
binding.Message = header;
           
binding.Use = isEncoded ? SoapBindingUse.Encoded : SoapBindingUse.Literal;

           
messageBinding.Extensions.Add(binding);
       
}

        private static void ValidationCallBack(object sender, ValidationEventArgs args)
       
{
            if (args.Severity == XmlSeverityType.Warning)
                Console.WriteLine(“\tWarning: Matching schema not found. No validation occurred.” + args.Message);
            else
               
Console.WriteLine(“\tValidation error: ” + args.Message);

        }

   
}
}


In the addHeaderToOperations method there are two calls to the ExportMessageHeaderBinding method.  The second call passes the operation.Output parameter which will pass the header back to the calling application with the response message.  This also also means that the method signature at the client will be to pass in the header object by Ref.  Since we needed the client to pass the header data into BizTalk we didn’t need to echo the header back to the client so we deleted this line.  If you want to echo it back then keep this line (as shown in the code above).


Also, in the code above, in the ExportEndpoint and CreateHeaderMessage methods there was another custom class called SoapHeaderNames.  This class contained the values that we wanted to place in the custom header.  By creating a class for this data we could limit the location of this information to one location.  The code for the SoapHeaderNames class looks like this:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Services.WCF.ServiceBehavior
{
    public static class SoapHeaderNames
   
{
        public const String SoapHeaderName = “SoapHeader”;

        public const String AppName = “App”;
        public const String UserName = “User”;

        public const String SoapHeaderNamespace = http://servicebehavior.mycompany.com;
   
}
}


Way back at the top, in the ApplyDispatchBehavior method of the SoapHeaderEndpointBehavior class we have a custom object called SoapHeaderMessageInspector.  Therefore, let’s add another class for the SoapHeaderMessageInspector.  There are two methods that we must implement on the IDispatchMessageInspector and they are the AfterReceiveRequest and the BeforeReceiveRequest.  Since we are interested in applying the headers in the dynamic WSDL we will only need code in the BeforeReceiveRequest.  The code will look like this:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel.Dispatcher;
using System.ServiceModel;
using System.Xml;

namespace Services.WCF.ServiceBehavior
{
    class SoapHeaderMessageInspector: IDispatchMessageInspector
   
{

        #region IDispatchMessageInspector Members

            public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
           
{
                return null;
           
}

            public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
           
{
                // Look for my custom header in the request
                Int32 headerPosition = OperationContext.Current.IncomingMessageHeaders.FindHeader(SoapHeaderNames.SoapHeaderName, SoapHeaderNames.SoapHeaderNamespace);

                // Get an XmlDictionaryReader to read the header content
               
XmlDictionaryReader reader = OperationContext.Current.IncomingMessageHeaders.GetReaderAtHeader(headerPosition);

                // Read through its static method ReadHeader
               
SoapHeader header = SoapHeader.ReadHeader(reader);

                if (header != null)
               
{
                    // Add the header from the request
                   
reply.Headers.Add(header);
               
}
           
}

       
#endregion
   
}
}


This code grabs the header section and will inject the header elements.  In the BeforeSendReply method you will see we are using a SoapHeader object.  This object contains the properties and methods to deal with the elements that we will be reading and writing to the header.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.ServiceModel.Channels;

namespace Services.WCF.ServiceBehavior
{
   
[Serializable]
    public class SoapHeader: MessageHeader
   
{
        private string _app;
        private string _user;

        public string App
       
{
            get
           
{
                return (this._app);
           
}
            set
           
{
               
this._app = value;
           
}
       
}

        public string User
       
{
            get
           
{
                return (this._user);
           
}
            set
           
{
                this._user = value;
           
}
       
}

        public SoapHeader()
       
{
       
}

        public SoapHeader(string app, string user)
       
{
            this._app = app;
            this._user = user;
        }

        public override string Name
       
{
            get { return (SoapHeaderNames.SoapHeaderName); }
        }

        public override string Namespace
       
{
            get { return (SoapHeaderNames.SoapHeaderNamespace); }
        }

         protected override void OnWriteHeaderContents(System.Xml.XmlDictionaryWriter writer, MessageVersion messageVersion)
       
{
            // Write the content of the header directly using the XmlDictionaryWriter
           
writer.WriteElementString(SoapHeaderNames.AppName, this.App);
           
writer.WriteElementString(SoapHeaderNames.UserName, this.User);
        }

        public static SoapHeader ReadHeader(XmlDictionaryReader reader)
       
{
            String app = null;
            String user = null;

            // Read the header content (key) using the XmlDictionaryReader
            if (reader.ReadToDescendant(SoapHeaderNames.AppName, SoapHeaderNames.SoapHeaderNamespace))
           
{
                app = reader.ReadElementString();
           
}

            if (reader.ReadToDescendant(SoapHeaderNames.UserName, SoapHeaderNames.SoapHeaderNamespace))
           
{
                user = reader.ReadElementString();
           
}

            if (!String.IsNullOrEmpty(app) && !String.IsNullOrEmpty(user))
           
{
                return new SoapHeader(app, user);
           
}
            else
           
{
                return null;
           
}
       
}

   
}
}


There is also a schema, called SoapHeader.xsd, that needs to be added to the project as well.  This schema defines the message contract for the header and is referenced and used in the ExportEndpoint method of the SoapHeaderWsdlExport class and looks like this:


<?xml version=”1.0″ encoding=”utf-16″?>
<xs:schema xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xmlns:b=”http://schemas.microsoft.com/BizTalk/2003″ xmlns=”http://servicebehavior.mycompany.com” attributeFormDefault=”unqualified” elementFormDefault=”qualified” targetNamespace=”http://servicebehavior.mycompany.com” xmlns:xs=”http://www.w3.org/2001/XMLSchema”>
   
<xs:element name=”SoapHeader”>
       
<xs:complexType>
           
<xs:sequence>
               
<xs:element name=”App” type=”xs:string” />
               
<xs:element name=”User” type=”xs:string” />
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>


At this point we have all the code that is part of our project.  Once this is compiled, we need to add the assembly to the machine config. 


There is an easy way to add entries by using the SvcConfigEditor.exe tool.  This tool is part of the Windows SDK and, if installed, can be found in the \Program Files\Microsoft SDKs\Windows\v6.0A\Bin directory. 


Once this utility is open you can click on the File ->Open->Config File menu item.  Open the machine.config file.  At the bottom of the tree view on the left side you will see an Advanced folder.  Expand that node and expand the the Extensions folder.  Click on the the ‘behavior element extensions’ node.  At the bottom right, click on the new button.  This will bring up the Extension Configuration Element Editor dialog box.  Enter the name you wish to give to your extension and then click on the ellipses next to type.  This will bring up the Type Browser dialog box.  Browse to your component (also note that you can select assemblies already placed in the GAC).  Once selected, your fully qualified assembly name will be entered.  Select Save under the File menu.  You are now ready to start using the new behavior.


Up to this point everything we have done has been specifically WCF functionality.  The next paragraph will outline how we can utilized this behavior in a BizTalk WCF endpoint. 


Create a WCF endpoint in BizTalk (if you need more information on creating a WCF endpoint check out the docs on MSDN (Insert Link)).  One thing to keep in mind is that when you create a WCF end point in BizTalk using one of the standard bindings you will not have the option to specify a behavior.  In order to specify a behavior you need to specify either the WCF-Custom or WCF-CustomIsolated binding.  Once you select the binding type, click on the Configure button and the Transport Properties dialog will appear.  Select the Behavior tab and then right click on the the Endpoint Behavior node.  Once the popup menu appears, select Add extension.  Select your behavior from the Select Behavior Extensions dialog box and click OK.  Enter the rest of the specific information you need for the end point and click OK to save your endpoint.


We have now done everything that is needed to create a custom behavior including the ability to link into the dynamic WSDL creation process at run time, register the behavior and finally to use the behavior.


Now, when you create a client against the end point you will see that there will be two parameters for the web method call.  The first will be the custom header and the second will be the message body.  When we look in the object browser for the header object we will see that the two items appear that we defined in our behavior. 


As I said at the beginning of this post, this will be a three part series.  What we have not covered is the ability to accept these header values from the client and promote or write the values to the context (part 2) and we have not covered the ability to create a behavior that exposes the properties through configuration to let you dynamically, per end point, set the header items (part 3).