Archive for the ‘WCF’ Category.

Host WCF Services in IIS with Service Bus Endpoints

Vishal Chowdhary, a Senior Test Lead on the Azure AppFabric team, recently posted a whitepaper on hosting WCF services with Service Bus endpoints from IIS.  This whitepaper provides two solutions to a (previously) significant challenge in hosting WCF services in IIS that connect to the Azure AppFabric Service Bus.

The primary challenge is activation. As Vishal writes, “For the on-premise WCF service to start receiving messages from the Service Bus in the cloud (aka Relay Service), the on-premises service opens an outbound port and creates a bidirectional socket for communication.  It connects to the Service Bus, authenticates itself, and starts listening to calls from the relay service before the client sends its requests.”  He goes on to say that “IIS/WAS relies on message-based activation & will launch the host only after the first request comes in.”  Consequently, until the first message is received by IIS the service will never establish a connection to the Service Bus; with no connection to the Service Bus, it will never receive a message.  A bit of a dilemma.

In the whitepaper, Vishal points out two ways to resolve this challenge:

  • IIS Application Warm-Up
  • ASP.NET 4.0 Auto-Start

In this post, I’m going to highlight exactly how to go about using IIS Application Warm-Up to get a WCF service hosted in IIS 7.5 to receive messages from the Service Bus.  This post borrows heavily from Visha’s whitepaper; I strongly suggest you spend the time to read the entire paper.

  1. If you’re using .NET 4.0, you must setup .NET 4.0 to work with the Azure AppFabric SDK.
  2. Create a new ASP.NET Web Application project called EchoSample in Visual Studio 2010 using .NET 4.0.
  3. To validate this approach, we want this project hosted in IIS.  Right-click the project and choose Properties.  Select the Web tab, and switch from Use Visual Studio Development Server to Use Local IIS Web server and click Create Virtual Directory.
  4. Add the Microsoft.ServiceBus reference from the “C:\%Program Files%\Windows Azure platform AppFabric SDK\V1.0\Assemblies\” folder.
  5. You have to create a custom BehaviorExtensionElement for the ServiceRegistrySettings to make the discoverability policy ‘Public’ in the configuration file.  Consequently, we need to create a class that we’ll call MyServiceRegistrySettingsElement that inherits the BehaviorExtensionElement.
public class MyServiceRegistrySettingsElement : BehaviorExtensionElement
{
    public override Type BehaviorType
    {
        get { return typeof(ServiceRegistrySettings); }
    }
    protected override object CreateBehavior()
    {
        return new ServiceRegistrySettings() {
           DiscoveryMode = this.DiscoveryMode,
           DisplayName = this.DisplayName };
    }
    [ConfigurationProperty("discoveryMode", DefaultValue = DiscoveryType.Private)]
    public DiscoveryType DiscoveryMode
    {
        get { return (DiscoveryType)this["discoveryMode"]; }
        set { this["discoveryMode"] = value; }
    }
    [ConfigurationProperty("displayName")]
    public string DisplayName
    {
        get { return (string)this["displayName"]; }
        set { this["displayName"] = value; }
    }
}
  1. Now, let’s add a new WCF Service called EchoService to the project.  Remove the existing method in the ServiceContract and create the following GetData method in the IEchoService.cs file.
[OperationContract]
string GetData(int value);
  1. Also, update the EchoService.svc.cs with the implementation of the GetData method.
public string GetData(int value)
{
    if (value < 0)
        throw new ApplicationException("Negative values not allowed!!!");

    Thread.Sleep(value);
    return string.Format("You entered: {0}", value);
}
  1. Now we need to update the web.config settings.  This is fairly extensive. Be sure and replace YOUR_NAMESPACE, YOUR_ISSUER_NAME, and YOUR_ISSUER_SECRET with your own values.
