Microsoft .NET WCF interoperability with a WebSphere Enterprise Service Bus mediation using MTOM encoded messages

This article shows you how to set up a Microsoft .NET web service and client that use Message Transmission Optimization Mechanism (MTOM) encoded attachments to interoperate with a WebSphere Enterprise Service Bus mediation. This is new function available in WebSphere Enterprise Service Bus V7.5.1.0.

Andrew J. Howes (andrew_howes@uk.ibm.com), Software Engineer, IBM

Photo of Andy HowesAndy Howes is a Software Engineer on the IBM Integration Bus Development Team at the IBM Software Lab in Hursley, United Kingdom. He has been in the software industry for over 20 years and has been involved in software development, systems support, project management, and function and system test. You can contact Andy at andrew_howes@uk.ibm.com.



06 June 2012

Also available in Portuguese

Introduction

MTOM/XOP enables large binary attachments to SOAP messages to be compressed and transmitted outside the SOAP encoding, thus increasing the space efficiency and decreasing the transmission time of the on-the-wire message. MTOM is increasingly being used in Microsoft® .NET® applications, and this article shows you how to integrate these applications with IBM® WebSphere® Enterprise Service Bus (hereafter called WebSphere ESB).

The article uses a simple scenario to describe the integration process. A .NET client sends a message containing a binary attachment (such as a .jpg file) via a WebSphere ESB mediation, which examines the binary object, and then the message is passed on to a .NET service. The service processes the message and then sends a response back via the WebSphere ESB mediation to the .NET client.

Prerequisites to set up the example:

  • Microsoft® Windows® Vista, Business Service Pack 2
  • Microsoft Visual Studio 2010 Professional Edition
  • Microsoft .NET Framework V4
  • Microsoft Internet Information Services (IIS) V6
  • WebSphere Enterprise Service Bus V7.5.1

Enabling Windows IIS

The .NET web service is hosted by Windows IIS, which must be enabled before use:

  1. On the Windows Vista system, select Windows Start => Control Panel.
  2. Select Programs and features.
  3. In the right pane, click Turn Windows features on or off.
  4. The Windows features dialog box opens. Select the Internet Information Services check box.
  5. Double-click (or expand) Web management tools, double-click IIS 6 management compatibility, and then select the IIS 6 Metabase and IIS 6 Configuration Compatibility check box.
  6. Double-click (or expand) World wide web services, double-click Application development features, and then select the ASP.NET check box.
  7. Click OK.

Windows Communication Foundation (WCF) service

To create the .NET web service:

  1. Select Windows Start => All Programs => Microsoft Visual Studio 2010 => Microsoft Visual Studio 2010.
  2. Select File => New web site.
  3. Ensure that .NET Framework 4 is selected and select the Visual C# template WCF service.
  4. Set the Web location to HTTP and a URL, such as http://myvistahost/mywcfservice. Click OK.

The WCF service has four main components that need to be developed or configured:

  • Service.svc
  • IService.cs
  • Service.cs
  • Web.config

Service.svc

Service.svc is the actual endpoint for the service. The service is accessed using a URL such as http://myvistahost/mywcfervice/Service.svc. The file itself is simple and mainly defines where the service code is located:

<%@ ServiceHost Language="C#" Debug="true" Service="Service"
                             CodeBehind="~/App_Code/Service.cs" %>

IService.cs

The IService.cs file of the WCF service contains an interface for the classes to be used by the service. Here is an example that defines a single method (TestOp) and the object that will be used by the class (TestObj). The important difference compared to a standard service is that the object uses a MessageContract rather than a DataContract to enable handling the binary object (field2):

using ...

[ServiceContract]
public interface IService
{
        [OperationContract]
        TestObj TestOp(TestObj testInput);
}

[MessageContract]
public class TestObj
{
    [MessageBodyMember]
        public string  field1 { get; set; }
    [MessageBodyMember]
    public Byte[] field2 { get; set; }
    [MessageBodyMember]
    public string field3 { get; set; }
}

Service.cs

Service.cs contains the main part of the service code. It uses the interface defined in the Iservice.cs file and provides the implementation for the method. This example processes the input TestObj object and populates and returns a TestObj object. The input and return objects do not need to be the same type -- it is just simpler for this example.

