Step 3: Implement a REST-based WCF Service Contract to use Service Bus

Important

This tutorial is moving to a new location, and this version will soon be retired. You can view the most recent version here: https://azure.microsoft.com/en-us/documentation/articles/service-bus-relay-rest-tutorial/.

This is the third of four tasks required to create a basic REST-style Service Bus service. For an overview of all tasks, see the Service Bus REST Tutorial.

Creating a REST-style Service Bus service requires that you first create the contract, which is defined by using an interface. For more information about creating the interface, see Step 2: Define a REST-based WCF Service Contract to use with Service Bus. The next step, shown in this example, is to implement the interface. This involves creating a class named ImageService that implements the user-defined IImageContract interface. After you implement the contract, you then configure the interface using an App.config file. The configuration file contains necessary information for the application, such as the name of the service, the name of the contract, and the type of protocol that is used to communicate with the Service Bus. The code used for these tasks is provided in the example following the procedure.

As with the previous steps, there is very little difference between implementing a REST-style contract and a basic Service Bus contract.

Expected time to completion: 10 minutes

To implement a REST-style Service Bus contract

  1. Create a new class named ImageService directly underneath the definition of the IImageContract interface. The ImageService class implements the IImageContract interface.

    class ImageService : IImageContract
    {
    }
    

    Similar to other interface implementations, you can implement the definition in a different file. However, for this tutorial, the implementation appears in the same file as the interface definition and Main() method.

  2. Apply the ServiceBehaviorAttribute attribute to the IImageService class to indicate that the class is an implementation of a WCF contract:

    [ServiceBehavior(Name = "ImageService", Namespace = "https://samples.microsoft.com/ServiceModel/Relay/")]
    class ImageService : IImageContract
    {
    }
    

    As mentioned previously, this namespace is not a traditional namespace. Instead, it is part of the WCF architecture that identifies the contract. For more information, see the Data Contract Names topic in the WCF documentation.

  3. Add a .jpg image to your project.

    This is a picture the service displays in the receiving browser. Right-click your project, click Add. Then click Existing Item. Use the Add Existing Item dialog to browse to an appropriate .jpg, and then click Add. An example .jpg file is available at <SDKInstallDir>\Samples\ServiceBus\ExploringFeatures\Bindings\WebHttp\CS35\Service\image.jpg.

    When adding the file, make sure that All Files (*.*) is selected in the drop-down list next to the File name: field. The rest of this tutorial assumes that the name of the image is “image.jpg”. If you have a different .jpg, you will have to rename the image, or change your code to compensate.

  4. To make sure that the running service can find the image file, in Solution Explorer right-click the image file. In the Properties pane, set Copy to Output Directory to Copy if newer.

  5. Add references to the System.Drawing.dll, System.Runtime.Serialization.dll, and Microsoft.ServiceBus.dll assemblies to the project, and also to the following associated using statements.

    using System.Drawing;
    using System.Drawing.Imaging;
    using Microsoft.ServiceBus;
    using Microsoft.ServiceBus.Web;
    
  6. Define a constructor that loads the bitmap and prepares to send it to the client browser:

    class ImageService : IImageContract
    {
        const string imageFileName = "image.jpg";
    
        Image bitmap;
    
        public ImageService()
        {
            this.bitmap = Image.FromFile(imageFileName);
        }
    }
    
  7. Directly underneath the previous code, add the following GetImage method in the ImageService class to return an HTTP message that contains the image:

    public Stream GetImage()
    {
       MemoryStream stream = new MemoryStream();
       this.bitmap.Save(stream, ImageFormat.Jpeg);
    
       stream.Position = 0;
       WebOperationContext.Current.OutgoingResponse.ContentType = "image/jpeg";
    
       return stream;
    }
    

    This implementation uses MemoryStream to retrieve the image and prepare it for streaming to the browser. It starts the stream position at zero, declares the stream content as a jpeg, and streams the information.

  8. From the Build menu, click Build Solution to build the whole solution.

