Prevent "To" SOAP header being added - c#

I'm have a problem with a SOAP header created in my C# client. The server is sending back the error
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<s:Header xmlns:s="http://www.w3.org/2003/05/soap-envelope" />
<soap:Body>
<soap:Fault>
<soap:Code>
<soap:Value>soap:MustUnderstand</soap:Value>
</soap:Code>
<soap:Reason>
<soap:Text xml:lang="en">MustUnderstand headers: [{http://www.w3.org/2005/08/addressing}To] are not understood.</soap:Text>
</soap:Reason>
</soap:Fault>
</soap:Body>
</soap:Envelope>
I have been under the impression that I have been removing all SOAP headers with the following code.
internal class CustomMessageInspector : IEndpointBehavior, IClientMessageInspector
{
public object BeforeSendRequest( ref Message request, IClientChannel channel )
{
request.Headers.Clear();
return null;
}
...
}
However, after activating System.ServiceModel.MessageLogging in the app.config, (WCF - Inspect the messages being sent/received?), I see that the server is correct - lo and behold there is a "To" header with "mustUnderstand" set to 1 :
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<a:To s:mustUnderstand="1">https://ws-single-transactions-int-bp.nmvs.eu:8443/WS_SINGLE_TRANSACTIONS_V1/SinglePackServiceV30</a:To>
</s:Header>
Any thoughts how I can prevent this header from being added?
Many thanks.

In case it helps anybody else, I have found a solution. In fact Nicolas Giannone provided all the necessary code here WSHttpBinding in .NetStandard or .NET core . What we can do is to replace the WSHttpBinding with a custom binding based on the WSHttpBinding, and then replace the TextMessageEncodingBindingElement with one with no addressing. Here's the code :
string endPoint = myConfig.SinglePackServicesEndPoint;
//Defines a secure binding with certificate authentication
WSHttpBinding binding = new WSHttpBinding();
binding.Security.Mode = SecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
// create a new binding based on the existing binding
var customTransportSecurityBinding = new CustomBinding( binding );
// locate the TextMessageEncodingBindingElement - that's the party guilty of the inclusion of the "To"
var ele = customTransportSecurityBinding.Elements.FirstOrDefault( x=>x is TextMessageEncodingBindingElement );
if( ele != null )
{
// and replace it with a version with no addressing
// replace {Soap12 (http://www.w3.org/2003/05/soap-envelope) Addressing10 (http://www.w3.org/2005/08/addressing)}
// with {Soap12 (http://www.w3.org/2003/05/soap-envelope) AddressingNone (http://schemas.microsoft.com/ws/2005/05/addressing/none)}
int index = customTransportSecurityBinding.Elements.IndexOf( ele );
var textBindingElement = new TextMessageEncodingBindingElement
{
MessageVersion = MessageVersion.CreateVersion(EnvelopeVersion.Soap12, AddressingVersion.None)
};
customTransportSecurityBinding.Elements[index] = textBindingElement;
}

Related

WCF Service Reference Interface and Excessive Namespaces in Java Web Service Response

So I am working on an internal project where I am consuming a Java based SOAP Web Service from a WinForm application using a WCF Service Reference interface. (This is something new for me so I apologize if I not totally using the right terminology, etc.) I am sending my request over to the service and I am getting a response, although it has taken some hoop jumping to get there. The format of the response is what is causing me some problems in that it has excessive namespaces and the response size can get large.
I hope someone can point me to a simple solution / setting to reduce the excess.
A few things that I have no control over: The interface is via HTTP (not HTTPS) and security is handled via an App Key/ID mechanism using the a SOAP Security Header and client certificates. The server WSDL does not indicate that WSSE is required in the SOAP Header so the header is being overwritten by the security one prior to the send.
All items below are actual code structure and SOAP request/response format but have been changed to generic items. Also, the "response" is greatly reduced in size. With the right request parameters, a response is over 64k in length.
The SoapUI Request 1 example built with the WSDL load looks like this:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:pric="http://xmlns.example.com/system/pricing" xmlns:ns="http://xmlns.example.com/system/pricing/shared/3.1.1">
<soapenv:Header/>
<soapenv:Body>
<pric: PricingRequest majorVersion="2" minorVersion="1">
<pric:version>?</pric:version>
<pric:timestamp>?</pric:timestamp>
<!--1 or more repetitions:-->
<pric:acctType>
<!--You have a CHOICE of the next 2 items at this level-->
<pric:customerNbr>?</pric: customerNbr >
<pric:accountNbr>?</pric:accountNbr>
</pric: acctType >
<!--1 to 3 repetitions:-->
<pric:system>?</pric: system >
<pric:source>?</pric:source>
<pric:searchItems>
<pric:purchaseDate>?</pric: purchaseDate >
<!--Zero or more repetitions:-->
<pric:service>
<ns:system>?</ns:system>
<ns:serviceType>?</ns:serviceType>
<!--Optional:-->
<ns:serviceDesc>?</ns:serviceDesc>
<!--Optional:-->
<ns:billingType>?</ns:billingType>
<!--Optional:-->
<ns:effectiveDate>?</ns:effectiveDate>
<!--Optional:-->
<ns:expirationDate>?</ns:expirationDate>
<!--Optional:-->
</pric:service>
</pric: searchItems >
</pric: PricingRequest >
</soapenv:Body>
</soapenv:Envelope>
The app.config Service Model - I added the maxReceivedMessageSize in order to handle the large responses:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="PricingServiceSoap11" maxReceivedMessageSize="256000" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://pricing-websvc.example.com:60000/PricingService"
binding="basicHttpBinding" bindingConfiguration="PricingServiceSoap11"
contract="pricingSvcRef.PricingService" name="PricingServiceSoap11" />
</client>
</system.serviceModel>
Code to consume service:
pricingSvcRef.PricingClient pricing = new pricingSvcRef.PricingClient();
var reqInfo = new InspectorBehavior();
pricing.Endpoint.Behaviors.Add(reqInfo);
pricingSvcRef.PricingRequest request = new pricingSvcRef.PricingRequest();
request.majorVersion = 2;
request.minorVersion = 1;
request.version = pricingSvcRef.PricingRequestVersion.Ver1;
request.timestamp = DateTime.Now;
request.acctType = new pricingSvcRef.PricingRequestAcctType[1];
request.acctType[0] = new pricingSvcRef.GetPricingRequestAcctype();
request.acctType[0].Item = txtAcctNo.Text.Trim();
request.system = "Pricing";
request.source = "MyApp";
List<pricingSvcRef.pricingService> svcList = new List<pricingSvcRef.pricingService>();
svcList.Add(
new pricingSvcRef.pricingService
{
system = txtSystem.Text.Trim(),
serviceType = Convert.ToInt32(txServiceType.Text.Trim(),
serviceDesc = txtService.Text.Trim(),
billingType = Convert.ToInt32(txBillingType.Text.Trim(),
effectiveDate = dateEffective.Value,
expirationDate = dateExpiration.Value
});
pricingSvcRef.PricingRequestSearchItems srchItems = new pricingSvcRef.PricingRequestSearchItems
{
purchaseDate = DateTime.Now;
service = svcList.ToArray(),
};
request.searchItems = srchItems;
pricingSvcRef.PricingResponse response = null;
try
{
response = eddSvcRef.GetPricing(request);
}
catch (Exception ex)
{
string msg = "Msg: " + ex.Message;
if ((ex.InnerException != null) && (ex.InnerException.Message.Trim().Length > 0))
msg = msg + "\r\n\r\nInner Msg: " + ex.InnerException.Message.Trim();
MessageBox.Show(msg);
}
SOAP Request that is generated:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:Username>v1:APP1234567:SfPLRHKdXWWqW7mdOdk+gTABVo+y4VZR7UqLHWibVD73jaI0IL9FT4PMgAVAxGsa83P/aon61GuS+IZnuVjRHR4hJgyMuCvtI07QtNaSdwEyw9Lw/Iewm+098fkMYK2pflV7w6hn0U2A9/wzuQS/vfWe53vhGSX1zfhuo6AygKA=:APP1234567</wsse:Username>
</wsse:UsernameToken>
</Security>
</s:Header>
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<PricingRequest majorVersion="2" minorVersion="1" xmlns="http://xmlns.example.com/system/pricing">
<version>1.0.0</version>
<timestamp>2019-03-25T09:46:26.7337264-05:00</timestamp>
<acctType>
<accountNbr>123456789</accountNbr>
</acctType>
<system>Pricing</system>
<source>MyApp</source>
<searchItems>
<purchaseDate>2019-03-25</purchaseDate>
<service>
<system xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">MyPricing</system>
<serviceType xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">1000</serviceType>
<serviceDesc xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">Service Description</serviceDesc>
<billingType xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">1234</billingType>
<effectiveDate xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">2019-01-01</effectiveDate>
<expirationDate xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">2019-12-31</expirationDate>
</service>
</searchItems>
</PricingRequest>
</s:Body>
</s:Envelope>
SOAP Response in application:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header />
<SOAP-ENV:Body>
<PricingResponse xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1" xmlns:ns2="http://xmlns.example.com/system/pricing">
<pricingContainer xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">
<version xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">1.0.0</version>
<timestamp xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">2019-03-25T14:46:28.876Z</timestamp>
<source xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">MyApp</source>
<status xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">
<code xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">0000</code>
<description xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">SUCCESS</description>
</status>
<acctType xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">
<accountNbr xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">123456789</accountNbr>
</acctType>
<system xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">Pricing</system>
<serviceDetail xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">
<valid xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">Y</valid>
<system xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">MyPricing</system>
<serviceType xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">1000</serviceType>
<serviceDesc xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">Service Description</serviceDesc>
<billingType xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">1234</billingType>
<effectiveDate xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">2019-01-01</effectiveDate>
<expirationDate xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">2019-12-31</expirationDate>
<pricingRate xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">100</pricingRate>
</serviceDetail>
</pricingContainer>
</PricingResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
So even though namespaces are returning as part of the PricingResponse element, they are also on each child item below that.
UPDATE: I thought SoapUI responses were coming back w/o the excessive namespace items on each element but I have now determined using Wireshark and SoapUI Raw display that this not the case.
Is there anyway to request from the WCF Interface to the Java Web Service that the response uses namespace prefixes rather than having a namespace on almost every response element? Obviously I am going to keep digging at it but any help / guidance would be appreciated.
Thanks

Adding SOAP Header to request

I have been trying to add a header to SOAP request as follows
<soapenv:Header>
<UsernameToken xmlns="http://test.com/webservices">username</UsernameToken>
<PasswordText xmlns="http://test.com/webservices">password</PasswordText>
<SessionType xmlns="http://test.com/webservices">None</SessionType>
</soapenv:Header>
I have found suggestions to use SoapHeader to include header values, but introduces another level such as
<soapenv:Header>
<CustomHeader>
<UsernameToken xmlns="http://test.com/webservices">username</UsernameToken>
<PasswordText xmlns="http://test.com/webservices">password</PasswordText>
<SessionType xmlns="http://test.com/webservices">None</SessionType>
</CustomHeader>
</soapenv:Header>
Can anyone suggest how I can form a request without CustomHeader.
Try to use this one
private static void Main()
{
using (var client = new ServiceClient())
using (var scope = new OperationContextScope(client.InnerChannel))
{
MessageHeader usernameTokenHeader = MessageHeader.CreateHeader("UsernameToken",
"http://test.com/webservices", "username");
OperationContext.Current.OutgoingMessageHeaders.Add(usernameTokenHeader);
MessageHeader passwordTextHeader = MessageHeader.CreateHeader("PasswordText",
"http://test.com/webservices", "password");
OperationContext.Current.OutgoingMessageHeaders.Add(passwordTextHeader);
MessageHeader sessionTypeHeader = MessageHeader.CreateHeader("SessionType",
"http://test.com/webservices", "None");
OperationContext.Current.OutgoingMessageHeaders.Add(sessionTypeHeader);
string result = client.GetData(1);
Console.WriteLine(result);
}
Console.ReadKey();
}
The Service Trace viewer shows following
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<UsernameToken xmlns="http://test.com/webservices">username</UsernameToken>
<PasswordText xmlns="http://test.com/webservices">password</PasswordText>
<SessionType xmlns="http://test.com/webservices">None</SessionType>
<To s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://localhost:13332/Service1.svc</To>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://tempuri.org/IService/GetData</Action>
</s:Header>
</s:Envelope>
Take a look OperationContextScope for more info

Duplicate security elements when building custom soap request

I'm trying to send a soap request to a WCF service. I am building the soap request using the System.ServiceModel.Channels.Message.CreateMessage() method.
I haven't gotten super deep into building the body, but here is what I have...
Message msg = Message.CreateMessage( MessageVersion.Soap11WSAddressing10, "MethodName" );
msg.Headers.MessageId = new UniqueId( Guid.NewGuid().ToString() );
msg.Headers.Add( Message.CreateHeader( "Security", "",
new Security()
{
TimeStamp = new TimeStampType() {
Created = DateTime.Now,
Expires = Created.AddDays( 1 )
},
UsernameToken = new UsernameToken() {
Username = "stackoverflow",
Password = new Password() {
Type = "hashed",
Value = "Password"
}
}
}, new SecuritySerializer() ) ) ); // The serializer inherits XmlObjectSerializer. Internally it is using the XmlSerializer class.
string s = msg.ToString();
When I run this, I get the following output. I'm using the Visual Studio XML Visualizer btw.
<s:Envelope>
<s:Header>
<Action>MethodName</Action>
<MessageID>GUIDVALUE</MessageID>
<Security>
<Security>
.....
</Security>
</Security>
</s:Header>
<s:Body />
</s:Envelope>
My question is, how can I remove one of the Security elements? I'm supposed to have one, but I have two since I first passed in the element name to the Message.CreateHeader() method and the second one was generated from the serializer.
Thanks in advance
I fixed this by making the Security class inherit from the MessageHeader abstract class. I then overrided the OnWriteHeaderContents method and serialized the properties there. Also I took out MessageHeader.CreateHeader() since the Security object is now a header object.

Exchange 2010 PushSubscription WCF SOAP

I'm trying to use the PushSubscription feature of Exchange 2010. So far I've got the code to setup push on Exchange 2010:
ExchangeService esService = new ExchangeService();
esService.Credentials = new WebCredentials("user", "pass", "domain");
esService.Url = new Uri("https://exchange-box-2010/ews/exchange.asmx");
PushSubscription ps = esService.SubscribeToPushNotificationsOnAllFolders(new Uri("http://192.168.1.102:8080/FinWorkFlow"), 1, null, EventType.NewMail, EventType.Copied);
I've also got a WCF service that run's at http://192.168.1.102:80/FinWorkFlow with a tcp tracing utility redirecting from 8080 to 80. The traces indicate that Exchange sends out a request to http://192.168.1.102:8080/FinWorkFlow and that a good response is sent from my WCF service. However the SendNotificationResponseType parameter of the SendNotification method is always null:
SendNotificationResultType INotificationServiceBinding.SendNotification(SendNotificationResponseType request)
{
if(request != null && request.ResponseMessages != null)
{
foreach(ResponseMessageType messsage in request.ResponseMessages.Items)
{
if(messsage.ResponseCode != ResponseCodeType.NoError)
{
return CreateNotificationResult(SubscriptionStatusType.Unsubscribe);
}
SendNotificationResponseMessageType mtNotificationMessage = (SendNotificationResponseMessageType)messsage;
NotificationType ntNotification = mtNotificationMessage.Notification;
string strSubscriptionId = ntNotification.SubscriptionId;
for(int i = 0; i < ntNotification.Items.Length; i++)
{
if(ntNotification.ItemsElementName[i].ToString() == "NewMailEvent")
{
BaseObjectChangedEventType bocet = (BaseObjectChangedEventType)ntNotification.Items[i];
}
}
}
}
return CreateNotificationResult(SubscriptionStatusType.OK);
}
The interface is defined as:
[System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "2.0.50727.42")]
[System.Web.Services.WebServiceBindingAttribute(Name = "NotificationServiceBinding", Namespace = "http://schemas.microsoft.com/exchange/services/2006/messages")]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(ServiceConfiguration))]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(DirectoryEntryType))]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(TargetFolderIdType))]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(RecurrenceRangeBaseType))]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(RecurrencePatternBaseType))]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(AttachmentType))]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(BasePermissionType))]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(BaseItemIdType))]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(BaseEmailAddressType))]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(BaseFolderIdType))]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(BaseFolderType))]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(BaseResponseMessageType))]
[ServiceContract(Namespace = "http://schemas.microsoft.com/exchange/services/2006/messages", ConfigurationName = "Microsoft.Exchange.Notifications.INotificationServicePortType")]
public interface INotificationServiceBinding
{
/// <remarks/>
[OperationContract(Action = "*", ReplyAction = "*")]
[System.Web.Services.WebMethodAttribute()]
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://schemas.microsoft.com/exchange/services/2006/messages/SendNotification", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Bare)]
[return: System.Xml.Serialization.XmlElementAttribute(Namespace = "http://schemas.microsoft.com/exchange/services/2006/messages")]
SendNotificationResultType SendNotification([System.Xml.Serialization.XmlElementAttribute("SendNotification", Namespace = "http://schemas.microsoft.com/exchange/services/2006/messages")] SendNotificationResponseType SendNotification1);
}
A typical request from Exchange is:
POST /FinWorkFlow HTTP/1.1
Content-Type: text/xml; charset=utf-8
Accept: text/xml
SOAPAction: http://schemas.microsoft.com/exchange/services/2006/messages/SendNotification
Host: 192.168.1.102:8080
Content-Length: 1486
Connection: Close
<?xml version="1.0" encoding="utf-8"?><soap11:Envelope xmlns:soap11="http://schemas.xmlsoap.org/soap/envelope/"><soap11:Header><RequestServerVersion xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" Version="Exchange2010" /></soap11:Header><soap11:Body><m:SendNotification xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"><m:ResponseMessages><m:SendNotificationResponseMessage ResponseClass="Success"><m:ResponseCode>NoError</m:ResponseCode><m:Notification><t:SubscriptionId>EgBiZnQtbWVybGluLnJibS5sYW4QAAAAz4lScRmxbEaLeCfsAFRDmEswGeTtJs0I</t:SubscriptionId><t:PreviousWatermark>AQAAAOUSjqlc3mdHh1LhIiuqSBc1UCgAAAAAAAA=</t:PreviousWatermark><t:MoreEvents>false</t:MoreEvents><t:NewMailEvent><t:Watermark>AQAAAOUSjqlc3mdHh1LhIiuqSBc8UCgAAAAAAAE=</t:Watermark><t:TimeStamp>2010-09-20T15:16:28Z</t:TimeStamp><t:ItemId Id="AAMkAGVmOWI3OGE5LWJmMjEtNDU4Mi1hY2JlLTdhYzZmMGQ2N2Q4ZABGAAAAAACd5Nq062e3ToqPr4+g8e/UBwDjUS8vlMohRaUyr3p641BAACy83CEfAABwOzEV48hOQJYkk18qYDCqAAAAnG3SAAA=" ChangeKey="CQAAAA==" /><t:ParentFolderId Id="AAMkAGVmOWI3OGE5LWJmMjEtNDU4Mi1hY2JlLTdhYzZmMGQ2N2Q4ZAAuAAAAAACd5Nq062e3ToqPr4+g8e/UAQDjUS8vlMohRaUyr3p641BAACy83CEfAAA=" ChangeKey="AQAAAA==" /></t:NewMailEvent></m:Notification></m:SendNotificationResponseMessage></m:ResponseMessages></m:SendNotification></soap11:Body></soap11:Envelope>
Can anyone explain why the body of the SOAP request is not being picked up and put into the SendNotificationResponseType variable?
Finally figured it out!
Turns out that I used the wsdl tool to build the interface - should have used svcutil. This built an interface with the correct method attributes.