using ...

public class Service : IService
{
    public TestObj TestOp(TestObj testInput)
        {
        string path = @"c:\temp\output.txt";
        // Delete the file if it exists.
        if (File.Exists(path))
        {
            File.Delete(path);
        }
        FileStream file = File.Create(path);
        StreamWriter writer = new StreamWriter(file);
        writer.Write("In MTService");
        TestObj retrunObj = new TestObj();

        writer.Write("Get input data");
        string first = testInput.field1;
        Byte[] binitem = testInput.field2;
        string last = testInput.field3;

        writer.Write("Set response data");
        TestObj returnObj = new TestObj();
        returnObj.field1 = first;
        returnObj.field2 = binitem;
        returnObj.field3 = last;

        writer.Write("Return from MTService");
        writer.Close();
        file.Close();

        return returnObj;
        }
}

Web.config

In the Web.config file, between the <system.serviceModel> tags, add a binding with MTOM encoding and a large enough maximum message size for the binary file. Also, create a service endpoint using the new binding.

  <system.serviceModel>
    <bindings>
      <wsHttpBinding>
        <binding name="wsHttpMtomBinding" messageEncoding="Mtom"
                                             maxReceivedMessageSize="2621440">
          <readerQuotas maxArrayLength="2621440"/>
          <security mode="None" />
        </binding>
      </wsHttpBinding>
    </bindings>
    <services>
      <service name="Service">
        <endpoint binding="wsHttpBinding" bindingConfiguration="wsHttpMtomBinding"
                                             contract="IService" />
      </service>
    </services>
        .
        .
        .

Configuring the web service in IIS

In Visual Studio, build the Web site to check for coding errors and so on. The most common problem is missing using statements at the top of the code:

  1. Select Build => Build Web site.
  2. Set up IIS to handle the WCF service:
    1. Select Windows Start => Control Panel.
    2. Double-click Administrative Tools.
    3. Double-click Internet Information Services (IIS) Manager.
    4. If your Web service is not present under the Default web site, right-click and select Add application.
    5. Provide an alias such as mywcf and browse to the web service location, such as C:\inetpub\wwwroot\mywcfservice. Click OK.

Testing the Web site

In Visual Studio, open the Service.svc file of you web service and press Ctrl-F5 to open a browser that will connect to the web site:

Figure 1. Test the web site
Test the web site

Windows Communication Foundation (WCF) client

Using Visual Studio, build a client application to send an MTOM message to the service:

  1. Select Windows Start => All Programs => Microsoft Visual Studio 2010 => Microsoft Visual Studio 2010.
  2. Select File => New project.
  3. Ensure that it is set to .NET Framework 4.
  4. Select Visual C# under Installed Templates.
  5. Select Console application.
  6. Set the Name you would like for your client, such as myWCFClient. Click OK.

Create the Web service proxy APIs in the client:

  1. In the Solution Explorer pane on the right-hand side, right-click References and select Add service reference.
  2. In the Address field, enter the name of the web service: http://myvistahost/mywcfservice/Service.svc. Click Go.
  3. Under Services, expand Service and select Iservice. Operations should be displayed in the right-hand pane.
  4. In the Namespace, specify an appropriate namespace for the client to use, such as mywcf.org. Click OK.

The client has two main components that need to be developed or configured: Program.cs, and app.config.

Program.cs

Program.cs is where the client sets up the object to be passed to the web service and processes the object returned from it. In this case, you need to read a binary file and insert it into the object to send. You can also process the response by checking that the returned binary is the same size as the one sent. The web service is accessed via a proxy API call, the code for which is generated when the web service reference is imported.

using ...

