2012年3月19日

[.Net] Generic SOAP Proxy

A soap generic proxy I wrote about 6 years ago. The proxy parses web service definition and provides the ability to invoke remote web services without generating proxy classes. The most important part of this generic proxy is how we parse WSDL and create a HTTP POST to that service.

To retrieve WSDL

public void ConnectWebService()
{
System.Net.WebRequest.DefaultWebProxy = iWebProxy;
AcceptAllCertificates();
const string XPATH_TO_WEB_METHOD_INFORMATION_NODE = "//*/types/schema/element";// "/types/schema/element[@name=\"{0}\"]/*";
const string XPATH_TO_WEB_METHOD_PARAMETERS = "sequence/element";
string resp = GetWSDL(WebServiceUrl + "?wsdl");

if (OnWSDLRetrieved != null)
OnWSDLRetrieved(this, new SoapProxyWSDLEventArgs(resp));

wsdlDoc.LoadXml(resp);
targetNamespace = wsdlDoc.DocumentElement.Attributes.GetNamedItem("targetNamespace").Value;
List<string> references = new List<string>();
if (OnSoapActionRetrieved != null)
{
foreach (System.Xml.XmlNode node in wsdlDoc.SelectNodes(XPATH_TO_WEB_METHOD_INFORMATION_NODE))
{
string action = node.Attributes.GetNamedItem("name").Value;
string paramType = string.Empty;
string paramName = string.Empty;
SoapProxySoapActionEventArgs e = new SoapProxySoapActionEventArgs(action);

if (node.SelectSingleNode("complexType").ChildNodes.Count > 0)
{
//this method has parameters
foreach (System.Xml.XmlNode paramElement in node.SelectNodes("complexType/sequence/element"))
{

if (paramElement.Attributes.GetNamedItem("ref") == null)
{
paramName = paramElement.Attributes.GetNamedItem("name").Value;
paramType = (paramElement.Attributes.GetNamedItem("type") == null ? "object" :
paramElement.Attributes.GetNamedItem("type").Value);
}
else
{
System.Xml.XmlNode refNode = wsdlDoc.SelectSingleNode("//*/types/schema/element[@name=\"" +

paramElement.Attributes.GetNamedItem("ref").Value + "\"]");
paramName = refNode.Attributes.GetNamedItem("name").Value;
paramType = (refNode.Attributes.GetNamedItem("type") == null ? "object" :
paramElement.Attributes.GetNamedItem("type").Value);
references.Add(paramName);
}
}
}
if (!references.Contains(action))
OnSoapActionRetrieved(this, e);
}
}
}






 



To invoke web method




public string InvokeWebMethod(string methodName, params object[] parameters)
{
try
{
WebRequest.DefaultWebProxy = iWebProxy;

byte[] requestData = CreateHttpRequestData(methodName, parameters);
string uri = WebServiceUrl + "?op=" + methodName;
HttpWebRequest httpRequest = (HttpWebRequest)HttpWebRequest.Create(uri);
httpRequest.Method = "POST";
httpRequest.KeepAlive = false;
httpRequest.ContentType = contentType;// "text/xml; charset=utf-8";// "application/x-www-form-urlencoded";
httpRequest.ContentLength = requestData.Length;

string action = (targetNamespace.EndsWith("/") ? targetNamespace + methodName : targetNamespace + "/" + methodName);
httpRequest.Headers.Add("SOAPAction", "\"" + GetSOAPAction(methodName) + "\"");

//httpRequest.Expect = "100-continue";
httpRequest.Timeout = TimeOut;
HttpWebResponse httpResponse = null;
string response = string.Empty;
try
{
httpRequest.GetRequestStream().Write(requestData, 0, requestData.Length);
httpRequest.GetRequestStream().Flush();
if (httpRequest.HaveResponse || TimeOut > 0)
{
httpResponse = (HttpWebResponse)httpRequest.GetResponse();
System.IO.Stream baseStream = httpResponse.GetResponseStream();
System.IO.StreamReader responseStreamReader = new System.IO.StreamReader(baseStream);
response = responseStreamReader.ReadToEnd();
responseStreamReader.Close();
System.Diagnostics.Debug.WriteLine("[WebService-Resp]HTTP State:" + httpResponse.StatusCode.ToString());
}
else
{
response = "Response not available(" + GetSOAPAction(methodName) + ")";
}
}
catch (WebException e)
{
const string CONST_ERROR_FORMAT = "<?xml version=\"1.0\" encoding=\"utf-8\"?><Exception><{0}Error>{1}” +

“<InnerException>{2}</InnerException></{0}Error></Exception>";
response = string.Format(CONST_ERROR_FORMAT, methodName, e.ToString(), (e.InnerException != null ?

e.InnerException.ToString() : string.Empty));
}
return response;
}
catch (Exception exp)
{
WriteLog("Exception while InvokeWebMethod:" + exp.Message);
WriteLog(" ->" + exp.StackTrace);
if (exp.InnerException != null)
{
WriteLog("InnerException:" + exp.InnerException.Message);
WriteLog(" ->" + exp.InnerException.StackTrace);
}
throw exp;
}
}




