使用WCF皇家邮政API在C#控制台应用程序 [英] Consume WCF Royal Mail API in c# Console Application

查看:1262
本文介绍了使用WCF皇家邮政API在C#控制台应用程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图消耗皇家邮政航运API在我的C#控制台应用程序,但我坚持。当我做对API的调用,它说无效的请求。



这是我做的,到目前为止



RoyalMailMessage.cs

 类RoyalMailMessage:消息
{
私人只读邮件消息;

公共RoyalMailMessage(消息消息)
{
this.message =消息;
}
公众覆盖MessageHeaders头
{
得到
{
返回this.message.Headers;
}
}
公众覆盖MessageProperties属性
{
得到
{
返回this.message.Properties;
}
}
公众覆盖MessageVersion版本
{
得到
{
返回this.message.Version;
}
}
保护覆盖无效OnWriteStartBody(的XmlDictionaryWriter作家)
{
writer.WriteStartElement(身体,http://schemas.xmlsoap.org/ SOAP /信封/);
}
保护覆盖无效OnWriteBodyContents(的XmlDictionaryWriter作家)
{
this.message.WriteBodyContents(作家);
}
保护覆盖无效OnWriteStartEnvelope(的XmlDictionaryWriter作家)
{
writer.WriteStartElement(S,信封,http://schemas.xmlsoap.org/soap /信封/);
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

 公共类RoyalMailMessageFormatter:IClientMessageFormatter 
{
私人只读IClientMessageFormatter格式;

公共RoyalMailMessageFormatter(IClientMessageFormatter格式)
{
this.formatter =格式;
}

公共对象DeserializeReply(消息消息,对象[]参数)
{
返回this.formatter.DeserializeReply(消息,参数);
}

公共信息SerializeRequest(MessageVersion messageVersion,对象[]参数)
{
VAR消息= this.formatter.SerializeRequest(messageVersion,参数);
返回新RoyalMailMessage(消息);
}
}



RoyalMailIEndpointBehavior.cs

 类RoyalMailIEndpointBehavior:IOperationBehavior 
{

公共RoyalMailIEndpointBehavior(){}

公共无效ApplyClientBehavior(OperationDescription描述,ClientOperation代理)
{
IClientMessageFormatter currentFormatter = proxy.Formatter;
proxy.Formatter =新RoyalMailMessageFormatter(currentFormatter);
}

公共无效AddBindingParameters(OperationDescription operationDescription,BindingParameterCollection bindingParameters)
{

}

公共无效ApplyDispatchBehavior(OperationDescription operationDescription,DispatchOperation dispatchOperation)
{

}

公共无效验证(operationDescription operationDescription)
{

}

}

的Program.cs

 类节目
{
静态无效的主要(字串[] args)
{


{

使用(VAR shippingService =新shippingAPIPortTypeClient())
{
shippingService.ClientCredentials.UserName.UserName =XXXX;
shippingService.ClientCredentials.UserName.Password =XXXXX;

的foreach(在shippingService.Endpoint.Contract.Operations OperationDescription OD)
{
od.Behaviors.Add(新RoyalMailIEndpointBehavior());
}


变种createShipment =新createShipmentRequest()
{
integrationHeader =新integrationHeader()
{
日期时间= DateTime.Now,
dateTimeSpecified = TRUE,
debugFlag =假,
debugFlagSpecified =假,
=识别新identificationStructure()
{
的applicationID = XXXX,
endUserId =桑德拉,
intermediaryId =空,
transactionId,有无=123456789
},
performanceFlag =假,
performanceFlagSpecified =假,
testFlag =假,
testFlagSpecified =假,
版本= 1,
versionSpecified = FALSE


},
requestedShipment =新requestedShipment()
{
bfpoFormat =新bFPOFormatType()
{
bFPOFormatCode = NULL,
},
customerReference =
departmentReference =,

}
};

shippingService.createShipment(NULL,createShipment);
}

}
赶上(异常前)
{
Console.WriteLine(ex.Message);
}
}
}



App.Config中

 <?XML版本=1.0编码=UTF-8>?; 
<结构>
<&启动GT;
< supportedRuntime版本=V4.0SKU =.net框架,版本= V4.5/>
< /启动>
< system.serviceModel>
<&绑定GT;
<&basicHttpBinding的GT;
<绑定名称=shippingAPISoapBinding>
<安全模式=运输>
<运输clientCredentialType =证书>< /运输及GT;
< /安全>
< /&结合GT;

< / basicHttpBinding的>
< /绑定>
<客户端>
<端点地址=htt​​ps://api.royalmail.com/shipping/onboarding绑定=basicHttpBinding的
bindingConfiguration =shippingAPISoapBinding合同=ShippingService.shippingAPIPortType
名称=shippingAPIPortbehaviorConfiguration =CustomBehavior/>
< /客户>
<&行为GT;
< endpointBehaviors>
<行为NAME =CustomBehavior>
< clientCredentials>
< clientCertificate findValue =RM10001815x509FindType =FindBySubjectName
storeLocation =的currentUserSTORENAME =我/>
< / clientCredentials>
< /行为>
< / endpointBehaviors>
< /行为>

< /system.serviceModel>
< /结构>

现在,当我做出了API的调用,它说:无效的请求..我不知道如果我错过什么,可能是添加在香皂外型头凭据像下面

 < soapenv:页眉和GT; 
< WSSE:安全的xmlns:WSSE =htt​​p://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:用户名>&XXXX LT; / WSSE:用户名>
< WSSE:密码TYPE =htt​​p://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest> XXXX< / WSSE:密码>
< WSSE:杜撰EncodingType =htt​​p://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary> xWstjXG0iUxbv3NH / FX +千瓦==< / WSSE:随机数>
< WSU:创建> 2014-08-16T15:29:42℃; / WSU:创建>
< / WSSE:用户名令牌>
< / WSSE:安全和GT;
< / soapenv:页眉和GT;


解决方案

首先你缺少安全头,你已经确定了,再加上你的createShipment要求的其他领域,如地址一大堆,服务代码等,我会强烈建议使用招捕捉你的SOAP请求和响应,他们会给你一个更深入地了解发生了什么。您还可以比较你是由英国皇家邮政上岗提供的示例请求产生的请求。



看你的代码,你不重视安全令牌(在WSSE),它必须是唯一为每个请求您(的随机数令牌即是)。您还缺少多种其他所需领域的createShipemt要求,如地址,服务代码和类型等。



我必须附上证书和密钥的请求使其正常工作。下面是我创建,使这项工作代码的一些片断,它不是一个复制粘贴解决方案,但比什么都重要,你会发现那里的问候英国皇家邮政和C#和应该指向你在正确的方向更好。



请注意,我有它加载了大量的从SQLite数据库的设置配置类(未公布)。对于createShipment请求的值是从一种形式(未公布),这是预填充的数据,但允许在我们的仓库用户改变并相应地调整过来。你已经从岗位(的 C#WCF命名空间移动到页眉和放大器;使用NS前缀)来处理空间问题。英国皇家邮政API是不容易在C#中实现的,我花了近2天来获得一个有效的请求和响应,正如我所说,你真的需要捕捉请求和响应工作了是怎么回事。

 私人X509Certificate2证书; 
私人配置的配置;

公共皇家邮政(){

//加载配置
配置=新配置();
config.loadConfig();

//载入SSL证书(检查文件是否存在)
字符串certificatePath =(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly()位置)+ @\ + config.GetCertificateName());

如果(!System.IO.File.Exists(certificatePath))
{
抛出新的异常(@皇家邮政证书丢失从Plugins目录。请将文件+ config.GetCertificateName()+在同一目录作为插件DLL档案与重新开张FileMaker.\\\
\\\
+ certificatePath);
}

证书=新X509Certificate2(certificatePath,config.GetCertificatePassword());

//检查它在证书
的X509Store店=新的X509Store(StoreName.My,StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadWrite); (!store.Certificates.Contains(证书))
如果
{
store.Add(证书);
MessageBox.Show(证书安装到计算机信任存储区);
}
store.Close();

}


/ *
*
* SOAP服务与;方法:
*
* /

私人shippingAPIPortTypeClient GetProxy()
{

basicHttpBinding的myBinding =新basicHttpBinding的(BasicHttpSecurityMode.Transport);
myBinding.MaxReceivedMessageSize = 2147483647;
myBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;

shippingClient =新shippingAPIPortTypeClient(myBinding,新的EndpointAddress(新的URI(config.GetEndpointURL()),EndpointIdentity.CreateDnsIdentity(api.royalmail.com),新AddressHeaderCollection()));
shippingClient.ClientCredentials.ClientCertificate.Certificate =证书;

的foreach(在shippingClient.Endpoint.Contract.Operations OperationDescription OD)
{
od.Behaviors.Add(新RoyalMailIEndpointBehavior());
}
返回shippingClient;
}


私人SecurityHeaderType GetSecurityHeaderType()
{
SecurityHeaderType securityHeader =新SecurityHeaderType();

DateTime的创建= DateTime.Now;

串creationDate;
creationDate = DateTime.UtcNow.ToString(YYYY-MM-DDTHH:MM:SSZ);

串随机数= =随机数(新的随机()和Next(0,int.MaxValue)。)的ToString()。

字节[] hashedPassword;
hashedPassword = GetSHA1(config.GetPassword());

串concatednatedDigestInput = string.Concat(随机数,creationDate,Encoding.Default.GetString(hashedPassword));
字节[]消化;
摘要= GetSHA1(concatednatedDigestInput);

串passwordDigest;
passwordDigest = Convert.ToBase64String(摘要);

串encodedNonce;
encodedNonce = Convert.ToBase64String(Encoding.Default.GetBytes(随机数));

XmlDocument的DOC =新的XmlDocument();使用
(XmlWriter的作家= doc.CreateNavigator()的appendChild()。)
{
writer.WriteStartDocument();
writer.WriteStartElement(安全);
writer.WriteStartElement(UsernameToken的,http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd);
writer.WriteElementString(用户名,config.GetUsername());
writer.WriteElementString(密码,passwordDigest);
writer.WriteElementString(现时,encodedNonce);
writer.WriteElementString(创建,creationDate);
writer.WriteEndElement();
writer.WriteEndElement();
writer.WriteEndDocument();
writer.Flush();
}

doc.DocumentElement.RemoveAllAttributes();

System.Xml.XmlElement [] =标题&doc.DocumentElement.ChildNodes.Cast LT; XmlElement的>()ToArray的<&XmlElement的GT;();

securityHeader.Any =头;

返回securityHeader;

}

私人integrationHeader GetIntegrationHeader()
{
integrationHeader头​​=新integrationHeader();

DateTime的创建= DateTime.Now;
字符串createdAt = DateTime.UtcNow.ToString(YYYY-MM-DDTHH:MM:SSZ);

header.dateTime =创造的;
header.version = Int32.Parse(config.GetVersion());
header.dateTimeSpecified = TRUE;
header.versionSpecified = TRUE;

identificationStructure idStructure =新identificationStructure();
idStructure.applicationId = config.GetApplicationID();

串随机数= =随机数(新的随机()和Next(0,int.MaxValue)。)的ToString()。

idStructure.transactionId = CalculateMD5Hash(随机数+ createdAt);

header.identification = idStructure;

返回头;
}

私人静态的byte [] GetSHA1(字符串输入)
{
返回SHA1Managed.Create()。ComputeHash(Encoding.Default.GetBytes(输入)) ;
}

公共字符串CalculateMD5Hash(字符串输入)
{
//第1步,计算从输入
MD5 MD5 = System.Security MD5哈希值。 Cryptography.MD5.Create();
字节[] = inputBytes System.Text.Encoding.ASCII.GetBytes(输入);
字节[] =哈希md5.ComputeHash(inputBytes);

//第2步,字节数组转换为十六进制字符串
StringBuilder的SB =新的StringBuilder();
的for(int i = 0; I< hash.Length;我++)
{
sb.Append(哈希[我]的ToString(X2));
}
返回sb.ToString();
}



/ *
*检查响应页脚中的错误和放大器;警告从服务
*如果错误返回true,这样我们可以通知的FileMaker错误
*忽略警告,现在
*
* /
私人布尔checkErrorsAndWarnings(integrationFooter integrationFooter)
{
如果(integrationFooter!= NULL)
{
如果(integrationFooter.errors = NULL&放大器;!&安培; integrationFooter.errors.Length大于0)
{
errorDetail [] =错误integrationFooter.errors;
的for(int i = 0; I< errors.Length;我++)
{
errorDetail错误=错误[I]
MessageBox.Show(皇家邮政请求错误:。+ error.errorDescription + + error.errorResolution,皇家邮政请求错误,MessageBoxButtons.OK,MessageBoxIcon.Error,MessageBoxDefaultButton.Button1);
}
如果(errors.Length大于0)
{
返回真;
}
}

如果(integrationFooter.warnings = NULL&放大器;!&安培; integrationFooter.warnings.Length大于0)
{
warningDetail [ ]警告= integrationFooter.warnings;
的for(int i = 0; I< warnings.Length;我++)
{
warningDetail警告=警告[I]
//MessageBox.Show(\"Royal邮件请求警告:+ warning.warningDescription ++ warning.warningResolution,皇家邮政请求警告,MessageBoxButtons.OK,MessageBoxIcon.Warning,MessageBoxDefaultButton.Button1);
}
}
}

返回FALSE;

}

/ *
*显示消息框,SOAP错误如果我们收到故障代码返回从服务
*
* /
私人无效showSoapException(FaultException异常E)
{
MessageFault消息= e.CreateMessageFault();

的XmlElement errorDetail = message.GetDetail<&XmlElement的GT;();

XmlNodeList中errorDetails = errorDetail.ChildNodes;

字符串fullErrorDetails =;

的for(int i = 0; I< errorDetails.Count;我++)
{
fullErrorDetails + = errorDetails.Item(I).Name点+:+ errorDetails .Item㈠.InnerText +\\\
;
}

MessageBox.Show(有错误发生皇家邮件服务:+ message.Reason.ToString()+\\\
\\\
+ fullErrorDetails,皇家邮政SOAP错误,MessageBoxButtons.OK,MessageBoxIcon.Error,MessageBoxDefaultButton.Button1);
}

公共createShipmentResponse SendCreateShipmentRequest(CreateShipmentForm使用ShippingForm)
{

shippingAPIPortTypeClient客户端= GetProxy();


{

createShipmentRequest要求=新createShipmentRequest();
request.integrationHeader = GetIntegrationHeader();

requestedShipment出货=新requestedShipment();

//装运类型代码(交货或Return)
referenceDataType shipmentType =新referenceDataType();
shipmentType.code = shippingForm.GetShippingType();
shipment.shipmentType = shipmentType;

//服务Occurence(在客户标识协议账户),默认为1。不要求如果有只有1在帐户
shipment.serviceOccurrence = config.GetServiceOccurance();

//服务类型码(1:24H第一类,2:48H二等,D:特别交货保证,H:HM部队(BFPO),I:国际,R:履带式返回,T :履带国内)
referenceDataType的serviceType =新referenceDataType();
serviceType.code = shippingForm.GetServiceType()GetServiceTypeCode();
shipment.serviceType =的serviceType;

//服务产品(见英国皇家邮政业提供服务类型代码举不胜举。)
serviceOfferingType serviceOfferingTypeContainer =新serviceOfferingType();
referenceDataType serviceOffering =新referenceDataType();
serviceOffering.code = shippingForm.GetServiceOffering()引用代码();
serviceOfferingTypeContainer.serviceOfferingCode = serviceOffering;
shipment.serviceOffering = serviceOfferingTypeContainer;

//服务格式代码
serviceFormatType serviceFormatTypeContainer =新serviceFormatType();
referenceDataType serviceFormat =新referenceDataType();
serviceFormat.code = shippingForm.GetServiceFormat()的getFormat();
serviceFormatTypeContainer.serviceFormatCode = serviceFormat;
shipment.serviceFormat = serviceFormatTypeContainer;

//出货日期
shipment.shippingDate = shippingForm.GetShippingDate();
shipment.shippingDateSpecified = TRUE;

//签名要求(仅适用于跟踪服务)
如果(shippingForm.IsSignatureRequired())
{
shipment.signature = TRUE;
}
,否则
{
shipment.signature = FALSE;

//留在安全的地方(可在履带非签名服务内容)
shipment.safePlace = shippingForm.GetSafePlaceText();
}
shipment.signatureSpecified = TRUE;

//发件人参考编号(例如发票号或RA号)
shipment.senderReference = shippingForm.GetInvoiceNumber();

/ *
*服务增强
* /

名单,LT; serviceEnhancementType> serviceEnhancements =新的List< serviceEnhancementType>();

名单,LT; dataObjects.ServiceEnhancement> selectedEnhancements = shippingForm.GetServiceEnhancements();

的for(int i = 0; I< selectedEnhancements.Count;我++)
{
serviceEnhancementType增强=新serviceEnhancementType();
referenceDataType enhancementCode =新referenceDataType();
enhancementCode.code = selectedEnhancements.ElementAt(ⅰ).GetEnhancementType()的ToString();
enhancement.serviceEnhancementCode = enhancementCode;
serviceEnhancements.Add(增强);
}

shipment.serviceEnhancements = serviceEnhancements.ToArray();


/ *
*收件人联系方式
* /

触点recipientContact =新的联系人();
recipientContact.complementaryName = shippingForm.GetCompany();
recipientContact.name = shippingForm.GetName();

如果{
digitalAddress电子邮件=新digitalAddress()(shippingForm.GetEmailAddress()等于()!);
email.electronicAddress = shippingForm.GetEmailAddress();
recipientContact.electronicAddress =电子邮件;
}

如果{
telephoneNumber电话=新telephoneNumber()(shippingForm.GetMobileNumber()等于()!);

正则表达式phoneRegex ​​=新的正则表达式(@[^ \d]);
tel.telephoneNumber1 = phoneRegex.Replace(shippingForm.GetMobileNumber(),);
tel.countryCode =00+ shippingForm.GetCountry()GetDialingCode();
recipientContact.telephoneNumber =电话;
}

shipment.recipientContact = recipientContact;

/ *
*收件人地址
*
* /
地址recipientAddress =新地址();
recipientAddress.addressLine1 = shippingForm.GetAddressLine1();
recipientAddress.addressLine2 = shippingForm.GetAddressLine2();
recipientAddress.addressLine3 = shippingForm.GetAddressLine3();
recipientAddress.addressLine4 = shippingForm.GetCounty();
recipientAddress.postTown = shippingForm.GetTown();
countryType国家=新countryType();
referenceDataType COUNTRYCODE =新referenceDataType();
countryCode.code = shippingForm.GetCountry()getCountryCode();
country.countryCode = COUNTRYCODE;
recipientAddress.country =国家;
recipientAddress.postcode = shippingForm.GetPostCode();

recipientAddress.stateOrProvince =新stateOrProvinceType();
recipientAddress.stateOrProvince.stateOrProvinceCode =新referenceDataType();

shipment.recipientAddress = recipientAddress;

//装运物品

名单,LT; RoyalMailAPI.RoyalMailShippingAPI.item>项目=新的List< RoyalMailAPI.RoyalMailShippingAPI.item> ();

的foreach(dataObjects.Item i的shippingForm.GetItems()){
RoyalMailAPI.RoyalMailShippingAPI.item项=新RoyalMailAPI.RoyalMailShippingAPI.item();
item.numberOfItems = i.GetQty()的ToString()。
item.weight =新的维度();
item.weight.value =(浮点)(i.GetWeight()* 1000);
item.weight.unitOfMeasure =新unitOfMeasureType();
item.weight.unitOfMeasure.unitOfMeasureCode =新referenceDataType();
item.weight.unitOfMeasure.unitOfMeasureCode.code =G;

items.Add(项目);
}

如果(shippingForm.GetServiceType()。GetDescription()。ToLower将()。包含(国际))
{
internationalInfo InternationalInfo =新internationalInfo ();
InternationalInfo.shipperExporterVatNo =GB945777273;
InternationalInfo.documentsOnly = FALSE;
InternationalInfo.shipmentDescription =发票号码:+ shippingForm.GetInvoiceNumber();
InternationalInfo.invoiceDate = DateTime.Now;
InternationalInfo.termsOfDelivery =EXW;
InternationalInfo.invoiceDateSpecified = TRUE;
InternationalInfo.purchaseOrderRef = shippingForm.GetInvoiceNumber();

名单,LT; RoyalMailShippingAPI.parcel>包裹=新的List<地块和GT;();
的foreach(dataObjects.Item我shippingForm.GetItems())
{
地块宗地=新的包裹();
Parcel.weight =新的维度();
Parcel.weight.value =(浮点)(i.GetWeight()* 1000);
Parcel.weight.unitOfMeasure =新unitOfMeasureType();
Parcel.weight.unitOfMeasure.unitOfMeasureCode =新referenceDataType();
Parcel.weight.unitOfMeasure.unitOfMeasureCode.code =G;

Parcel.invoiceNumber = shippingForm.GetInvoiceNumber();
Parcel.purposeOfShipment =新referenceDataType();
Parcel.purposeOfShipment.code =31;

名单,LT; contentDetail>内容=新的List< contentDetail>();
的foreach(RoyalMailAPI.dataObjects.ProductDetail产品在i.GetProducts())
{
contentDetail ContentDetail =新contentDetail();
ContentDetail.articleReference = product.Sku;
ContentDetail.countryOfManufacture =新countryType();
ContentDetail.countryOfManufacture.countryCode =新referenceDataType();
ContentDetail.countryOfManufacture.countryCode.code = product.CountryOfManufacture;

ContentDetail.currencyCode =新referenceDataType();
ContentDetail.currencyCode.code = product.CurrencyCode;
ContentDetail.description = product.Name;
ContentDetail.unitQuantity = product.Qty.ToString();
ContentDetail.unitValue = Convert.ToDecimal(product.Price);
ContentDetail.unitWeight =新的维度();
ContentDetail.unitWeight.value = Convert.ToSingle(product.Weight * 1000);
ContentDetail.unitWeight.unitOfMeasure =新unitOfMeasureType();
ContentDetail.unitWeight.unitOfMeasure.unitOfMeasureCode =新referenceDataType();
ContentDetail.unitWeight.unitOfMeasure.unitOfMeasureCode.code =G;


Contents.Add(ContentDetail);
}

//Parcel.contentDetails = Contents.ToArray();

parcels.Add(包裹);

}

InternationalInfo.parcels = parcels.ToArray();

shipment.internationalInfo = InternationalInfo;
}
,否则
{
shipment.items = items.ToArray();
}

request.requestedShipment =发货;

createShipmentResponse响应= client.createShipment(GetSecurityHeaderType(),请求);

// Show Errors And Warnings
checkErrorsAndWarnings(response.integrationFooter);

return response;

}
catch (TimeoutException e)
{
client.Abort();
MessageBox.Show(\"Request Timed Out: \" + e.Message, \"Request Timeout\", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
}
catch (FaultException e)
{
client.Abort();
showSoapException(e);
}
catch (CommunicationException e)
{
client.Abort();
MessageBox.Show(\"A communication error has occured: \" + e.Message + \" - \" + e.StackTrace, \"Communication Error\", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
}
catch (Exception e)
{
client.Abort();
MessageBox.Show(e.Message, \"Royal Mail Error\", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
}

return null;
}


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>

解决方案

Firstly you are missing the security header as you have already identified, plus a whole host of other fields in your createShipment request such as address, service code etc. I would strongly suggest using fiddler to capture your SOAP requests and responses, they will give you a lot more insight into what is happening. You can also compare the requests you are generating with the example requests provided by royal mail onboarding.

Looking at your code, you are not attaching the security tokens (the wsse) which needs to be unique for every request you make (The nonce token that is). You are also missing a variety of other required fields for the createShipemt request such as address, service code and type etc.

I had to attach the certificate and key to the request to make it work as well. Below are some fragments of the code I created to make this work, it's not a copy paste solution but better than anything else you will find out there with regards to Royal Mail and C# and should point you in the right direction.

Please note, I have config class which loads a lot of the settings from an sqlite database (not posted). The values for the createShipment request are coming from a form (not posted) which is pre-populated with the data but allows the user in our warehouse to alter and adjust accordingly. You have already made use of my custom message formatter example from post (C# WCF Namespaces Move To Header & Use NS Prefix) to handle the namespace issue. Royal Mail API is not easy to implement in C#, took me nearly 2 days to get a valid request and response and as I say, you really need to capture the requests and responses to work out what is going on.

private X509Certificate2 certificate;
private Config config;

    public RoyalMail() {

        // Load The Config
        config = new Config();
        config.loadConfig();

        // Load The SSL Certificate (Check The File Exists)
        String certificatePath = (Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + @"\" + config.GetCertificateName());

        if (!System.IO.File.Exists(certificatePath))
        {
            throw new Exception(@"The Royal Mail Certificate Is Missing From The Plugins Directory. Please Place The File " + config.GetCertificateName() + " In The Same Directory As The Plugin DLL File & Relaunch FileMaker.\n\n" + certificatePath);
        }

        certificate = new X509Certificate2(certificatePath, config.GetCertificatePassword());

        // Check It's In The Certificate 
        X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
        store.Open(OpenFlags.ReadWrite);
        if (!store.Certificates.Contains(certificate))
        {
            store.Add(certificate);
            MessageBox.Show("Certificate Was Installed Into Computer Trust Store");
        }
        store.Close(); 

    }


    /*
     * 
     * SOAP Service & Methods
     * 
     */

    private shippingAPIPortTypeClient GetProxy()
    {

        BasicHttpBinding myBinding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
        myBinding.MaxReceivedMessageSize = 2147483647;
        myBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;

        shippingClient = new shippingAPIPortTypeClient(myBinding, new EndpointAddress(new Uri(config.GetEndpointURL()), EndpointIdentity.CreateDnsIdentity("api.royalmail.com"), new AddressHeaderCollection()));
        shippingClient.ClientCredentials.ClientCertificate.Certificate = certificate;

        foreach (OperationDescription od in shippingClient.Endpoint.Contract.Operations)
        {
            od.Behaviors.Add(new RoyalMailIEndpointBehavior());
        }
        return shippingClient;
    }


    private SecurityHeaderType GetSecurityHeaderType()
    {
        SecurityHeaderType securityHeader = new SecurityHeaderType();

        DateTime created = DateTime.Now;

        string creationDate;
        creationDate = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ");

        string nonce = nonce = (new Random().Next(0, int.MaxValue)).ToString();

        byte[] hashedPassword;
        hashedPassword = GetSHA1(config.GetPassword());

        string concatednatedDigestInput = string.Concat(nonce, creationDate, Encoding.Default.GetString(hashedPassword));
        byte[] digest;
        digest = GetSHA1(concatednatedDigestInput);

        string passwordDigest;
        passwordDigest = Convert.ToBase64String(digest);

        string encodedNonce;
        encodedNonce = Convert.ToBase64String(Encoding.Default.GetBytes(nonce));

        XmlDocument doc = new XmlDocument();
        using (XmlWriter writer = doc.CreateNavigator().AppendChild())
        {
            writer.WriteStartDocument();
            writer.WriteStartElement("Security");
            writer.WriteStartElement("UsernameToken", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
            writer.WriteElementString("Username", config.GetUsername());
            writer.WriteElementString("Password", passwordDigest);
            writer.WriteElementString("Nonce", encodedNonce);
            writer.WriteElementString("Created", creationDate);
            writer.WriteEndElement();
            writer.WriteEndElement();
            writer.WriteEndDocument();
            writer.Flush();
        }

        doc.DocumentElement.RemoveAllAttributes();

        System.Xml.XmlElement[] headers = doc.DocumentElement.ChildNodes.Cast<XmlElement>().ToArray<XmlElement>();

        securityHeader.Any = headers;

        return securityHeader;

    }

    private integrationHeader GetIntegrationHeader()
    {
        integrationHeader header = new integrationHeader();

        DateTime created = DateTime.Now;
        String createdAt = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ");

        header.dateTime = created;
        header.version = Int32.Parse(config.GetVersion());
        header.dateTimeSpecified = true;
        header.versionSpecified = true;

        identificationStructure idStructure = new identificationStructure();
        idStructure.applicationId = config.GetApplicationID();

        string nonce = nonce = (new Random().Next(0, int.MaxValue)).ToString();

        idStructure.transactionId = CalculateMD5Hash(nonce + createdAt);

        header.identification = idStructure;

        return header;
    }

    private static byte[] GetSHA1(string input)
    {
        return SHA1Managed.Create().ComputeHash(Encoding.Default.GetBytes(input));
    }

    public string CalculateMD5Hash(string input)
    {
        // step 1, calculate MD5 hash from input
        MD5 md5 = System.Security.Cryptography.MD5.Create();
        byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
        byte[] hash = md5.ComputeHash(inputBytes);

        // step 2, convert byte array to hex string
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < hash.Length; i++)
        {
            sb.Append(hash[i].ToString("X2"));
        }
        return sb.ToString();
    }



    /*
     * Check Response Footer For Errors & Warnings From Service
     * If Error Return True So We Can Inform Filemaker Of Error
     * Ignore Warnings For Now
     * 
     */
    private bool checkErrorsAndWarnings(integrationFooter integrationFooter)
    {
        if (integrationFooter != null)
        {
            if (integrationFooter.errors != null && integrationFooter.errors.Length > 0)
            {
                errorDetail[] errors = integrationFooter.errors;
                for (int i = 0; i < errors.Length; i++)
                {
                    errorDetail error = errors[i];
                    MessageBox.Show("Royal Mail Request Error: " + error.errorDescription + ". " + error.errorResolution, "Royal Mail Request Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
                }
                if (errors.Length > 0)
                {
                    return true;
                }
            }

            if (integrationFooter.warnings != null && integrationFooter.warnings.Length > 0)
            {
                warningDetail[] warnings = integrationFooter.warnings;
                for (int i = 0; i < warnings.Length; i++)
                {
                    warningDetail warning = warnings[i];
                    //MessageBox.Show("Royal Mail Request Warning: " + warning.warningDescription + ". " + warning.warningResolution, "Royal Mail Request Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1);
                }
            }
        }

        return false;

    }

    /*
     * Show Message Box With SOAP Error If We Receive A Fault Code Back From Service
     *
     */
    private void showSoapException(FaultException e)
    {
        MessageFault message = e.CreateMessageFault();

        XmlElement errorDetail = message.GetDetail<XmlElement>();

        XmlNodeList errorDetails = errorDetail.ChildNodes;

        String fullErrorDetails = "";

        for (int i = 0; i < errorDetails.Count; i++)
        {
            fullErrorDetails += errorDetails.Item(i).Name + ": " + errorDetails.Item(i).InnerText + "\n";
        }

        MessageBox.Show("An Error Occured With Royal Mail Service: " + message.Reason.ToString() + "\n\n" + fullErrorDetails, "Royal Mail SOAP Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
    }

    public createShipmentResponse SendCreateShipmentRequest(CreateShipmentForm shippingForm)
    {

        shippingAPIPortTypeClient client = GetProxy();

        try
        {

            createShipmentRequest request = new createShipmentRequest();
            request.integrationHeader = GetIntegrationHeader();

            requestedShipment shipment = new requestedShipment();

            // Shipment Type Code (Delivery or Return)
            referenceDataType shipmentType = new referenceDataType();
            shipmentType.code = shippingForm.GetShippingType();
            shipment.shipmentType = shipmentType;

            // Service Occurence (Identifies Agreement on Customers Account) Default to 1. Not Required If There Is There Is Only 1 On Account
            shipment.serviceOccurrence = config.GetServiceOccurance();

            // Service Type Code (1:24H 1st Class, 2: 48H 2nd Class, D: Special Delivery Guaranteed, H: HM Forces (BFPO), I: International, R: Tracked Returns, T: Tracked Domestic)
            referenceDataType serviceType = new referenceDataType();
            serviceType.code = shippingForm.GetServiceType().GetServiceTypeCode();
            shipment.serviceType = serviceType;

            // Service Offering (See Royal Mail Service Offering Type Codes. Too Many To List)
            serviceOfferingType serviceOfferingTypeContainer = new serviceOfferingType();
            referenceDataType serviceOffering = new referenceDataType();
            serviceOffering.code = shippingForm.GetServiceOffering().GetCode();
            serviceOfferingTypeContainer.serviceOfferingCode = serviceOffering;
            shipment.serviceOffering = serviceOfferingTypeContainer;

            // Service Format Code
            serviceFormatType serviceFormatTypeContainer = new serviceFormatType();
            referenceDataType serviceFormat = new referenceDataType();
            serviceFormat.code = shippingForm.GetServiceFormat().GetFormat();
            serviceFormatTypeContainer.serviceFormatCode = serviceFormat;
            shipment.serviceFormat = serviceFormatTypeContainer;

            // Shipping Date
            shipment.shippingDate = shippingForm.GetShippingDate();
            shipment.shippingDateSpecified = true;

            // Signature Required (Only Available On Tracked Services)
            if (shippingForm.IsSignatureRequired())
            {
                shipment.signature = true;
            }
            else
            {
                shipment.signature = false;

                // Leave In Safe Place (Available On Tracked Non Signature Service Offerings)
                shipment.safePlace = shippingForm.GetSafePlaceText();
            }
            shipment.signatureSpecified = true;

            // Sender Reference Number (e.g. Invoice Number or RA Number)
            shipment.senderReference = shippingForm.GetInvoiceNumber();

            /*
             * Service Enhancements
            */

            List<serviceEnhancementType> serviceEnhancements = new List<serviceEnhancementType>();

            List<dataObjects.ServiceEnhancement> selectedEnhancements = shippingForm.GetServiceEnhancements();

            for (int i = 0; i < selectedEnhancements.Count; i++)
            {
                serviceEnhancementType enhancement = new serviceEnhancementType();
                referenceDataType enhancementCode = new referenceDataType();
                enhancementCode.code = selectedEnhancements.ElementAt(i).GetEnhancementType().ToString();
                enhancement.serviceEnhancementCode = enhancementCode;
                serviceEnhancements.Add(enhancement);
            }

            shipment.serviceEnhancements = serviceEnhancements.ToArray();


            /*
             * Recipient Contact Details
            */

            contact recipientContact = new contact();
            recipientContact.complementaryName = shippingForm.GetCompany();
            recipientContact.name = shippingForm.GetName();

            if(!shippingForm.GetEmailAddress().Equals("")) {
                digitalAddress email = new digitalAddress();
                email.electronicAddress = shippingForm.GetEmailAddress();
                recipientContact.electronicAddress = email;
            }

            if(!shippingForm.GetMobileNumber().Equals("")) {
                telephoneNumber tel = new telephoneNumber();

                Regex phoneRegex = new Regex(@"[^\d]");
                tel.telephoneNumber1 = phoneRegex.Replace(shippingForm.GetMobileNumber(), "");
                tel.countryCode = "00" + shippingForm.GetCountry().GetDialingCode();
                recipientContact.telephoneNumber = tel;
            }

            shipment.recipientContact = recipientContact;

            /*
             * Recipient Address
             * 
            */
            address recipientAddress = new address();
            recipientAddress.addressLine1 = shippingForm.GetAddressLine1();
            recipientAddress.addressLine2 = shippingForm.GetAddressLine2();
            recipientAddress.addressLine3 = shippingForm.GetAddressLine3();
            recipientAddress.addressLine4 = shippingForm.GetCounty();
            recipientAddress.postTown = shippingForm.GetTown();
            countryType country = new countryType();
            referenceDataType countryCode = new referenceDataType();
            countryCode.code = shippingForm.GetCountry().getCountryCode();
            country.countryCode = countryCode;
            recipientAddress.country = country;
            recipientAddress.postcode = shippingForm.GetPostCode();

            recipientAddress.stateOrProvince = new stateOrProvinceType();
            recipientAddress.stateOrProvince.stateOrProvinceCode = new referenceDataType();

            shipment.recipientAddress = recipientAddress;

            // Shipment Items

            List<RoyalMailAPI.RoyalMailShippingAPI.item> items = new List<RoyalMailAPI.RoyalMailShippingAPI.item> ();

            foreach(dataObjects.Item i in shippingForm.GetItems()) {
                RoyalMailAPI.RoyalMailShippingAPI.item item = new RoyalMailAPI.RoyalMailShippingAPI.item();
                item.numberOfItems = i.GetQty().ToString();
                item.weight = new dimension();
                item.weight.value = (float) (i.GetWeight() * 1000);
                item.weight.unitOfMeasure = new unitOfMeasureType();
                item.weight.unitOfMeasure.unitOfMeasureCode = new referenceDataType();
                item.weight.unitOfMeasure.unitOfMeasureCode.code = "g";

                items.Add(item);
            }

            if (shippingForm.GetServiceType().GetDescription().ToLower().Contains("international"))
            {
                internationalInfo InternationalInfo = new internationalInfo();
                InternationalInfo.shipperExporterVatNo = "GB945777273";
                InternationalInfo.documentsOnly = false;
                InternationalInfo.shipmentDescription = "Invoice Number: " + shippingForm.GetInvoiceNumber();
                InternationalInfo.invoiceDate = DateTime.Now;
                InternationalInfo.termsOfDelivery = "EXW";
                InternationalInfo.invoiceDateSpecified = true;
                InternationalInfo.purchaseOrderRef = shippingForm.GetInvoiceNumber();

                List<RoyalMailShippingAPI.parcel> parcels = new List<parcel>();
                foreach (dataObjects.Item i in shippingForm.GetItems())
                {
                    parcel Parcel = new parcel();
                    Parcel.weight = new dimension();
                    Parcel.weight.value = (float)(i.GetWeight() * 1000);
                    Parcel.weight.unitOfMeasure = new unitOfMeasureType();
                    Parcel.weight.unitOfMeasure.unitOfMeasureCode = new referenceDataType();
                    Parcel.weight.unitOfMeasure.unitOfMeasureCode.code = "g";

                    Parcel.invoiceNumber = shippingForm.GetInvoiceNumber();
                    Parcel.purposeOfShipment = new referenceDataType();
                    Parcel.purposeOfShipment.code = "31";

                    List<contentDetail> Contents = new List<contentDetail>();
                    foreach (RoyalMailAPI.dataObjects.ProductDetail product in i.GetProducts())
                    {
                        contentDetail ContentDetail = new contentDetail();
                        ContentDetail.articleReference = product.Sku;
                        ContentDetail.countryOfManufacture = new countryType();
                        ContentDetail.countryOfManufacture.countryCode = new referenceDataType();
                        ContentDetail.countryOfManufacture.countryCode.code = product.CountryOfManufacture;

                        ContentDetail.currencyCode = new referenceDataType();
                        ContentDetail.currencyCode.code = product.CurrencyCode;
                        ContentDetail.description = product.Name;
                        ContentDetail.unitQuantity = product.Qty.ToString();
                        ContentDetail.unitValue = Convert.ToDecimal(product.Price);
                        ContentDetail.unitWeight = new dimension();
                        ContentDetail.unitWeight.value = Convert.ToSingle(product.Weight * 1000);
                        ContentDetail.unitWeight.unitOfMeasure = new unitOfMeasureType();
                        ContentDetail.unitWeight.unitOfMeasure.unitOfMeasureCode = new referenceDataType();
                        ContentDetail.unitWeight.unitOfMeasure.unitOfMeasureCode.code = "g";


                        Contents.Add(ContentDetail);
                    }

                    //Parcel.contentDetails = Contents.ToArray();

                    parcels.Add(Parcel);

                }

                InternationalInfo.parcels = parcels.ToArray();

                shipment.internationalInfo = InternationalInfo;
            }
            else
            {
                shipment.items = items.ToArray();
            }

            request.requestedShipment = shipment;

            createShipmentResponse response = client.createShipment(GetSecurityHeaderType(), request);

            // Show Errors And Warnings
            checkErrorsAndWarnings(response.integrationFooter);

            return response;

        }
        catch (TimeoutException e)
        {
            client.Abort();
            MessageBox.Show("Request Timed Out: " + e.Message, "Request Timeout", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
        }
        catch (FaultException e)
        {
            client.Abort();
            showSoapException(e);
        }
        catch (CommunicationException e)
        {
            client.Abort();
            MessageBox.Show("A communication error has occured: " + e.Message + " - " + e.StackTrace, "Communication Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
        }
        catch (Exception e)
        {
            client.Abort();
            MessageBox.Show(e.Message, "Royal Mail Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
        }

        return null;
    }

这篇关于使用WCF皇家邮政API在C#控制台应用程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