static void Main(string[] args)
{
    EndpointAddress targetURI = new EndpointAddress(args[0]);
        // Set up the proxy
    myWCFClient.mywcf.org.ServiceClient proxy = 
        new mywcf.org.ServiceClient("WSHttpBinding_IService", targetURI);
    string url = proxy.Endpoint.Address.ToString();
    Console.WriteLine("Your url is " + url);

    try {
        // Set up attachment
        string attachment = @"c:\tmp\pic1.JPG";
        Console.WriteLine("Your file is " + attachment);
        byte[] mtomAtt = null;
        using (FileStream file = new FileStream(attachment, 
                FileMode.Open, FileAccess.Read))
        {
            using (BinaryReader reader = new BinaryReader(file))
            {
                int numBytes = (int)file.Length;  
                mtomAtt = reader.ReadBytes(numBytes);
            }
        }
        // Create the object to send
        myWCFClient.mywcf.org.TestObj inputObj = 
                new myWCFClient.mywcf.org.TestObj();
        inputObj.field1 = "Start";
        inputObj.field2 = mtomAtt;
        inputObj.field3 = "End";
        // Send the object to the service
        Console.WriteLine("Sending binary with length "+mtomAtt.Length);
        proxy.TestOp(ref inputObj.field1, ref inputObj.field2, 
                ref inputObj.field3);
        // Get the returned data
        String first = inputObj.field1;
        byte[] outbin = inputObj.field2;
        String last = inputObj.field3;
        // Check the returned data
        Console.WriteLine("field1  " + first);
        Console.WriteLine("Got output binary with length "+outbin.Length);
        Console.WriteLine("field3 " + last);
        Console.WriteLine("");
        if ( mtomAtt.Length == outbin.Length) {
            Console.WriteLine("Received binary is the same as sent binary");
        }
        else {
        Console.WriteLine("Received binary is not the same as sent binary");
        }
    }
    catch (Exception e) {
    Console.WriteLine("Exception caught in process: {0}", e.ToString());
    }
}

app.config

In the app.config file, ensure that the binding's encoding is MTOM, that its maxReceivedMessageSize is sufficient for the size of the binary file (same as service), and similarly that the readerQuotas maxArrayLength is sufficient:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <bindings>
            <wsHttpBinding>
                <binding name="WSHttpBinding_IService" closeTimeout="00:01:00"
                    openTimeout="00:01:00" receiveTimeout="00:10:00" 
                        sendTimeout="00:01:00"
                    bypassProxyOnLocal="false" transactionFlow="false" 
                        hostNameComparisonMode="StrongWildcard"
                    maxBufferPoolSize="524288" maxReceivedMessageSize="2621440"
                    messageEncoding="Mtom" textEncoding="utf-8" useDefaultWebProxy="true"
                    allowCookies="false">
                    <readerQuotas maxDepth="32" maxStringContentLength="8192" 
                        maxArrayLength="2621440"
                        maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                    <reliableSession ordered="true" inactivityTimeout="00:10:00"
                        enabled="false" />
                    <security mode="None">
                        <transport clientCredentialType="Windows" 
                            proxyCredentialType="None"
                            realm="" />
                        <message clientCredentialType="Windows" 
                            negotiateServiceCredential="true" />
                    </security>
                </binding>
            </wsHttpBinding>
        </bindings>
        <client>
          <endpoint address="http://myvistahost/mywcfervice/Service.svc" 
                       binding="wsHttpBinding"
              bindingConfiguration="WSHttpBinding_IService" 
                       contract="mtservice.org.IService"
              name="WSHttpBinding_IService" />
        </client>
    </system.serviceModel>
</configuration>

Testing the client against the web site

Build the client from the Visual Studio menu: Select Build => Build myWCFClient. Open a console window and run the client, which should generate a result like this:

"C:\users\myuser\Documents\Visual Studio 2010\Projects\myWCFClient\
myWCFClient\bin\Debug\myWCFClient.exe" http://myvistahost/mywcfervice/Service.svc
Your url is http://myvistahost/mywcfervice/Service.svc
Your file is c:\tmp\pic1.JPG
Sending binary with length 4030
field1  Start
Got output binary with length 4030
field3 End

Received binary is the same as sent binary

WebSphere ESB mediation

Generating the business object and interface

