Friday, March 19, 2010

Consuming XML-RPC web services with C# - Part 1 - the rough way


While dealing with integration of Bugzilla as data provider within BugtraqPlugin (which I described here) I encountered that bugzilla has an XML-RPC interface. Not this bad, but

How to perform XML-RPC calls with c# and .NET?

It's a simple task to get access on soap web services because it provides a description of it's own interface through a wsdl definition, so you easily can generate proxy classes for such a case.

But whats about XML-RPC web services? Here is just a sample practiced on bugzilla web service.
First, we take a look at the XML-RPC architecture:



Data or even method call parameters are serialized to and passed over http(s) to be perform some action on the remote machine. Result goes vice versa.

To call a remote procedure through xml you have to specify the methodname and the parameters of the methodcall in XML and send this via POST to the web service that handles this request.

The minimal version to call a remote procedure via XML-RCP is the following XML snippet:

<?xml version="1.0"?>
<methodCall>
 <methodName>[METHODNAME]</methodName>
 <params>
  <param>
   <value>
    <[PARAMETERTYPE]>[PARAMETERVALUE]</[PARAMETERTYPE]>
   </value>
  </param>
 </params>
</methodCall>

For example, to call the version method without any parameters on bugzilla webservice the XML looks like this:

<?xml version="1.0"?>
<methodCall>
 <methodName>Bugzilla.version</methodName>
</methodCall>

Granted, this is a very simple excample, but it simple shows the needs. A good resource on XML-RPC is XMLRPC.com. Take a look there to go further.

Now you have to pass this to the webservice to get the result back. The simplest way to achieve this is to send the data on a POST request to the server and retrieve the result of the call.

Let's go:
byte[] requestData = Encoding.ASCII.GetBytes("<?xml version=\"1.0\"?><methodCall><methodName>Bugzilla.version</methodName></methodCall>");
 
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://bugzilla.mozilla.org/xmlrpc.cgi");
request.Method = "POST";
request.UserAgent = "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729;)";
request.ContentType = "text/xml";
request.ContentLength = requestData.Length;
 
using (Stream requestStream = request.GetRequestStream())
   requestStream.Write(requestData, 0, requestData.Length);
 
string result = null;
 
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
   using (Stream stream = response.GetResponseStream())
   {
      using (StreamReader reader = new StreamReader(stream, Encoding.ASCII))
         result = reader.ReadToEnd();
   }
}

Done, thats all. Now you have to handle the result data:
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
 <params>
  <param>
   <value>
    <struct>
     <member>
      <name>version</name>
      <value>
       <string>3.4.5</string>
      </value>
     </member>
    </struct>
   </value>
  </param>
 </params>
</methodResponse>

Read ahead with Part 2 of the series.

UPDATE 2013-08-29:
Sample codes of this part are now available at github.

8 comments:

  1. Did you look at BugzProxy? I don't know if it's maintained anymore, but it was a Bugzilla XML-RPC interface written for .NET.

    -Max

    ReplyDelete
  2. Yes I did, but it doesn't fit my needs.

    Currently, I'm using my own proxy implementation to access bugzilla web service with usage of http://www.xml-rpc.net/ library.

    ReplyDelete
  3. Thank you Torsten. Excellent aticle. I was looking for the same one

    ReplyDelete
  4. hello TORSTEN BÄR,

    How to access individual argument i.e method name, parameter list individually

    ReplyDelete
    Replies
    1. I'm not sure what are you looking for, but have you already read Part 2 and Part 3?

      Delete
  5. your part 2 is not available, or maybe is it just me that couldn't access it?

    ReplyDelete
    Replies
    1. Wrong link. Sorry for that. Link is fixed now.

      Delete
  6. Do I need to run that code? Do I need any special programs? thank you very much

    ReplyDelete