I am trying to use the Royal Mail delivery API in my C # console application, but I am stuck. When I access the API, it says "Invalid request".
This is what I have done 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 call the API, it says "Invalid request". I'm not sure if something is missing, maybe adding credentials to the Soap Envelop header, as shown 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>