The mediation flow needs to use an interface to talk to the .NET client and service. You create the interface by obtaining the WSDL from the .NET service:

  1. Start IBM Integration Developer V7.5.1 and go to the Business Integration perspective.
  2. Select File => New => Library.
  3. Give the library a name and click Finish.
  4. Expand the library, right-click Interfaces and select Import.
  5. In the dialog, expand Business Integration, select WSDL and XSD, and then click Next.
  6. Select the Remote WSDL or XSD file radio button.
  7. Paste in the URL of the .NET service plus ?wsdl. For example: http://myvistahost/mywcfservice/Service.svc?wsdl. Click Next.
  8. Ensure that any required XSD files are checked then click Finish.

Sometimes the import from .NET does not translate fully for WebSphere requirements and some editing of the WSDL may be required. For example, the input and output names of an operation may be the same, in which case you need to change them. To do so, open the interface with the WSDL Editor and select the Source tab on the opened artifact. Here is the original imported WSDL:

  <wsdl:portType name="IService">
    <wsdl:operation name="TestOp">
      <wsdl:input message="tns:TestObj" name="TestObj"      <==
          wsaw:Action="http://tempuri.org/IService/TestOp"/>
      <wsdl:output message="tns:TestObj" name="TestObj"     <==
          wsaw:Action="http://tempuri.org/IService/TestOpResponse"/>
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="WSHttpBinding_IService" type="tns:IService">
    <wsp:PolicyReference URI="#WSHttpBinding_IService_policy"/>
    <soap12:binding transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="TestOp">
      <soap12:operation soapAction="http://tempuri.org/IService/TestOp" 
          style="document"/>
      <wsdl:input name="TestObj">                            <==
        <soap12:body use="literal"/>
      </wsdl:input>
      <wsdl:output name="TestObj">                           <==
        <soap12:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>

And here is the updated WSDL:

  <wsdl:portType name="IService">
    <wsdl:operation name="TestOp">
      <wsdl:input message="tns:TestObj" name="TestObjIn"    <==
          wsaw:Action="http://tempuri.org/IService/TestOp"/>
      <wsdl:output message="tns:TestObj" name="TestObjOut"  <==
          wsaw:Action="http://tempuri.org/IService/TestOpResponse"/>
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="WSHttpBinding_IService" type="tns:IService">
    <wsp:PolicyReference URI="#WSHttpBinding_IService_policy"/>
    <soap12:binding transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="TestOp">
      <soap12:operation soapAction="http://tempuri.org/IService/TestOp" 
          style="document"/>
      <wsdl:input name="TestObjIn">                          <==
        <soap12:body use="literal"/>
      </wsdl:input>
      <wsdl:output name="TestObjOut">                        <==
        <soap12:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>

Creating a message flow using the interface

Create a mediation module project and reference the library containing the .NET interface:

  1. Select File => New => Mediation Module.
  2. Give the module a name such as MtomFlow, set the target runtime to WebSphere ESB Server, and then click Next.
  3. Select the library that you imported the .NET WSDL into and click Finish.

Add the interface as an export to the mediation flow and generate a SOAP 1.2 binding for it:

  1. Right-click the mediation flow icon and select Add => Interface.
  2. From the dialog, select the interface name (such as IService) and click OK.
  3. Right-click the mediation flow icon again and select Generate export => Web service binding.
  4. In the Configure web service dialog, click the SOAP 1.2/HTTP button and then click Finish.
  5. Select the new export, and under the Properties tab, select the Binding tab, tick the MTOM box, and then save the flow.

Add the interface as an import to the mediation flow and generate a SOAP 1.2 binding for it:

  1. Right-click the mediation flow icon and select Add => Reference.
  2. From the dialog, select the interface name (such as IService) and click OK.
  3. Drag an import onto the canvas and connect the output from the mediation flow to the import. Click OK on the pop-up that asks about creating a matching target.
  4. Right-click the Import icon and select Generate binding => Web service binding.
  5. The Use an existing web service port radio button will be selected. Click Browse.
  6. Select the port, such as WSHttpBinding_IService, and then click OK.
  7. The SOAP 1.2/HTTP radio button should already be selected. Click Finish.
  8. On the Web service Import details dialog, click OK.
  9. Select the new import, and under the Properties tab, select the Binding tab and tick the MTOM box.
  10. Ensure that the Address points to the .NET service, such as http://myvistahost/mywcfservice/Service.svc. Save the flow.