To define the configuration to run the web service on Service Bus

  1. Right-click the ImageListener project. Then click Add, New Item.

  2. In the Add New Item dialog, in the Templates pane, select Application Configuration. Then click Add.

    The configuration file resembles a WCF configuration file, and includes the service name, endpoint (that is, the location Service Bus exposes for clients and hosts to communicate with each other), and binding (the type of protocol that is used to communicate). The main difference here is that the configured service endpoint refers to a WebHttpRelayBinding binding, which is not part of the .NET Framework. WebHttpRelayBinding is one of the new bindings introduced with Service Bus. For more information about how to configure an Service Bus application, see Configuring a .NET Services Application.

  3. In Solution Explorer, click App.config, which currently contains the following XML elements:

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
    </configuration>
    
  4. Add an XML element to the App.config file for system.serviceModel. This is a WCF element that defines one or more services. Here, it is used to define the service name and endpoint.

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <system.serviceModel>
    
      </system.serviceModel>
    
    </configuration>
    
  5. Within the system.serviceModel element, add a <bindings> element that has the following content. This defines the bindings used in the application. You can define multiple bindings, but for this tutorial you are defining only one.

    <bindings>
      <!-- Application Binding -->
      <webHttpRelayBinding>
        <binding name="default">
          <security relayClientAuthenticationType="None" />
        </binding>
      </webHttpRelayBinding>
    </bindings>
    

    This step defines a Service Bus WebHttpRelayBinding binding with the relayClientAuthenticationType as None. This indicates that an endpoint using this binding will not require a client credential.

  6. Below the <bindings> element, add a <services> element. As with the bindings, you can define multiple services in a single configuration file. However, for this tutorial, you define only one.

    <services>
      <!-- Application Service -->
      <service name="Microsoft.ServiceBus.Samples.ImageService"
               behaviorConfiguration="default">
        <endpoint name="RelayEndpoint"
                  contract="Microsoft.ServiceBus.Samples.IImageContract"
                  binding="webHttpRelayBinding"
                  bindingConfiguration="default"
                  behaviorConfiguration="sbTokenProvider"
                  address="" />
      </service>
    </services>
    

    This step configures a service that uses the previously defined default webHttpRelayBinding. It also uses the default sbTokenProvider, which is defined in the next step.

  7. Below the <services> element, create a <behaviors> element, with the following content, replacing “SAS_KEY” with the Shared Access Signature (SAS) key you made a note of in Step 1: Sign up for an Account for the REST Tutorial.

    <behaviors>
      <endpointBehaviors>
        <behavior name="sbTokenProvider">
          <transportClientEndpointBehavior>
            <tokenProvider>
              <sharedAccessSignature keyName="RootManageSharedAccessKey" key="SAS_KEY" />
            </tokenProvider>
          </transportClientEndpointBehavior>
        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior name="default">
          <serviceDebug httpHelpPageEnabled="false" httpsHelpPageEnabled="false" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    

    The sharedSecretClientCredentials behavior defines the type of credentials the service uses to access the Service Bus: SharedSecret. In addition, the actual issuer names and issuer secrets are stored in the App.config file. Note that storing secrets in clear text is not considered good programming practice for production code. Be sure to implement more rigorous security in your own code.

    This code also defines the default debugging behavior, which consists of turning off the HTTP and HTTPS help pages.

  8. From the Build menu, click Build Solution to build the whole solution.

Example

The following code shows the contract and service implementation for a REST-based service that is running on the Service Bus using the WebHttpRelayBinding binding.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Web;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using Microsoft.ServiceBus;
using Microsoft.ServiceBus.Web;

namespace Microsoft.ServiceBus.Samples
{
    

    [ServiceContract(Name = "ImageContract", Namespace = "https://samples.microsoft.com/ServiceModel/Relay/")]
    public interface IImageContract
    {
        [OperationContract, WebGet]
        Stream GetImage();
    }

    public interface IImageChannel : IImageContract, IClientChannel { }

    [ServiceBehavior(Name = "ImageService", Namespace = "https://samples.microsoft.com/ServiceModel/Relay/")]
    class ImageService : IImageContract
    {
        const string imageFileName = "image.jpg";

        Image bitmap;

        public ImageService()
        {
            this.bitmap = Image.FromFile(imageFileName);
        }

        public Stream GetImage()
        {
            MemoryStream stream = new MemoryStream();
            this.bitmap.Save(stream, ImageFormat.Jpeg);

            stream.Position = 0;
            WebOperationContext.Current.OutgoingResponse.ContentType = "image/jpeg";

            return stream;
        }    
    }

    class Program
    {
        static void Main(string[] args)
        {
        }
    }
}

The following example shows the App.config file associated with the service.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <bindings>
      <!-- Application Binding -->
      <webHttpRelayBinding>
        <binding name="default">
          <!-- Turn off client authentication so that client does not need to present credential through browser or fiddler -->
          <security relayClientAuthenticationType="None" />
        </binding>
      </webHttpRelayBinding>
    </bindings>

    <services>
      <!-- Application Service -->
      <service name="Microsoft.ServiceBus.Samples.ImageService"
               behaviorConfiguration="default">
        <endpoint name="RelayEndpoint"
                  contract="Microsoft.ServiceBus.Samples.IImageContract"
                  binding="webHttpRelayBinding"
                  bindingConfiguration="default"
                  behaviorConfiguration="sbTokenProvider"
                  address="" />
      </service>
    </services>

    <behaviors>
      <endpointBehaviors>
        <behavior name="sbTokenProvider">
          <transportClientEndpointBehavior>
            <tokenProvider>
              <sharedAccessSignature keyName="RootManageSharedAccessKey" key="SAS_KEY" />
            </tokenProvider>
          <transportClientEndpointBehavior>






        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior name="default">
          <serviceDebug httpHelpPageEnabled="false" httpsHelpPageEnabled="false" />
        </behavior>
      </serviceBehaviors>
    </behaviors>

  </system.serviceModel>
</configuration>

Now that you have configured and implemented the Web service contract, proceed to Step 4: Host the REST-based WCF Service to use the Service Bus.