Problem with Fedex Address Verification Web Reference

I'm trying to get the sample FedEx Address Verification application to work in C#. After contacting my FedEx technical contact and having him activate Address Verification on my test account (apparently it is considered an advanced service that requires additional permissions) I was able to compile and run the example application.
However, I wasn't getting quite the results I expected given the settings...
request.Options.ConvertToUpperCase = true;
request.Options.CheckResidentialStatus = true;
Based on these flags, I expected to have the address come back in upper case, and to be able to check the Residential or ResidentialStatus properties to determine commercial vs residential. Neither were occuring.
So I installed Fiddler to see the exact SOAP exchange that was taking place and found that the outbound Options tag was not populating except for one property, MaximumNumberOfMatches.
Is there something I should check for in the Reference.cs file that is created by Visual Studio? I didn't see anything out of the norm, but something is happening that is preventing the serialization of some of the properties.
--Edit--
Updated my code as per the suggestion below. Unfortunately, it still only populates 2 of the options parameters. I've included the C# settings code and the outbound/inbound SOAP request below. Can anyone think of a reason the rest of the options are not being sent in the SOAP request?
AddressValidationRequest request = new AddressValidationRequest();
//
request.WebAuthenticationDetail = new WebAuthenticationDetail();
request.WebAuthenticationDetail.UserCredential = new WebAuthenticationCredential();
request.WebAuthenticationDetail.UserCredential.Key = "XXX-KEY-XXX"; // Replace "XXX" with the Key
request.WebAuthenticationDetail.UserCredential.Password = "XXX-PWD-XXX"; // Replace "XXX" with the Password
//
request.ClientDetail = new ClientDetail();
request.ClientDetail.AccountNumber = "XXX-ACCT#-XXX"; // Replace "XXX" with client's account number
request.ClientDetail.MeterNumber = "XXX-MTR#-XXX"; // Replace "XXX" with client's meter number
//
request.TransactionDetail = new TransactionDetail();
request.TransactionDetail.CustomerTransactionId = "***Address Validation v2 Request using VC#***"; // This is just an echo back
//
request.Version = new VersionId(); // Creates the Version element with all child elements populated
//
request.RequestTimestamp = DateTime.Now;
//
request.Options = new AddressValidationOptions();
request.Options.CheckResidentialStatus = true;
request.Options.CheckResidentialStatusSpecified = true;
request.Options.VerifyAddresses = true;
request.Options.MaximumNumberOfMatches = "5";
request.Options.StreetAccuracy = AddressValidationAccuracyType.MEDIUM;
request.Options.DirectionalAccuracy = AddressValidationAccuracyType.MEDIUM;
request.Options.CompanyNameAccuracy = AddressValidationAccuracyType.MEDIUM;
request.Options.ConvertToUpperCase = true;
request.Options.RecognizeAlternateCityNames = true;
request.Options.ReturnParsedElements = true;
//
request.AddressesToValidate = new AddressToValidate[2];
request.AddressesToValidate[0] = new AddressToValidate();
request.AddressesToValidate[0].AddressId = "Kimmel";
request.AddressesToValidate[0].Address = new Address();
request.AddressesToValidate[0].Address.StreetLines = new String[1] { "425 Morningside Dr" };
request.AddressesToValidate[0].Address.City = "Deerfield";
request.AddressesToValidate[0].Address.PostalCode = "53531";
request.AddressesToValidate[0].Address.CountryCode = "US";
//
request.AddressesToValidate[1] = new AddressToValidate();
request.AddressesToValidate[1].AddressId = "WD";
request.AddressesToValidate[1].Address = new Address();
request.AddressesToValidate[1].Address.StreetLines = new String[1] { "2830 Progress Rd" };
request.AddressesToValidate[1].Address.PostalCode = "53716";
request.AddressesToValidate[1].CompanyName = "Wingra Direct";
The outbound SOAP Request (obtained using Fiddler). Note the missing options:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<AddressValidationRequest xmlns="http://fedex.com/ws/addressvalidation/v2">
<WebAuthenticationDetail>
<UserCredential>
<Key>XXX-KEY-XXX</Key>
<Password>XXX-PWD-XXX</Password>
</UserCredential>
</WebAuthenticationDetail>
<ClientDetail>
<AccountNumber>XXX-ACCT#-XXX</AccountNumber>
<MeterNumber>XXX-MTR#-XXX</MeterNumber>
</ClientDetail>
<TransactionDetail>
<CustomerTransactionId>***Address Validation v2 Request using VC#***</CustomerTransactionId>
</TransactionDetail>
<Version>
<ServiceId>aval</ServiceId>
<Major>2</Major>
<Intermediate>0</Intermediate>
<Minor>0</Minor>
</Version>
<RequestTimestamp>2010-08-26T16:40:13.2026134-05:00</RequestTimestamp>
<Options>
<CheckResidentialStatus>true</CheckResidentialStatus>
<MaximumNumberOfMatches>5</MaximumNumberOfMatches>
</Options>
<AddressesToValidate>
<AddressId>Kimmel</AddressId>
<Address>
<StreetLines>425 Morningside Dr</StreetLines>
<City>Deerfield</City>
<PostalCode>53531</PostalCode>
<CountryCode>US</CountryCode>
<Residential>true</Residential>
</Address>
</AddressesToValidate>
<AddressesToValidate>
<AddressId>WD</AddressId>
<CompanyName>Wingra Direct</CompanyName>
<Address>
<StreetLines>2830 Progress Rd</StreetLines>
<PostalCode>53716</PostalCode>
</Address>
</AddressesToValidate>
</AddressValidationRequest>
</soap:Body>
</soap:Envelope>
The response I get back is:
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<env:Header xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"/>
<soapenv:Body>
<v2:AddressValidationReply xmlns:v2="http://fedex.com/ws/addressvalidation/v2">
<v2:HighestSeverity>SUCCESS</v2:HighestSeverity>
<v2:Notifications>
<v2:Severity>SUCCESS</v2:Severity>
<v2:Source>wsi</v2:Source>
</v2:Notifications>
<v2:TransactionDetail xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<v2:CustomerTransactionId>***Address Validation v2 Request using VC#***</v2:CustomerTransactionId>
</v2:TransactionDetail>
<v2:Version xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<v2:ServiceId>aval</v2:ServiceId>
<v2:Major>2</v2:Major>
<v2:Intermediate>0</v2:Intermediate>
<v2:Minor>0</v2:Minor>
</v2:Version>
<v2:ReplyTimestamp>2010-08-26T21:40:14.140Z</v2:ReplyTimestamp>
<v2:AddressResults>
<v2:AddressId>Kimmel</v2:AddressId>
<v2:ProposedAddressDetails>
<v2:Score>93</v2:Score>
<v2:Changes>MODIFIED_TO_ACHIEVE_MATCH</v2:Changes>
<v2:ResidentialStatus>UNAVAILABLE</v2:ResidentialStatus>
<v2:DeliveryPointValidation>CONFIRMED</v2:DeliveryPointValidation>
<v2:Address>
<v2:StreetLines>425 Morningside Dr</v2:StreetLines>
<v2:City>Deerfield</v2:City>
<v2:StateOrProvinceCode>WI</v2:StateOrProvinceCode>
<v2:PostalCode>53531-9492</v2:PostalCode>
<v2:CountryCode>US</v2:CountryCode>
</v2:Address>
<v2:RemovedNonAddressData/>
</v2:ProposedAddressDetails>
</v2:AddressResults>
<v2:AddressResults>
<v2:AddressId>WD</v2:AddressId>
<v2:ProposedAddressDetails>
<v2:Score>93</v2:Score>
<v2:Changes>MODIFIED_TO_ACHIEVE_MATCH</v2:Changes>
<v2:ResidentialStatus>UNAVAILABLE</v2:ResidentialStatus>
<v2:DeliveryPointValidation>CONFIRMED</v2:DeliveryPointValidation>
<v2:CompanyName>Wingra Direct</v2:CompanyName>
<v2:Address>
<v2:StreetLines>2830 Progress Rd</v2:StreetLines>
<v2:City>Madison</v2:City>
<v2:StateOrProvinceCode>WI</v2:StateOrProvinceCode>
<v2:PostalCode>53716-3338</v2:PostalCode>
<v2:CountryCode>US</v2:CountryCode>
</v2:Address>
<v2:RemovedNonAddressData/>
</v2:ProposedAddressDetails>
</v2:AddressResults>
</v2:AddressValidationReply>
</soapenv:Body>
</soapenv:Envelope>
It appears that on option is ignored unless you also set the optionSpecified flag to true also.
Here is my new options code that works - the key being that you need to add the Options.(property)specified = true for each one you want:
request.Options = New AddressValidationOptions()
request.Options.CheckResidentialStatus = True
request.Options.CheckResidentialStatusSpecified = True
request.Options.VerifyAddresses = True
request.Options.VerifyAddressesSpecified = True
request.Options.MaximumNumberOfMatches = 5
request.Options.StreetAccuracy = AddressValidationAccuracyType.MEDIUM
request.Options.DirectionalAccuracy = AddressValidationAccuracyType.MEDIUM
request.Options.CompanyNameAccuracy = AddressValidationAccuracyType.MEDIUM
request.Options.ConvertToUpperCase = True
request.Options.ConvertToUpperCaseSpecified = True
request.Options.RecognizeAlternateCityNames = True
request.Options.RecognizeAlternateCityNamesSpecified = True
request.Options.ReturnParsedElements = True
request.Options.ReturnParsedElementsSpecified = True
I was unable to get the API working so I ended up manually coding the handling of SOAP requests and responses. Aside from the API not properly setting all the flags, I also found out that the FedEx DEV server was not returning the Residential Status, regardless of what the options were (confirmed by our FedEx Web Services contact). When we gained access to the production servers the new code worked like a charm.
Here's another answer from FedEx tech support:
"The address verification API is not available from the test
environment".
So I'm not sure how you got your test account "activated" for address verification. Supposedly the FedEx system uses the USPS production address verification system which is why it's not accessible from the FedEx test environment.
I don't know if I believe this 100%, but I know that I'm hitting the FedEx test server with valid credentials and getting a "Authentication Failed" response.

Categories

Resources