Create a simple mediation, adding some custom code to access the binary attachment:

  1. Double-click the mediation flow icon to see the operations overview.
  2. Click on the operation name link, such as TestOp, and select the Blank mediation flow template.
  3. Drag a Callout node onto the canvas for the Request flow, select the appropriate reference such as IServicePartner, and click OK.
  4. Drag a custom mediation node onto the canvas, connect the input node to the custom mediation In terminal, and connect the Out terminal of the custom mediation to the Callout node.
  5. Add some code to the custom mediation via its Details tab to access the binary attachment. For example:
    DataObject body = (DataObject) smo.getBody();
     
    DataObject operation = (DataObject)body.get("parameters");
    
    String start = operation.getString("field1");
    byte[] image = operation.getBytes("field2");
    String end = operation.getString("field3");
    Integer length = image.length;
     
    operation.setString("field1",start+length.toString());
    operation.setString("field3",end+length.toString());
    
    body.set("parameters",operation);
    smo.setBody(body);
    out.fire(smo);
  6. Click the Java Imports tab and add import commonj.sdo.DataObject;.
  7. Click on the Response flow tab and connect the Callout response directly to the Input response. Save the flow.

Export the flow as an EAR file by selecting Export => Integration modules and libraries and then deploy the EAR file to the WebSphere ESB server. A WS-Addressing policy set needs to be applied to the mediation import so that WS-Addressing headers are sent to the .NET service:

  1. Log in to the WebSphere ESB administrative console.
  2. Navigate to Applications => Application Types => WebSphere enterprise applications.
  3. Click on the mediation module name and then click on Service client policy sets and bindings under Web services properties.
  4. Tick the box next to the service for the application. For example: IServiceExport1_IServiceHttpService.
  5. Click Attach client policy set and choose WSAddressing default.
  6. Click Save.
  7. Start the mediation module application.

Testing the scenario

To test that the flow is working correctly, send a message from the .NET client to the endpoint of the mediation flow. The flow should then pass the message on to the .NET service, receive the response, and deliver the response back to the client. Open a console window on the .NET server and run the client, which should print out a result like this:

"C:\users\myuser\Documents\Visual Studio 2010\Projects\myWCFClient\
myWCFClient\bin\Debug\myWCFClient.exe" 
        http://mywesbhost:9080/MtomFlowWeb/sca/IServiceExport1
Your url is http://mywesbhost:9080/MtomFlowWeb/sca/IServiceExport1
Your file is c:\tmp\pic1.JPG
Sending binary with length 4030
field1  Start4030
Got output binary with length 4030
field3 End4030

Received binary is the same as sent binary

Conclusion

This article showed you how to set up a .NET client and service to send and receive MTOM messages and also how to set up a WebSphere ESB flow to mediate an MTOM message between a .NET client and service.

Resources

  • WebSphere ESB resources
  • WebSphere resources
  • developerWorks resources
    • Trial downloads for IBM software products
      No-charge trial downloads for selected IBM® DB2®, Lotus®, Rational®, Tivoli®, and WebSphere® products.
    • developerWorks blogs
      Join a conversation with developerWorks users and authors, and IBM editors and developers.
    • developerWorks cloud computing resources
      Access the IBM or Amazon EC2 cloud, test an IBM cloud computing product in a sandbox, see demos of cloud computing products and services, read cloud articles, and access other cloud resources.
    • developerWorks tech briefings
      Free technical sessions by IBM experts to accelerate your learning curve and help you succeed in your most challenging software projects. Sessions range from one-hour virtual briefings to half-day and full-day live sessions in cities worldwide.
    • developerWorks podcasts
      Listen to interesting and offbeat interviews and discussions with software innovators.
    • developerWorks on Twitter
      Check out recent Twitter messages and URLs.
    • IBM Education Assistant
      A collection of multimedia educational modules that will help you better understand IBM software products and use them more effectively to meet your business requirements.

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into WebSphere on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=WebSphere
ArticleID=820156
ArticleTitle=Microsoft .NET WCF interoperability with a WebSphere Enterprise Service Bus mediation using MTOM encoded messages
publish-date=06062012