Create HTTP POST Data



private byte[] CreateHttpRequestData(string methodName, params object[] parameters)
{
System.Xml.XmlNode node = wsdlDoc.SelectSingleNode("//*/types/schema/element[@name=\"" + methodName + "\"]");
string text = GetSOAPRequestTemplate(soapVersion);
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
doc.LoadXml(text);
System.Xml.XmlNode soapBody = doc.DocumentElement.ChildNodes[0];
string ns = targetNamespace;

System.Xml.XmlNode methodNode = doc.CreateNode(System.Xml.XmlNodeType.Element, methodName, "");
System.Xml.XmlAttribute attr = doc.CreateAttribute("xmlns");
attr.Value = ns;
methodNode.Attributes.Append(attr);
int i = 0;
foreach (System.Xml.XmlNode paramElement in node.SelectNodes("complexType/sequence/element"))
{
string paramName = "", paramType = "";
if (paramElement.Attributes.GetNamedItem("ref") == null)
{
paramName = paramElement.Attributes.GetNamedItem("name").Value;
paramType = (paramElement.Attributes.GetNamedItem("type") == null ? "object" :
paramElement.Attributes.GetNamedItem("type").Value);

System.Xml.XmlNode paramNode = doc.CreateNode(System.Xml.XmlNodeType.Element, paramElement.Attributes.GetNamedItem("name").Value, "");
paramNode.InnerXml = (string)parameters[i++];// System.Web.HttpUtility.HtmlEncode((string)parameters[i++]);// "<![CDATA[" + (string)parameters[i++] + "]]>";
methodNode.AppendChild(paramNode);
}
else
{
WriteLog("paramElement=" + paramElement.OuterXml);
WriteLog("ref=" + paramElement.Attributes.GetNamedItem("ref").Value);
string refName = paramElement.Attributes.GetNamedItem("ref").Value.IndexOf(":") > 0 ? paramElement.Attributes.GetNamedItem("ref").Value.Split(':')[1] : paramElement.Attributes.GetNamedItem("ref").Value;
WriteLog("XPath=" + "//*/types/schema/element[@name=\"" + paramElement.Attributes.GetNamedItem("ref").Value + "\"]");
WriteLog("XPath=" + "//*/types/schema/element[@name=\"" + refName + "\"]");

//System.Xml.XmlNode refNode = wsdlDoc.SelectSingleNode("//*/types/schema/element[@name=\"" + paramElement.Attributes.GetNamedItem("ref").Value + "\"]");
System.Xml.XmlNode refNode = wsdlDoc.SelectSingleNode("//*/types/schema/element[@name=\"" + refName + "\"]");

WriteLog("refNode=" + refNode.OuterXml);
paramName = refNode.Attributes.GetNamedItem("name").Value;
WriteLog("paramName=" + paramName);
paramType = (refNode.Attributes.GetNamedItem("type") == null ? "object" :
paramElement.Attributes.GetNamedItem("type").Value);

System.Xml.XmlNode paramNode = doc.CreateNode(System.Xml.XmlNodeType.Element, paramName, "");
paramNode.InnerXml = (string)parameters[i++];//System.Web.HttpUtility.HtmlEncode((string)parameters[i++]);// "<![CDATA[" + (string)parameters[i++] + "]]>";
methodNode.AppendChild(paramNode);
}
}
text = text.Replace("<GENERATED_XML_DATA/>",methodNode.OuterXml);//"<![CDATA![" + methodNode.OuterXml + "]]>");
//doc.LoadXml(text);
//soapBody.AppendChild(methodNode);
{
//doc.Save(@"C:\content.xml");
}
if (wsdlDoc.FirstChild is System.Xml.XmlDeclaration)
{
return System.Text.Encoding.GetEncoding(((System.Xml.XmlDeclaration)wsdlDoc.FirstChild).Encoding).GetBytes(text);
}
return System.Text.Encoding.Unicode.GetBytes(text);//doc.OuterXml);
}





 


And a template for SOAP 1.1 & 1.2 messages




<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>
<GENERATED_XML_DATA/>
</soap:Body>
</soap:Envelope>







<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd=http://www.w3.org/2001/XMLSchema

xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
<soap12:Body>
<GENERATED_XML_DATA/>
</soap12:Body>
</soap12:Envelope>




沒有留言:

About Me