DEV Community

Cover image for Expose SOAP service in Azure API Management and store data in Blob
Markus Meyer
Markus Meyer

Posted on • Originally published at markusmeyer.hashnode.dev

Expose SOAP service in Azure API Management and store data in Blob

Table of Contents

1 Objective

2 Create SOAP API

3 Policy

4 Request

5 Blob

1 Objective

An external system has to send data but it's only capable to send SOAP messages. REST does not work for this system.

API Management has to expose an endpoint to receive SOAP messages.

For further processing, the entire SOAP message has to be stored in Azure Blob.

2 Create SOAP API

Create a new API in API Management by selecting WSDL.

Microsoft: Import SOAP API

APIM-NEW-WSDL.png

Provide a link to WSDL-Document or upload a WSDL-Document.
In my case, I uploaded a document:

APIM-SOAP-WSDL.png

I used the data contract for my previous post:

Transforming data from JSON to XML and XML to JSON with C#

DataContract:

[DataContract(Name = "person")]
public class Person
{
    [DataMember(Name ="firstname")] 
    public string FirstName { get; set; }

    [DataMember(Name ="lastname")]
    public string LastName { get; set; }

    [DataMember(Name ="gender"), XmlAttribute]
    public string Gender { get; set; }

    [DataMember(Name ="age")]
    public int Age { get; set; }

}

Enter fullscreen mode Exit fullscreen mode

The service itself contains a store method:

ServiceContract:

[ServiceContract]
public interface IPerson
{
    [OperationContract]
    void Store(PersonModel personModel);
}
Enter fullscreen mode Exit fullscreen mode

By running the service on my machine, I saved the WSDL to the local disc.

3 Policy

The inbound policy contains a put request to Blob.
Most of the code is about authorization.
Please find more details about it in the Microsoft documentation.

The data will be stored in the container "soap".

Named Values:

BLOB-URL: https://mmdatatransformation.blob.core.windows.net

BLOB-KEY: secret


<inbound>
    <base />
    <!-- ########## put to storage ########## -->
    <set-variable name="container" value="soap" />
    <set-variable name="fileName" value="@{return Guid.NewGuid().ToString() + ".xml";}" />
    <set-variable name="resource" value="@{
                        string prefix = "/" + context.Variables.GetValueOrDefault<string>("container") + "/";
                        string fileName = context.Variables.GetValueOrDefault<string>("fileName");
                        return prefix + fileName;
                        }" />
    <set-variable name="storageUrl" value="{{BLOB-URL}}" />
    <set-variable name="storageKey" value="{{BLOB-KEY}}" />
    <set-variable name="storageAccountName" value="@(context.Variables.GetValueOrDefault<string>("storageUrl").Split('.')[0].Split('/')[2])" />
    <set-variable name="blobUrl" value="@(context.Variables.GetValueOrDefault<string>("storageUrl") + context.Variables.GetValueOrDefault<string>("resource"))" />
    <set-variable name="date" value="@(DateTime.UtcNow.ToString("R"))" />
    <set-variable name="version" value="2018-03-28" />
    <set-backend-service base-url="@(context.Variables.GetValueOrDefault<string>("storageUrl") + "/" + context.Variables.GetValueOrDefault<string>("container"))" />
    <set-method>PUT</set-method>
    <set-header name="x-ms-date" exists-action="override">
        <value>@(context.Variables.GetValueOrDefault<string>("date") )</value>
    </set-header>
    <set-header name="x-ms-version" exists-action="override">
        <value>@(context.Variables.GetValueOrDefault<string>("version"))</value>
    </set-header>
    <set-header name="x-ms-blob-type" exists-action="override">
        <value>BlockBlob</value>
    </set-header>
    <set-header name="Content-Type" exists-action="override">
        <value>application/xml</value>
    </set-header>
    <set-header name="Authorization" exists-action="override">
        <value>@{
            string body = context.Request.Body.As<string>(preserveContent: true);
            string contentType = "application/xml";
            string contentLength = context.Request.Headers["Content-Length"][0];
            var hmacSha256 = new System.Security.Cryptography.HMACSHA256 { Key = Convert.FromBase64String(context.Variables.GetValueOrDefault<string>("storageKey")) };
            var payLoad = string.Format("{0}\n\n\n{1}\n\n{2}\n\n\n\n\n\n\nx-ms-blob-type:BlockBlob\nx-ms-date:{3}\nx-ms-version:{4}\n{5}", 
                "PUT", 
                contentLength,
                contentType,
                context.Variables.GetValueOrDefault<string>("date"),
                context.Variables.GetValueOrDefault<string>("version"),
                "/" + context.Variables.GetValueOrDefault<string>("storageAccountName") + context.Variables.GetValueOrDefault<string>("resource"));
            return "SharedKey "+ context.Variables.GetValueOrDefault<string>("storageAccountName") + ":" + Convert.ToBase64String(hmacSha256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(payLoad)));
        }</value>
    </set-header>
    <set-body>@( context.Request.Body.As<string>(true) )</set-body>
    <rewrite-uri template="@("/" + context.Variables.GetValueOrDefault<string>("fileName"))" copy-unmatched-params="true" />
</inbound>

Enter fullscreen mode Exit fullscreen mode

4 Request

My API contains one operation: Store

apim_SOAP.png

With Postman a SOAP header has to be added:

SOAPAction: http://tempuri.org/IPerson/Store

POST https://mm-sample.azure-api.net/person/

Request Body:

<?xml version="1.0" encoding="utf-8"?>
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
      <Body>
        <Store xmlns="http://tempuri.org/">
          <person>
            <age>1</age>
            <firstname>firstname1</firstname>
            <gender>gender1</gender>
            <lastname>lastname1</lastname>
          </person>
        </Store>
      </Body>
</Envelope>
Enter fullscreen mode Exit fullscreen mode

Postman:
postman-soap-request.png

5 Blob

Finally, the SOAP data is stored in the blob and ready for further processing:

soap_blob.png

Top comments (0)