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
Provide a link to WSDL-Document or upload a WSDL-Document. In my case, I uploaded a document:
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; }
}
The service itself contains a store method:
ServiceContract:
[ServiceContract]
public interface IPerson
{
[OperationContract]
void Store(PersonModel personModel);
}
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: 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>
4 Request
My API contains one operation: Store
With Postman a SOAP header has to be added:
SOAPAction: tempuri.org/IPerson/Store
POST 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>
Postman:
5 Blob
Finally, the SOAP data is stored in the blob and ready for further processing: