I am trying to consume Royal Mail shipping API in my C# Console Application but I am stuck. When I make a call to the API, it says Invalid Request..
This is what I did so far
RoyalMailMessage.cs
class RoyalMailMessage : Message
{
private readonly Message message;
public RoyalMailMessage(Message message)
{
this.message = message;
}
public override MessageHeaders Headers
{
get
{
return this.message.Headers;
}
}
public override MessageProperties Properties
{
get
{
return this.message.Properties;
}
}
public override MessageVersion Version
{
get
{
return this.message.Version;
}
}
protected override void OnWriteStartBody(XmlDictionaryWriter writer)
{
writer.WriteStartElement("Body", "http://schemas.xmlsoap.org/soap/envelope/");
}
protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
{
this.message.WriteBodyContents(writer);
}
protected override void OnWriteStartEnvelope(XmlDictionaryWriter writer)
{
writer.WriteStartElement("s", "Envelope", "http://schemas.xmlsoap.org/soap/envelope/");
writer.WriteAttributeString("xmlns", "v2", null, "http://www.royalmailgroup.com/api/ship/V2");
writer.WriteAttributeString("xmlns", "v1", null, "http://www.royalmailgroup.com/integration/core/V1");
writer.WriteAttributeString("xmlns", "xsi", null, "http://www.w3.org/2001/XMLSchema-instance");
writer.WriteAttributeString("xmlns", "xsd", null, "http://www.w3.org/2001/XMLSchema");
writer.WriteAttributeString("xmlns", "xsd", null, "http://www.w3.org/2001/XMLSchema");
}
}
RoyalMailMessageFormatter.cs
public class RoyalMailMessageFormatter : IClientMessageFormatter
{
private readonly IClientMessageFormatter formatter;
public RoyalMailMessageFormatter(IClientMessageFormatter formatter)
{
this.formatter = formatter;
}
public object DeserializeReply(Message message, object[] parameters)
{
return this.formatter.DeserializeReply(message, parameters);
}
public Message SerializeRequest(MessageVersion messageVersion, object[] parameters)
{
var message = this.formatter.SerializeRequest(messageVersion, parameters);
return new RoyalMailMessage(message);
}
}
RoyalMailIEndpointBehavior.cs
class RoyalMailIEndpointBehavior : IOperationBehavior
{
public RoyalMailIEndpointBehavior() { }
public void ApplyClientBehavior(OperationDescription description, ClientOperation proxy)
{
IClientMessageFormatter currentFormatter = proxy.Formatter;
proxy.Formatter = new RoyalMailMessageFormatter(currentFormatter);
}
public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
}
public void Validate(OperationDescription operationDescription)
{
}
}
Program.cs
class Program
{
static void Main(string[] args)
{
try
{
using (var shippingService = new shippingAPIPortTypeClient())
{
shippingService.ClientCredentials.UserName.UserName = "xxxx";
shippingService.ClientCredentials.UserName.Password = "xxxxx";
foreach (OperationDescription od in shippingService.Endpoint.Contract.Operations)
{
od.Behaviors.Add(new RoyalMailIEndpointBehavior());
}
var createShipment = new createShipmentRequest()
{
integrationHeader = new integrationHeader()
{
dateTime = DateTime.Now,
dateTimeSpecified = true,
debugFlag = false,
debugFlagSpecified = false,
identification = new identificationStructure()
{
applicationId = "xxxx",
endUserId = "Sandra",
intermediaryId = "null",
transactionId = "123456789"
},
performanceFlag = false,
performanceFlagSpecified = false,
testFlag = false,
testFlagSpecified = false,
version = 1,
versionSpecified = false
},
requestedShipment = new requestedShipment()
{
bfpoFormat = new bFPOFormatType()
{
bFPOFormatCode = null,
},
customerReference = "",
departmentReference = "",
}
};
shippingService.createShipment(null, createShipment);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
App.Config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="shippingAPISoapBinding">
<security mode="Transport">
<transport clientCredentialType="Certificate"></transport>
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://api.royalmail.com/shipping/onboarding" binding="basicHttpBinding"
bindingConfiguration="shippingAPISoapBinding" contract="ShippingService.shippingAPIPortType"
name="shippingAPIPort" behaviorConfiguration="CustomBehavior" />
</client>
<behaviors>
<endpointBehaviors>
<behavior name="CustomBehavior">
<clientCredentials>
<clientCertificate findValue="RM10001815" x509FindType="FindBySubjectName"
storeLocation="CurrentUser" storeName="My" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
Now, when I make a call to the API, it says "Invalid Request"..I am not sure if I missing anything, may be adding credentials in Soap Envelop header like below?
<soapenv:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:Username>xxxx</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">xxxx</wsse:Password>
<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">xWstjXG0iUxbv3NH/fX+kw==</wsse:Nonce>
<wsu:Created>2014-08-16T15:29:42</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>