<system.serviceModel>
  <extensions>
    <behaviorExtensions>
      <add name="ServiceRegistrySettings"
            type="EchoSample.MyServiceRegistrySettingsElement, EchoSample,
            Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
    </behaviorExtensions>
  </extensions>
  <services>
    <clear />
    <service behaviorConfiguration="MyServiceTypeBehavior"
             name="EchoSample.EchoService">
      <endpoint address="http://localhost/EchoSample/EchoService.svc/LocalEchoService"
                binding="basicHttpBinding"
                bindingConfiguration="BasicHttpConfig"
                name="Basic" contract="EchoSample.IEchoService" />
      <endpoint address="https://YOUR_NAMESPACE.servicebus.windows.net/EchoServiceHttp/"
                behaviorConfiguration="sharedSecretClientCredentials"
                binding="basicHttpRelayBinding"
                bindingConfiguration="HttpRelayEndpointConfig"
                name="RelayEndpoint"
                contract="EchoSample.IEchoService" />
      <endpoint address="sb://YOUR_NAMESPACE.servicebus.windows.net/EchoServiceNetTcp/"
                behaviorConfiguration="sharedSecretClientCredentials"
                binding="netTcpRelayBinding"
                bindingConfiguration="NetTcpRelayEndpointConfig"
                name="RelayEndpoint"
                contract="EchoSample.IEchoService" />
    </service>
  </services>
  <bindings>
    <basicHttpBinding>
      <binding name="BasicHttpConfig" />
    </basicHttpBinding>
    <!--service bus binding-->
    <basicHttpRelayBinding>
      <binding name="HttpRelayEndpointConfig">
        <security relayClientAuthenticationType="RelayAccessToken" />
      </binding>
    </basicHttpRelayBinding>
    <netTcpRelayBinding>
      <binding name="NetTcpRelayEndpointConfig">
        <security relayClientAuthenticationType="RelayAccessToken" />
      </binding>
    </netTcpRelayBinding>
  </bindings>
  <behaviors>
    <endpointBehaviors>
      <behavior name="sharedSecretClientCredentials">
        <transportClientEndpointBehavior credentialType="SharedSecret">
          <clientCredentials>
            <sharedSecret issuerName="YOUR_ISSUER_NAME" issuerSecret="YOUR_ISSUER_SECRET" />
          </clientCredentials>
        </transportClientEndpointBehavior>
        <ServiceRegistrySettings discoveryMode="Public" />
      </behavior>
    </endpointBehaviors>
    <serviceBehaviors>
      <behavior name="MyServiceTypeBehavior">
        <serviceMetadata httpGetEnabled="true" />
        <serviceDebug includeExceptionDetailInFaults="true" />
      </behavior>
    </serviceBehaviors>
  </behaviors>
</system.serviceModel>

At this point, once you compile and build the solution, the service will not automatically connect to the Service Bus; this is because IIS/WAS waits until the first service call to activate.  Consequently, if you load the WCF service in the browser it will activate the service and establish a connection to the Service Bus (you can confirm by checking https://YOUR_NAMESPACE.servicebus.windows.net/).  So, we’re close, but not yet there.

To get the service to automatically establish the connection to the Service Bus, we’ll use the Application Warm-Up extension for IIS 7.5.

  1. Download and install the Application Warm-Up extension for IIS 7.5.  This gives us the ability to proactively load and initialize processes before the first request arrives.  In addition to improving responsiveness it also gives us the ability to connect our WCF service to the Azure AppFabric Service Bus.
  2. In IIS, select your virtual application EchoSample.  Double-click the Application Warm-Up feature, and click Settings.  Check the Start Application Pool ‘ASP.NET v4.0’ when service started checkbox.

Application Warm-Up settings

  1. Add a new request to register EchoService.svc as a warm-up request for the application.  Right-click and choose Add Request.  Enter EchoService.svc, and click OK.  You should now see it in the Request URL list.

Application Warm-Up add request

Application Warm-Up

And that’s it!  The service is now automatically started and “warmed up” by IIS.  To test, recycle the Application Pool and restart the web site.  Then, hit your Service Bus endpoint and confirm that you’re services are running.

Publicly Listed Services

Now, even if we restart the computer, the WCF service will reestablish the connection to the Service Bus because IIS 7.5, through the Application Warm-Up Extensions, will automatically refresh.

Now, to complete the test, let’s build a quick Console application to connect to the WCF service via the Service Bus.

  1. Create a new Console Application project called Client.
  2. Add a reference to the Microsoft.ServiceBus and System.ServiceModel.
  3. Add a link to the IEchoService.cs file in the EchoSample project.  Right-click the project, choose Add Existing, and change Add to Add as Link.

Add Existing Item - Add As Link 

  1. Update the Program.cs file with the following code.  Be sure and replace YOUR_NAMESPACE, YOUR_ISSUER_NAME, and YOUR_ISSUER_SECRET with your own values.
class Program
{
    static void Main(string[] args)
    {
        // Determine the system connectivity mode based on the command line
        // arguments: -http, -tcp or -auto  (defaults to auto)
        ServiceBusEnvironment.SystemConnectivity.Mode = GetConnectivityMode(args);
        string serviceNamespace = "YOUR_NAMESPACE";
        string issuerName = "YOUR_ISSUER_NAME";
        string issuerSecret = "YOUR_ISSUER_SECRET";
        // create the service URI based on the service namespace
        Uri serviceUri = ServiceBusEnvironment.CreateServiceUri("sb",
            serviceNamespace, "EchoServiceNetTcp");
        //Uri serviceUri = ServiceBusEnvironment.CreateServiceUri(
        //    "https", serviceNamespace, "EchoServiceHttp");
        // create the credentials object for the endpoint
        TransportClientEndpointBehavior sharedSecretServiceBusCredential =
            new TransportClientEndpointBehavior();
        sharedSecretServiceBusCredential.CredentialType =
            TransportClientCredentialType.SharedSecret;
        sharedSecretServiceBusCredential.Credentials.SharedSecret.IssuerName =
            issuerName;
        sharedSecretServiceBusCredential.Credentials.SharedSecret.IssuerSecret =
            issuerSecret;
        // create the channel factory loading the configuration
        //BasicHttpRelayBinding myBinding = new BasicHttpRelayBinding();
        NetTcpRelayBinding myBinding = new NetTcpRelayBinding();
        EndpointAddress myEndpoint = new EndpointAddress(serviceUri);
        ChannelFactory<IEchoService> channelFactory =
            new ChannelFactory<IEchoService>(myBinding, myEndpoint);
        // apply the Service Bus credentials
        channelFactory.Endpoint.Behaviors.Add(sharedSecretServiceBusCredential);
        // create and open the client channel
        IEchoService channel = channelFactory.CreateChannel();
        Console.WriteLine("Enter text to echo (or [Enter] to exit):");
        string input = Console.ReadLine();
        while (input != String.Empty)
        {
            try
            {
                Console.WriteLine("Server echoed: {0}",
                    channel.GetData(Int32.Parse(input)));
            }
            catch (Exception e)
            {
                Console.WriteLine("Error: " + e.Message);
            }
            input = Console.ReadLine();
        }
        if (((IClientChannel)channel).State != CommunicationState.Faulted)
            ((IClientChannel)channel).Close();
        else
            ((IClientChannel)channel).Abort();
        channelFactory.Close();
    }
    static ConnectivityMode GetConnectivityMode(string[] args)
    {
        foreach (string arg in args)
        {
            if (arg.Equals("/auto", StringComparison.InvariantCultureIgnoreCase) ||
                    arg.Equals("-auto", StringComparison.InvariantCultureIgnoreCase))
            {
                return ConnectivityMode.AutoDetect;
            }
            else if (arg.Equals("/tcp", StringComparison.InvariantCultureIgnoreCase) ||
                    arg.Equals("-tcp", StringComparison.InvariantCultureIgnoreCase))
            {
                return ConnectivityMode.Tcp;
            }
            else if (arg.Equals("/http", StringComparison.InvariantCultureIgnoreCase) ||
                    arg.Equals("-http", StringComparison.InvariantCultureIgnoreCase))
            {
                return ConnectivityMode.Http;
            }
        }
        return ConnectivityMode.AutoDetect;
    }
}

When you run the console application, it will connect to your WCF service through the Service Bus.  Run it to validate. You can also uncomment some of the code to use BasicHttpRelayBinding instead of NetTcpRelayBinding to try out a different configuration.

The ability to host a WCF service in IIS that exposes itself on the Service Bus is a significant milestone.  This opens up a number of fantastic opportunities and scenarios that otherwise would have been extremely difficult to accomplish.

I’ll show the second scenario – using ASP.NET 4.0 Auto-Start – in a future post.

A few tips when using WCF with BizTalk Server 2006 R2

As I was putting together the demonstration for the talk I’m giving tomorrow on BizTalk Server R2 and the WCF Adapters I had to do a few things to get some basic examples working, as this was a brand new virtual environment.  I thought I’d document some of the actions I had to take.

1. Registering the “WCF-BasicHttp” adapter.

After creating and deploying an orchestration for use with the “WCF-BasicHttp” adapter, I received the following error:

The Messaging Engine failed to register the adapter for “WCF-BasicHttp” for the receive location “/SampleWCFDemo/SampleWCFDemo_Process_ProcessPort.svc”. Please verify that the receive location exists, and that the isolated adapter runs under an account that has access to the BizTalk databases.

I had to take two steps to resolve the problem.  First, create a new application pool and set the identity to the service account used by the isolated host instance.  Second, give the service account used by the isolated host instance read/write access to the C:\Windows\Temp\ directory.

2. Can’t find the “SvcUtil.exe” console application.

Turns out that I had forgotten to install the Windows SDK and .NET Framework 3.0 Runtime Components.  See my previous post on how to setup a BizTalk Server 2006 R2 development environment for more information.

3. “SvcUtil.exe” failed when generating the service metadata.

When I ran the command “C:\Program Files\Microsoft SDKs\Windows\v6.0\Bin\SvcUtil.exe”
http://localhost/SampleWCFDemo/SampleWCFDemo_Process_ProcessPort.svc?wsdl I ended up getting the following error:

Error: Cannot obtain Metadata from http://localhost/SampleWCFDemo/SampleWCFDemo_Process_ProcessPort.svc?wsdl

If this is a Windows (R) Communication Foundation service to which you have access, please check that you have enabled metadata publishing at the specified address.  For help enabling metadata publishing, please refer to the MSDN documentation at http://go.microsoft.com/fwlink/?LinkId=65455.

WS-Metadata Exchange Error
    URI: http://localhost/SampleWCFDemo/SampleWCFDemo_Process_ProcessPort.svc?wsdl
    Metadata contains a reference that cannot be resolved: ‘http://localhost/SampleWCFDemo/SampleWCFDemo_Process_ProcessPort.svc?wsdl’.
    Content Type application/soap+xml; charset=utf-8 was not supported by service http://localhost/SampleWCFDemo/SampleWCFDemo_Process_ProcessPort.svc?wsdl .  The client and service bindings may be mismatched.
    The remote server returned an error: (415) Cannot process the message because the content type ‘application/soap+xml; charset=utf-8′ was not the expected type ‘text/xml; charset=utf-8′..

HTTP GET Error
    URI: http://localhost/SampleWCFDemo/SampleWCFDemo_Process_ProcessPort.svc?wsdl

Additionally, when I loaded the WSDL in Internet Explorer, I got the message:

Metadata publishing for this service is currently disabled.

Turns out that I had to change the service behavior to allow the metadata to be published.  You can do this by modifying the Web.Config file of the service so that “httpHelpPageEnabled” is set to true:

<behavior name=”ServiceBehaviorConfiguration”>
    <serviceMetadata httpGetEnabled=”true” httpsGetEnabled=”false” />
</behavior>

Changing the value from “false” to “true” resolves the problem.

Those were the three issues that came up tonight.  I’m sure there will be more, and I’ll post the resolutions when I can.

I hope this helps!

Setting up a BizTalk Server 2006 R2 (beta 2) development environment

In preparation for the talk I am giving tomorrow on BizTalk Server R2 and the WCF Adapters, I thought I would post some notes on how to setup and configure a BizTalk Server 2006 R2 development environment.
The installation is really quite straightforward.  Start with a relatively clean machine (I suggest you use a virtual machine, as these are all beta bits).  My (virtual) machine had the following installed before I started the R2 installation:

  • Windows Server 2003 R2 Standard Edition with Service Pack 2
  • IIS 6.0
  • Microsoft .NET 1.0, 1.1, 2.0, 3.0
  • Microsoft Visual Studio 2005 Team Developer Edition with Service Pack SP1
  • SQL Server 2005 with Service Pack SP2

Additionally, you need to install the Windows SDK and .NET Framework 3.0 Runtime Components.  This gives you the documentation, samples, header files, libraries, and tools you need to develop applications that run on Windows.  You can download this from: http://www.microsoft.com/downloads/details.aspx?FamilyId=C2B1E300-F358-4523-B479-F53D234CDCCF&displaylang=en.  Note: it takes awhile, so be patient.  Also, I removed the documentation and samples, which makes the download and installation a lot faster.
From here you just need to download the R2 bits.  To find out how you can obtain BizTalk Server 2006 R2 (beta 2), take a look at this article: http://support.microsoft.com/kb/936046.  Or, if you want me to save you the work and take you directly to the bits, you can go here: https://connect.microsoft.com/Downloads/DownloadDetails.aspx?SiteID=65&DownloadID=6014.
The BizTalk 2006 R2 Beta 2 release includes the following components:

  • BizTalk core engine
  • EDI
  • RFID
  • LOB Adapters
  • BizTalk Accelerators (HL7, SWIFT, RosettaNet)

The components are available by downloading and installing the following files:

  • BTS06R2_Beta2.exe
  • BTS06R2_Beta2_Accelerators.zip
  • BizTalk LOB Adapters Sp1 Beta2.exe
  • CustomSOAPHeaderPipeline.zip

Note: if you only want the R2 functionality (e.g. WCF, etc) you only need BTS06R2_Beta2.exe.
After I downloaded all the files, I first extracted the contents of BTS06R2_Beta2.exe to a temporary folder (choose a folder you can remember, like C:\Temp\BTS06R2_Beta2).  Next, I ran Setup.exe from that folder.  Click Next until you get to the Component Installation screen.  You’ll see that there are a few differences from the standard BizTalk components.  Here’s a peak:
 BizTalk Server 2006 R2 Installation Wizard
I decided to leave the default settings.  Feel free to do what you want.  Continue to click Next until you get to the Summary screen.  Review your selections and click Install (you may also want to set your auto-login credentials to save time).
After it installs you have to run the BizTalk Configuration Tool.  The configuration is roughly the same as it is for BizTalk Server 2006:
BizTalk Server 2006 R2 Configuration
I don’t plan on using many of the features at the moment (e.g. BAM, HWS, etc.) so I only installed the following features:
BizTalk Server 2006 R2 Features
And that’s it!  At this point, you will have BizTalk 2006 R2 (beta 2) installed and functioning.  Open up the BizTalk Server 2006 Administration Console and take a look at the adapters now available to you:
BizTalk Server 2006 R2 Adapters
Specifically, you now can use the following adapters:

  • WCF-BasicHttp
  • WCF-Custom
  • WCF-CustomIsolated
  • WCF-NetMsmq
  • WCF-NetNamedPipe
  • WCF-NetTcp
  • WCF-WSHttp

I hope this helps you explore the new functionality available to you in BizTalk Server 2006 R2.  Enjoy!

Presenting to the Denver BizTalk User Group

I know this notice is late, but I will be presenting a talk entitled “BizTalk Server 2006 R2 and the WCF Adapters” to the Denver BizTalk User Group tomorrow.  Here’s the link to the event:

BizTalk User Group: BizTalk Server 2006 R2 and the WCF Adapters

The event will take place at the Denver Microsoft building at the following address:

Maroon Bells Room
7595 Technology Way
Suite 400 Denver Colorado 80237
United States

Here’s the event abstract …

BizTalk Server 2006 R2 provides new adapters that enable simple communication to and from BizTalk Server and Web services-based applications via the Windows Communication Foundation (WCF). Through the WCF Adapter SDK you can utilize these new extensions to write WCF-based transports to expose existing technologies and applications. We will discuss real world uses for the WCF adapters and provide a demonstration of these adapters in action.

I’ll post my slide deck and some bits after the presentation.  I hope to see  you there!