We have a new accounting system that provides webservice interface to external clients. I want to access one of the interfaces but there's no WSDL so i created the request through the use of HttpWebRequest and it works fine.
However to ease the creation of the requests and parsing of the response i would like to create some kind of automapping function. I have the request and response structure in an XSD file. Any ideas?
Request creation:
public void SendRequest()
{
HttpWebRequest request = CreateWebRequest();
XmlDocument soapEnvelopeXml = new XmlDocument();
soapEnvelopeXml.LoadXml(#"<?xml version=""1.0"" encoding=""utf-8""?>
<soap:Envelope xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">
<soap:Body xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
++ structure type inserted here ++
</soap:Body>
</soap:Envelope>");
using (Stream stream = request.GetRequestStream())
{
soapEnvelopeXml.Save(stream);
}
using (WebResponse response = request.GetResponse())
{
using (StreamReader rd = new StreamReader(response.GetResponseStream()))
{
string soapResult = rd.ReadToEnd();
Console.WriteLine(soapResult);
}
}
}
Well, if you really have no way of getting hold of a proper WSDL file but have XSD:s you could probably use the xsd.exe tool to create classes that map to your request and response types.
Something like this (run this in a Visual Studio Command Prompt)
xsd.exe TheRequest.xsd /c /n:Your.Namespace
xsd.exe TheResponse.xsd /c /n:Your.Namespace
But really, try your best to find that WSDL, it will make your life a lot easier..
I recommend that you Create a WSDL - reverse engineer it, and then produce your webservices client stubs from it.
The way to do it:
Get a wire trace of the exact request and response the webservice uses. Use Fiddler or something similar.
Build a WCF service, that approximates the request and response.
Get the trace of that
Compare (3) to (1). Remember you want XML infoset equivalence. Your namespace prefixes need not be the same, for example. Your namespaces need not be declared in the same location. But, the element names need to be exactly the same, and the xmlns strings need to be exactly the same. Modify the WCF service to more closely match the original. Restart it, go to step 3. Iterate as many times as it takes.
point your WCF client to the real web service
sit back and relax.
I've done this and it works. It can be tricky if you don't have insight into how DataContract attributes affect the XML on the wire. But as you play with it, you will gain the insight pretty quickly.
But how is it possible that it is a SOAP service and there is no WSDL on the service side? It might save you a ton of work to re-double your efforts to locate the real WSDL.
Related
I have an issue parsing through some XML in C#.
My XML is this:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<GetArticleByIDResponse xmlns="namespace_1">
<GetArticleByIDResult xmlns:a="namespace_a" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:ArticleHeader>Header text here</a:ArticleHeader>
<a:Content>Content here</a:Content>
</GetArticleByIDResult>
</GetArticleByIDResponse>
</s:Body>
</s:Envelope>
How Can I get the content and article header from that XML when parsed as in as a string. I have tried so many examples, and failed all of them.
It doesnt matter if its linq or XmlDocument. Just need a scenario, where I can grab the content and actually use it.
Using LINQ-to-XML :
XNamespace a = "namespace_a";
XDocument doc = XDocument.Parse("your xml string here");
var header = (string)doc.Root.Descendants(a + "ArticleHeader").FirstOrDefault();
var content = (string)doc.Root.Descendants(a + "Content").FirstOrDefault();
Adding to my comment the .Net Soap System is bugged or just flaming wrong as it does not support using xmlns as a namcespace for some stupid reason i have spent many hours with this problem from a php client to a .Net Server to correct try this.
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
<Body xmlns="http://schemas.xmlsoap.org/soap/envelope/">
<GetArticleByIDResponse xmlns="namespace_1">
<GetArticleByIDResult>
<ArticleHeader xmlns="namespace_a">Header text here</ArticleHeader>
<Content xmlns="namespace_a">Content here</Content>
</GetArticleByIDResult>
</GetArticleByIDResponse>
</Body>
</Envelope>
i think that should work for if you should be using php to send to soap i have a fix on a feature/bug request with php https://bugs.php.net/bug.php?id=64704&edit=3 that will correct the problem with php if your using another soap client request builder you will need to see if you can tell it to use in-line namespacing insted of named/taged namespacing (i think thats what they call it but i cant be certain)
Preface: I've been trying to do XML signature verification on an HTTP response, and I need help! All code is .NET 4.0 using C#.
So here's what I'm trying to accomplish:
Create a signed XML document on the server
Send the signed XML as body of an HTTP response
Client receives the response and verifies that the signature is valid.
Server-side, I create the XML and load it into an XmlDocument. I then sign this XmlDocument object (using this example code from MSDN) and build a string from this signed XML. This string is what I send as the HTTP response body.
When my client application receives the response, it pulls the body of the response out and passes it to my signature verification function. This function builds an XmlDocument from the string, creates a SignedXml object from the XmlDocument, and retrieves the Signature to verify. Almost all this code is taken from MSDN as well (here).
Seems straightforward, right? Well my verification fails every time. I know that it's not a problem with the signing/verifying code. I've tested it in a separate app where the XML it loads is from a file, and it works perfectly. I'm even using the exact same XML to test my client/server code.
Thus, I believe the problem lies in the step where XmlDocument is converted to a string or the string is converted back to XmlDocument.
XmlDocument -> string -> XmlDocument
I've done the following things to try to make it easier to the signature to verify:
Remove all tabs, newlines, carriage returns from the XML before I create the XmlDocument.
Ensured that the encoding of the document is explicitly set at UTF-8 (i know from previous threads that this can cause an issue if not set).
Tried generating the strings in two different ways (from OuterXML of the XmlDocument & also by using XmlWriter and StringWriter).
Visually verified that the XML sent from the server is the exact same as that loaded by the client.
If you have any idea on how to remedy this problem, please help! I can post code if desired, but the only code that might be worth seeing is how I generate the string from the XmlDocument.
An old question but I figured I would would answer it for anyone else who might have encountered a similar issue. The problem was in the encoding of the string as it was sent back via the HTTP response. However, I remedied this by writing the XmlDocument directly to the response stream instead of converting it to a string first. Like such:
public void ProcessRequest(HttpContext context)
{
// a bunch of request handling logic
//...
HttpResponse response = context.Response;
XmlDocument signedXML = getTheSignedXMLData(); //the XML
signedXML.PreserveWhitespace = true;
signedXML.Save(response.Output);
}
This solved by encoding issues and the signature verifies correctly.
How can i get soap messages posted on IP say 12.23.421.12:3759
is there any way that soap messages on this IP can be read and data can be parsed from XML.
this is the log from WIRESHARK tool, i need to parse this
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:SOAP-ENC="http://schemas.xmlso ap.org/soap/encoding/"
xmlns:xsi ="http://www.w3.org/2001/XMLSche ma-instance"
xmlns:xsd="http://w ww.w3.org/2001/XMLSchema">
<SOAP-ENV:Body>
<huawei:setSubscriberDetails xmlns:huawei="http://business.add.gsm.rcom.com">
<paramSubscriberDetails>
<IMEI>355030005026 8312</IMEI>
<IMSI >405828210239016</IMSI>
<prepaid>true</prepaid>
<MSISDN>919646845889</MSISDN>
</paramSubscriberDetails>
</huawei:setSubscriberDetails>
</SOAP-ENV:Body>
Try to add an Service Reference to your project. This creates a class and some methods that you can use to call the soap service.
If you receive just the Soap message load it in XDocument using the Load method.
because it is XML you can get your information by doing
var xDoc = XDocument.Load("http://yourserver.com/yourservice/1");
var body = xDoc.Element("SOAP-ENV:Body");
var huaweiSubscriberDetails = new HuaweiSubscriberDetails(){
Imei = body.Element("IMEI").Value,
Imsi = body.Element("IMSI").Value,
etc...
}
I just did this out of my head without Visual Studio so don't pin me down on it, if it contains errors.
I think you need TCP Listener install on your IP:Port
TcpListener MSDN
usually SOAP Response back to caller address (SOAP Request). You do not need a TcpListener if SOAP Request coming from you. It's my guess :)
Here's the proxy method that was created for the web service I'm trying to access. How would I go about modifying it to get the raw XML from the web service call?
/// <remarks/>
[System.Web.Services.Protocols.SoapHeaderAttribute("CallOptionsValue")]
[System.Web.Services.Protocols.SoapHeaderAttribute("MruHeaderValue")]
[System.Web.Services.Protocols.SoapHeaderAttribute("SessionHeaderValue")]
[System.Web.Services.Protocols.SoapHeaderAttribute("QueryOptionsValue")]
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("", RequestNamespace = "urn:partner.soap.sforce.com", ResponseNamespace = "urn:partner.soap.sforce.com", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
[return: System.Xml.Serialization.XmlElementAttribute("result")]
public QueryResult query(string queryString)
{
object[] results = this.Invoke("query", new object[] {
queryString});
return ((QueryResult)(results[0]));
}
Thanks for your help!
Fortunately there is a nice way to do it, just modify the generated proxy class so it inherits from different base. The alternative implementation comes from Web Services Enhancements 3.0 pack:
Microsoft.Web.Services3.WebServicesClientProtocol
in the class you'll have RequestSoapContext.Envelope.InnerXml and ResponseSoapContext.Envelope.InnerXml in the scope - that's exactly what you need.
If you want just make a dump using the Fiddler Web Debugging tools.
If you want to really retrive/process raw XML then proxy method will not help you. Create System.Net.HttpWebRequest for the web service, call it, and retrive pure XML response. Format/structure can be found at .ASPX page or web service documentation.
Well, as far as I remember, a buddy of mine that this once with regular ASMX webservices, and it was quite a hack....
How about just serializing the result you get back into XML? That might do the trick...
Something along the lines of (totally untested and from memory):
MemoryStream stm = new MemoryStream();
XmlSerializer xmlSer = new XmlSerializer(typeof(QueryResult));
xmlSer.Serialize(stm, queryResult);
Would that work?
Marc
Is there a straightforward way to query a web service to see which messages it supports? The C# .NET application I'm working on needs to be able to handle an older version of the web service, which does not implement the message I'm trying to send. The web service does not expose a version number, so Plan B is to see if the message is defined.
I'm assuming I can just make an HTTP request for the WSDL and parse it, but before I go down that path, I want to make sure there's not a simpler approach.
Update:
I've decided to get the WSDL and get messages directly. Here's the rough draft for getting all the messages:
HttpWebRequest webRequest = (HttpWebRequest) WebRequest.Create( "http://your/web/service/here.asmx?WSDL" );
webRequest.PreAuthenticate = // details elided
webRequest.Credentials = // details elided
webRequest.Timeout = // details elided
HttpWebResponse webResponse = (HttpWebResponse) webRequest.GetResponse();
XPathDocument xpathDocument = new XPathDocument( webResponse.GetResponseStream() );
XPathNavigator xpathNavigator = xpathDocument.CreateNavigator();
XmlNamespaceManager xmlNamespaceManager = new XmlNamespaceManager( new NameTable() );
xmlNamespaceManager.AddNamespace( "wsdl", "http://schemas.xmlsoap.org/wsdl/" );
foreach( XPathNavigator node in xpathNavigator.Select( "//wsdl:message/#name", xmlNamespaceManager ) )
{
string messageName = node.Value;
}
Parsing the WSDL is probably the simplest way to do this. Using WCF, it's also possible to download the WSDL at runtime, essentially run svcutil on it through code, and end up with a dynamically generated proxy that you can check the structure of. See https://learn.microsoft.com/en-us/archive/blogs/vipulmodi/dynamic-programming-with-wcf for an example of a runtime-generated proxy.
I'm pretty sure WSDL is the way to do this.