Error when calling third-party method using WebService - c#

I want to send some data to a third-party application in SOAP XML format. I have added reference of their .WSDL file and the method is now available. One parameter to be sent is the CDATA part in this method.
When I test the Request and Response from SOAPUI, it works well. The data gets inserted in the third-party application. The Request looks like this:
[SOAP UI Request]
<soapenv:Envelope xmlns:soapenv=http://schemas.xmlsoap.org/soap/envelope/ xmlns:sec=http://schemas.xmlsoap.org/ws/2003/06/secext xmlns:wsu=http://schemas.xmlsoap.org/ws/2003/06/utility xmlns:urn="urn:ThirdParty">
<soapenv:Header>
<sec:Security>
<sec:UsernameToken wsu:Id="ThirdParty">
<sec:Username>abcd</sec:Username>
<!--Optional:-->
<sec:Password>abcd</sec:Password>
</sec:UsernameToken>
</sec:Security>
</soapenv:Header>
<soapenv:Body>
<urn:ImportData>
<Table>Persons</Table>
<FolderId>0</FolderId>
<Data><![CDATA[<Document>
<Record>
<FirstName>Test USer</FirstName>
<LastName>Test USer</LastName>
<IsMainRole>Yes</IsMainRole>
<IsHomeSite>Yes</IsHomeSite>
<AccountStatus>System Administrator</AccountStatus>
<IsClient/>
<UserId>test_user</UserId>
<Email>testuser#testuser.com</Email>
<UserName>test_user</UserName>
<HOFirstAxis>None</HOFirstAxis>
<ModulesIMS>2</ModulesIMS>
<InspectionType/>
<RoleName>Main</RoleName>
<Extra>mmeyers</Extra>
<FunctionalGroups/>
<SelectAllCalendarsByDefault>Yes</SelectAllCalendarsByDefault>
<GroupNameho><None></GroupNameho>
<GroupNameTCK><None></GroupNameTCK>
<GroupNameIMS><None></GroupNameIMS>
<GroupNameacs><None></GroupNameacs>
<GroupNameAP><None></GroupNameAP>
<GroupNameMoC><None></GroupNameMoC>
<GroupNameRCM><None></GroupNameRCM>
<DisplayUserLang>English</DisplayUserLang>
<UseUserRS>No</UseUserRS>
<TimeZone/>
</Record>
</Document>]]></Data>
<FormatType>3</FormatType>
<CSVSeparator>1</CSVSeparator>
<FormatOptions>22</FormatOptions>
<ImportType>2</ImportType>
<MatchType>1</MatchType>
<ImportOptions>1234</ImportOptions>
</urn:ImportData>
</soapenv:Body>
</soapenv:Envelope>
But when I copy this format in an .xml file and create the CDATA part in WCF and pass to the method, it throws error.
[Code in WCF]
[WebMethod]
[SoapHeader("header", Direction = SoapHeaderDirection.InOut)]
public string CreateXmlForImport()
{
ThirdPartyClient client = new ThirdPartyClient();
const string FILENAME = #"test.xml";
XDocument doc = XDocument.Load(FILENAME);
XNamespace nsUrn = doc.Root.GetNamespaceOfPrefix("urn");
XElement importData = doc.Descendants(nsUrn + "ImportData").FirstOrDefault();
XElement xCdata = new XElement("Document",
new XElement("Record",
new XElement("UserName", "T12345"),
new XElement("FirstName", "TEST_RP"),
new XElement("LastName", "Test_LNAME"),
new XElement("Email", "test#test.com")
));
string cDataStr = xCdata.ToString();
XCData cdata = new XCData(cDataStr);
var response = client.ImportData(cDataStr);
return response;
}
Error:
InvalidOperationException: The top XML element 'Response' from
namespace '' references distinct types System.String and
System.Object. Use XML attributes to specify another XML name or
namespace for the element or types.

Based on the error, I think it may be because they have the same element name (namespace="", name=" name ") but are of different types. In xml file you can try changing the name of the element or dropping it into a different namespace if the name is the same.
The likely cause of this problem is that the XMLSerializer uses XSD schema validation. You can read the xml serialization and this for more info.
Hope it helps.

Related

The top XML element 'Data' from namespace '' references distinct types

I have to send Active Directory data to a third-party application. This third-party application provides a .WSDL URL which I have added as a Service Reference in my .NET application. After this I have to call a function "Import" which looks something like this:
Import(Security security, string Data, int FolderID)
Here 'Data' is the XML data that needs to be transferred. I have an XML something like this:
var xEle = new XElement("Document",
from emp in lstADUsers
select new XElement("Record",
new XElement("UserName", emp.UserName),
new XAttribute("FirstName", "TEST_FNAME"),
new XAttribute("LastName", "Test_LNAME"),
new XAttribute("Email", "test#test.com")
));
I call the Import method as:
Import(token, xEle, 1)
When this method is hit, I am getting below error:
The top XML element 'Data' from namespace '' references distinct types
System.String and System.Byte[]. Use XML attributes to specify another
XML name or namespace for the element or types.
The third-party application expects SOAP data.
Extra details
SOAP envelope looks like this:
<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/' xmlns:sec='http://schemas.xmlsoap.org/ws/2003/06/secext' xmlns:wsu='http://schemas.xmlsoap.org/ws/2003/06/utility'
xmlns:urn='urn:TestApp'>
<soapenv:Header>
<sec:Security>
<sec:UsernameToken wsu:Id='TestApp'>
<sec:Username>TestUser</sec:Username>
<!--Optional:-->
<sec:Password>TestPassword</sec:Password>
</sec:UsernameToken>
</sec:Security>
</soapenv:Header>
<soapenv:Body>
<urn:ImportData>
<Table></Table>
<FolderId>0</FolderId>
<Data><![CDATA[<Document>
<Record></Record>
</Document>
</Data>
Code Changes Below
/// <summary>
/// Summary description for ThirdPArtyApp
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
// [System.Web.Script.Services.ScriptService]
public class ThirdParty : System.Web.Services.WebService
{
public Header header;
[WebMethod]
[SoapHeader("header", Direction = SoapHeaderDirection.InOut)]
public void CreateXmlForImport()
{
ThirdParty_Serv thirdParty = new ThirdParty_Serv();
header.Username = "test123";
header.Password = "XYZ123";
const string FILENAME = #"D:\Users\Documents\test.xml";
XDocument doc = XDocument.Load(FILENAME);
XNamespace nsUrn = doc.Root.GetNamespaceOfPrefix("urn");
XElement importData = doc.Descendants(nsUrn + "ImportData").FirstOrDefault();
XElement xCdata = new XElement("Document",
new XElement("Record",
new XAttribute("UserName", "T12345"),
new XAttribute("FirstName", "TEST_RP"),
new XAttribute("LastName", "Test_LNAME"),
new XAttribute("Email", "test#test.com")
));
string cDataStr = xCdata.ToString();
XCData cdata = new XCData(cDataStr);
thirdParty.ImportData("/Do/Persons", 0, cDataStr, 3);
}
}
I used the schema to get correct structure. From VS you can test the syntax by going to menu Project:Add New Item : Xml File. Than past the xml into view. Errors will show like compiler errors in the Error List. Also if you type an opening angle bracket is will show the elements that can be added in any section.
I used following xml
<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/' xmlns:sec='http://schemas.xmlsoap.org/ws/2003/06/secext' xmlns:wsu='http://schemas.xmlsoap.org/ws/2003/06/utility'
xmlns:urn='urn:TestApp'>
<soapenv:Header>
<sec:Security>
<sec:UsernameToken wsu:Id='TestApp'>
<sec:Username>TestUser</sec:Username>
<!--Optional:-->
<sec:Password>TestPassword</sec:Password>
</sec:UsernameToken>
</sec:Security>
</soapenv:Header>
<soapenv:Body>
<urn:ImportData>
<Table></Table>
<FolderId>0</FolderId>
<Record></Record>
</urn:ImportData>
</soapenv:Body>
</soapenv:Envelope>
Here is my code
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
XNamespace nsUrn = doc.Root.GetNamespaceOfPrefix("urn");
XElement importData = doc.Descendants(nsUrn + "ImportData").FirstOrDefault();
XElement xCdata = new XElement("Record",
new XElement("UserName", "username"),
new XAttribute("FirstName", "TEST_FNAME"),
new XAttribute("LastName", "Test_LNAME"),
new XAttribute("Email", "test#test.com")
);
string cDataStr = xCdata.ToString();
XCData cdata = new XCData(cDataStr);
importData.Add(cdata);
}
Here is final Xml
<?xml version="1.0"?>
<soapenv:Envelope xmlns:urn="urn:TestApp" xmlns:wsu="http://schemas.xmlsoap.org/ws/2003/06/utility" xmlns:sec="http://schemas.xmlsoap.org/ws/2003/06/secext" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header>
<sec:Security>
<sec:UsernameToken wsu:Id="TestApp">
<sec:Username>TestUser</sec:Username>
<!--Optional:-->
<sec:Password>TestPassword</sec:Password>
</sec:UsernameToken>
</sec:Security>
</soapenv:Header>
<soapenv:Body>
<urn:ImportData>
<Table/>
<FolderId>0</FolderId>
<Record/>
<![CDATA[<Record FirstName="TEST_FNAME" LastName="Test_LNAME" Email="test#test.com"><UserName>username</UserName></Record>]]>
</urn:ImportData>
</soapenv:Body>
</soapenv:Envelope>

How to change WebMethod XML output for ASP.NET Webservice, specifically namespace declaration?

I'm developing an ASP.NET Webservice (not WCF) for a given client. This is one of those situations, where you can not change anything at the client.
The client sends the following XML to request a method:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:cometxsd="http://werk-ii.de/soap/comet/Schema"
xmlns:comet="http://werk-ii.de/soap/comet"
xmlns:xop="http://www.w3.org/2004/08/xop/include"
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
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"
xmlns:xmime5="http://www.w3.org/2005/05/xmlmime"
xmlns:ns1="http://soap.comet.werkii.com/">
<SOAP-ENV:Body>
<ns1:login xsi:type="ns1:login">
<user>myusername</user>
<password>mypassword</password>
<client>whatever</client>
<language>de</language>
</ns1:login>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
My Service provides the login-Method like this:
[WebService(Namespace = "http://soap.comet.werkii.com/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
public class CometService : WebService
{
[WebMethod(MessageName = "login")]
[return: XmlElement("return")]
public LoginResult Login (string user, string password, string client, string language)
{
return new LoginResult() {
ResultCode = 0,
SessionId = user + "-" + password + "-" + client + "-" + language
};
}
}
public class LoginResult
{
[XmlElement("resultCode")]
public int ResultCode { get; set; }
[XmlElement("sessionId")]
public string SessionId { get; set; }
}
If I start the service, it tells me what SOAP 1.1 code I have to send as a request, that ist:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<login xmlns="http://soap.comet.werkii.com/">
<user>string</user>
<password>string</password>
<client>string</client>
<language>string</language>
</login>
</soap:Body>
</soap:Envelope>
When I use this code - as told by the service - from another test client (i wrote one in PHP), everything works fine an I get a result. But when I send the code from the beginning (which is what the real client will send), the method is called but all 4 arguments are null.
From an XML view, in my opinion both requests are the same. The only difference is, where the namespace is defined and if elements use the ns1 prefix. This should not make any difference, when the service reads it as XML. Maybe I'm wrong.
Perhaps the 4 arguments in the first XML have a different namespace (none) than the method (ns1). Can that be the reason why all arguments are null? How would I change the namespace for the arguments only?
When I change only the method lines in XML - replacing <ns1:login xsi:type="ns1:login"> with <login xmlns="http://soap.comet.werkii.com/"> and also the closing tag - it works! So the service seems not to understand my request, if the method element uses a namespace prefix, though the namespace is properly defined in the root element.
I tried the following to change the XML format which the service expects:
System.Web.Services.Protocols.SoapDocumentMethodAttribute - no effect at all
XmlNamespaceDeclarationsAttribute as shown here - which seems not to work because it is made for manipulating complex types, not the service class or a method
So the question is, how can I tell my service to accept the XML from the first example?
Good to know that parameters can also have Attributes:
public LoginResult Login (
[XmlElement(Namespace = "")] string user,
[XmlElement(Namespace = "")] string password,
[XmlElement(Namespace = "")] string client,
[XmlElement(Namespace = "")] string language)
{
return new LoginResult() {
ResultCode = 0,
SessionId = user + "-" + password + "-" + client + "-" + language
};
}
That's the solution to put the parameters into the global namespace – problem solved.

Soap request and response in c#

I wrote c# code for a Soap XML request, I have verified this code generating an XML class.
My question is how to send request and receive response using c# code.
Please be kind with my simple or basic mistakes because I am a newbie to XML but your help would be really appreciated.
SOAP XML Request:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ce="http://www." xmlns:os="http://www.domainname.com/schema/soap/v1" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<soapenv:Header />
<soapenv:Body>
<ce:message>
<ce:m_control>
<os:control_timestamp>2001-12-31T12:00:00</os:control_timestamp>
<os:message_id>000000000000000000000000000000000</os:message_id>
<os:message_type>Contract Enquiry Request</os:message_type>
<os:message_version>ce/v2.2/NameContractRequest</os:message_version>
<os:expected_response_type>synchronous</os:expected_response_type>
<os:initiator_id>initiator_id</os:initiator_id>
<os:initiator_orchestration_id>initiator_orchestration_id</os:initiator_orchestration_id>
<os:KeyInfo>
<ds:X509Data>
<ds:X509IssuerSerial>
<ds:X509IssuerName>CN=OSIS Customer CA, O=Origo Secure Internet Services Ltd., CN=OSIS Customer CA</ds:X509IssuerName>
<ds:X509SerialNumber>111111111111111111111111111111111111</ds:X509SerialNumber>
</ds:X509IssuerSerial>
<ds:X509SubjectName>C=GB, O=FirmID3400010000023NR11QQ, OU=CPS - www.unipass.co.uk/cps, OU=Warning/Terms of Use - www.unipass.co.uk/tou, OU=EmployeeID10101101010101, OU=TPSP2, OU=BPNR1 1QQ, CN=Testt Orgg/emailAddress=Fname.Lname#aviva.co.uk</ds:X509SubjectName>
</ds:X509Data>
</os:KeyInfo>
<os:responder_id>os:responder_id</os:responder_id>
</ce:m_control>
<ce:m_content>
<ce:b_control>
<ce:contract_enquiry_reference>TestRequest</ce:contract_enquiry_reference>
</ce:b_control>
<ce:intermediary>
<ce:FirmFSARef id="idvalue14">456123</ce:FirmFSARef>
</ce:intermediary>
<ce:request_scope>
<ce:contract_details_required_ind>No</ce:contract_details_required_ind>
<ce:valuation_currency>GBP</ce:valuation_currency>
<ce:fund_code_type_required>SEDOL</ce:fund_code_type_required>
<ce:valuation_request ce:type="Current" />
</ce:request_scope>
<ce:contract>
<ce:contract_reference_number>TL12345678</ce:contract_reference_number>
</ce:contract>
</ce:m_content>
</ce:message>
</soapenv:Body>
</soapenv:Envelope>
################################################ c# code ##################
Guid CEGuid = Guid.NewGuid();
string GuidString = CEGuid.ToString();
string CEVersion = "";
string URL = "";
string ResponderId = "";
string ContractDetailsRequired = "Yes";
using (XmlTextWriter xmlRequestWriter = new XmlTextWriter(#"C:/Unipass/PensionRequest.xml", Encoding.UTF8))
{
xmlRequestWriter.WriteStartDocument();
xmlRequestWriter.WriteComment("This file is generated by the program.");
xmlRequestWriter.WriteStartElement("soapenv:Envelope");
xmlRequestWriter.WriteAttributeString("xmlns:soapenv", null, "http://schemas.xmlsoap.org/soap/envelope/");
xmlRequestWriter.WriteAttributeString("xmlns:ce", null, "http://www.WhateveryDomain.com/schema/ce/v2.2/WhateverRequest");
xmlRequestWriter.WriteAttributeString("xmlns:os", null, "http://www.WhateveryDomain.com/schema/soap/v1");
xmlRequestWriter.WriteAttributeString("xmlns:ds", null, "http://www.w3.org/2000/09/xmldsig#");
xmlRequestWriter.WriteStartElement("soapenv:Header");
xmlRequestWriter.WriteEndElement();
xmlRequestWriter.WriteStartElement("ce:message");
xmlRequestWriter.WriteStartElement("ce:m_control");
xmlRequestWriter.WriteElementString("os:control_timestamp", DateTime.Now.ToString("s"));
xmlRequestWriter.WriteElementString("os:message_id", GuidString);
xmlRequestWriter.WriteElementString("os:message_type", "Contract Enquiry Request");
xmlRequestWriter.WriteElementString("os:message_version", "ce/v2.2/WhateverRequest");
xmlRequestWriter.WriteElementString("os:expected_response_type", "synchronous");
xmlRequestWriter.WriteElementString("os:initiator_id", "initiator_id");
xmlRequestWriter.WriteElementString("os:initiator_orchestration_id", "initiator_orchestration_id");
xmlRequestWriter.WriteStartElement("os:KeyInfo");
xmlRequestWriter.WriteStartElement("ds:X509Data");
xmlRequestWriter.WriteStartElement("ds:X509IssuerSerial");
xmlRequestWriter.WriteElementString("ds:X509IssuerName", "CN=OSIS Customer CA, O=Origo Secure Internet Services Ltd., CN=OSIS Customer CA");
xmlRequestWriter.WriteElementString("ds:X509SerialNumber", "111111111111111111111111111111111");
xmlRequestWriter.WriteEndElement();
xmlRequestWriter.WriteElementString("ds:X509SubjectName", "C=GB, O=FirmID3400010000023NR11QQ, OU=CPS - www.unipass.co.uk/cps, OU=Warning/Terms of Use - www.unipass.co.uk/tou, OU=EmployeeID01200012000003, OU=TPSP2, OU=BPNR1 1QQ, CN=Testt Orgg/emailAddress=fname.lastname#aviva.co.uk");
xmlRequestWriter.WriteEndElement();
xmlRequestWriter.WriteEndElement();
xmlRequestWriter.WriteElementString("os:responder_id", "os:responder_id");
xmlRequestWriter.WriteEndElement();
xmlRequestWriter.WriteStartElement("ce:m_content");
xmlRequestWriter.WriteStartElement("ce:b_control");
xmlRequestWriter.WriteElementString("ce:contract_enquiry_reference", "TestRequest");
xmlRequestWriter.WriteEndElement();
xmlRequestWriter.WriteStartElement("ce:intermediary");
xmlRequestWriter.WriteStartElement("ce:FirmFSARef");
xmlRequestWriter.WriteElementString("id", "456123");//="idvalue14">
xmlRequestWriter.WriteEndElement();
xmlRequestWriter.WriteEndElement();
xmlRequestWriter.WriteStartElement("ce:request_scope");
xmlRequestWriter.WriteElementString("ce:contract_details_required_ind", "Yes");
xmlRequestWriter.WriteElementString("ce:valuation_currency", "GBP");
xmlRequestWriter.WriteElementString("ce:fund_code_type_required", "SEDOL");
xmlRequestWriter.WriteStartElement("ce:valuation_request");
xmlRequestWriter.WriteElementString("ce:type", "Current");//"ce:type","Current"
xmlRequestWriter.WriteEndElement();
xmlRequestWriter.WriteEndElement();
xmlRequestWriter.WriteStartElement("ce:contract");
xmlRequestWriter.WriteElementString("ce:contract_reference_number", "PP12345678");
xmlRequestWriter.WriteEndElement();
xmlRequestWriter.WriteEndElement();
xmlRequestWriter.WriteEndElement();
xmlRequestWriter.WriteEndElement();
xmlRequestWriter.WriteEndDocument();
xmlRequestWriter.Flush();
Please could you tell me how to send Request and receive response from WCF service using above code.
Even though I have added wsdl reference but I don't know how to pass XmlElement[] in the line below.
serviceReference.getDetail(ref XmlElement[] Any);
Here is a method in Reference class.
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(Namespace="http://www.domainname.com/whatever/webname/schema/ce/v2.2/NameContractServic" +
"e", ConfigurationName="TestingPension.NameContractServiceDetailType")]
public interface NameContractServiceDetailType {
// CODEGEN: Generating message contract since the wrapper namespace (http://www.domainname.com/schema/ce/v2.2/NameContractRequest) of message getDetailRequest does not match the default value (http://www.domainname.com/name/name/schema/ce/v2.2/NameContractService)
[System.ServiceModel.OperationContractAttribute(Action="http://www.origostandards.com/schema/ce/v2.2/CEPensionSingleContract#getDetail", ReplyAction="*")]
[System.ServiceModel.FaultContractAttribute(typeof(SoapReqResWebApplication.TestingPension.Error[]), Action="http://www.domainname.com/schema/ce/v2.2/NameContract#getDetail", Name="errors", Namespace="http://www.domainname.com/schema/tech/v1.0/SOAPFaultDetail")]
[System.ServiceModel.XmlSerializerFormatAttribute(SupportFaults=true)]
SoapReqResWebApplication.TestingPension.getDetailResponse getDetail(SoapReqResWebApplication.TestingPension.getDetailRequest request);
}
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
[System.ServiceModel.MessageContractAttribute(WrapperName="message", WrapperNamespace="http://www.domainname.com/schema/ce/v2.2/NameContractRequest", IsWrapped=true)]
public partial class getDetailRequest {
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="", Order=0)]
[System.Xml.Serialization.XmlAnyElementAttribute()]
public System.Xml.XmlElement[] Any;
public getDetailRequest() {
}
public getDetailRequest(System.Xml.XmlElement[] Any) {
this.Any = Any;
}
}
#CodeCaster
I tried your code as:
var documentToSend = new XmlDocument();
//// TODO: add all elements you like
using (XmlTextWriter xmlRequestWriter = new XmlTextWriter(#"C:/Unipass/Request.xml", Encoding.UTF8))
{
xmlRequestWriter.WriteStartDocument();
xmlRequestWriter.WriteStartElement("ce:message");
xmlRequestWriter.WriteEndElement();
xmlRequestWriter.WriteEndDocument();
xmlRequestWriter.Flush();
documentToSend.Save(xmlRequestWriter);
//// Create an array with the root message node as only element.
var xmlToSend = new XmlElement[] { documentToSend.DocumentElement }; //xmlToSend = null
}
Might be I am doing completely wrong, please can you tell me why xmlToSend is null.
It seems that you are writing code by hand to serialise messages into SOAP/XML. The SOAP request example is an actual instance document rather than WSDL, yes? This is one of the things that WCF does for you - you should not need to generate your own SOAP messages.
In WCF, you focus on the object types you want to transmit and the operations you want to support. Then WCF does all the heavy lifting of SOAP serialisation for you. That is the main point of WCF really.
It's quite hard to decipher from your sample SOAP message what exactly you are trying to do, so I would recommend looking at one of the simple WCF samples, say from here
http://msdn.microsoft.com/en-us/library/vstudio/ms751514(v=vs.90).aspx
Get a simple one up and running using wsHttpBinding or basicHttpBinding (these are SOAP bindings in WCF). Then capture the HTTP request using Fiddler or similar and see what WCF has done for you in terms of the SOAP envelope generation.
You should then be able to translate that to your own case.
It seems like WCF's proxy generator cannot create a class from the provided WSDL/XSD, given the generated method signature is getDetailRequest(System.Xml.XmlElement[] Any). What does a tool like SoapUI say about the WSDL?
A way to solve this is to indeed manually generate the message, which is just the <ce:message>..</ce:message> block. WCF will wrap it in a proper SOAP envelope when you call the service method.
You'll have to play around a bit with the XmlDocument class, but I think something like this will do it:
// Create an XmlDocument and fill it
var documentToSend = new XmlDocument();
// TODO: add all elements you like
// Create an array with the root message node as only element.
var xmlToSend = new XmlElement[] { documentToSend.DocumentElement };
// Call the service.
var response = serviceReference.getDetail(xmlToSend);
Another way would be to manually recreate the request class in C# and populate and serialize an instance of it to XML when sending a request. The ultimate way would be to fix the XML so Add Service Reference (SvcUtil) can generate classes from the service's metadata.
As for your edit, you're not writing the XML elements to the documentToSend, but you write them to your file.

Build USPS web service request

I want to build a web service request which accesses USPS's address web service.
I am facing a problem with building the request URL string in the format they want.
What i want to do is give the zip code in a variable so that it can be dynamic.
But USPS web service isn't accepting the URL string I am sending, guess I am making a mistake with the format.
The format which USPS expects is:
<CityStateLookupRequest USERID=”xxxxxxxx”>
<ZipCode ID="0">
<Zip5>90210</Zip5>
</ZipCode>
<ZipCode ID="1">
<Zip5>20770</Zip5>
</ZipCode>
</CityStateLookupRequest>
https://servername/ShippingAPI.dll?API=CityStateLookup&XML=<CityStateLookupRe
quest USERID="username">.......</CityStateLookupRequest>
This is how I am trying to build the URL:
WebRequest USPSReq = String.Format("http://production.shippingapis.com/ShippingAPI.dll?API=CityStateLookup&XML=CityStateLookupRequest&USERID=xxxxxxxx&ZipCode ID=0&Zip5=" + oZip);
How can I build this request URL?
Simply build that XML using your favorite XML API. For instance:
XDocument requestXml = new XDocument(
new XElement("CityStateLookupRequest",
new XAttribute("USERID", userID),
new XElement("ZipCode",
new XAttribute("ID", "0"),
new XElement("ZIP5", zip5)));
var requestUrl = new UriBuilder("http://production.shippingapis.com/ShippingAPITest.dll");
requestUrl.Query = "API=CityStateLookup&XML=" + requestXml.ToString();
var request = WebRequest.Create(requestUrl.Uri);

Pull SecurityToken from SAML Assertion

I have the XML of a SAML Assertion that looks like this:
<saml:Assertion MajorVersion="1" MinorVersion="1" AssertionID="_9b6e6302-d6a8-47f0-9155-1051a05edbfb" Issuer="http://example.com/adfs/services/trust" IssueInstant="2013-04-29T19:35:51.197Z" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion">
...
</saml:Assertion>
I am trying to get a SecurityToken out of this XML using code similar to the following:
// Loading the XML referenced above.
XDocument doc = XDocument.Load(new StringReader(assertion));
// Creating config to use in TokenHandlers below; required if not using a SecurityTokenHandlerCollection.
SecurityTokenHandlerConfiguration config = new SecurityTokenHandlerConfiguration();
config.AudienceRestriction.AllowedAudienceUris.Add(new Uri("https://localhost/Orchard/"));
config.CertificateValidator = X509CertificateValidator.None;
// Both of these lines throw Exceptions, as explained below.
new Saml11SecurityTokenHandler() { Configuration = config }.ReadToken(doc.CreateReader());
new Saml2SecurityTokenHandler() { Configuration = config }.ReadToken(doc.CreateReader());
If I try to read the token using the Saml11SecurityTokenHandler, I get the following Exception:
ID4075: SAML Assertion is missing the required 'MajorVersion' Attribute.
If I try to read the token using the Saml2SecurityTokenHandler, I get a different Exception:
Element 'Assertion' with namespace name 'urn:oasis:names:tc:SAML:2.0:assertion' was not found.
Obviously the one for Saml2SecurityTokenHandler makes sense, since this is a SAML 1.1 Assertion. However, why can't the SAML 1.1 TokenHandler read this Assertion?
EDIT: The reader appears to be empty; why is that? doc has content.
string notEmpty = doc.FirstNode.ToString();
string empty = doc.CreateReader().ReadOuterXml();
Drawing from the technique shown here, this works:
SecurityToken token;
using (StringReader sr = new StringReader(assertion))
{
using (XmlReader reader = XmlReader.Create(sr))
{
if (!reader.ReadToFollowing("saml:Assertion"))
{
throw new Exception("Assertion not found!");
}
SecurityTokenHandlerCollection collection = SecurityTokenHandlerCollection.CreateDefaultSecurityTokenHandlerCollection();
token = collection.ReadToken(reader.ReadSubtree());
}
}
Make sure you don't change of the whitespace in the XML document, otherwise you'll get a signature verification error.

Categories

Resources