Home   Cook Computing

XML-RPC.NET FAQ

Version 2-5-0 5th September 2010. © Charles Cook, 2002-2010.

Please send feedback, corrections, etc, to xmlrpcfaq@gmail.com.

Contents

1. Introduction

1.1 What is XML-RPC?
1.2 What is XML-RPC.NET?
1.3 Why use XML-RPC instead of SOAP?
1.4 Where do I obtain XML-RPC.NET from?
1.5 How do I install XML-RPC.NET?
1.6 Can I install XML-RPC.NET in the GAC?
1.7 How do I build with XML-RPC.NET?
1.8 How does XML-RPC.NET represent XML-RPC requests and responses?
1.9 How are XML-RPC simple types mapped onto .NET data types?
1.10 How are XML-RPC structs represented as .NET types?
1.11 What if the XML-RPC struct member name is not valid in .NET?
1.12 How are XML-RPC arrays represented as .NET types?
1.13 Is XML-RPC.NET CLS Compliant?
1.14 Why are my struct members ignored?
1.15 Can I specify struct members as optional?
1.16 How do I specify data whose type is not known until runtime?
1.17 With which versions of .NET is XML-RPC.NET compatible?

2. Clients

2.1 How do I implement an XML-RPC client?
2.2 What if the XML-RPC method name is not valid in my programming language?
2.3 Can I specify the server endpoint URL at runtime?
2.4 How do I set a timeout on a proxy method call?
2.5 How do I supply authentication credentials?
2.6 Can I specify custom HTTP headers?
2.7 How do I send cookies with a request?
2.8 How do I make an asynchronous XML-RPC request?
2.9 How do I poll for the result of an asynchronous call?
2.10 How do I receive a callback on completion of an asynchronous call?
2.11 What is the asyncState parameter used for?
2.12 How do I implement a client in VB.NET?
2.13 Why doesn't the following code cause an exception?
2.14 How do I implement a client in Managed C++?
2.15 How do I implement a client in JScript.NET?
2.16 Do proxies support the Introspection API?
2.17 Can I define a proxy method to return void?
2.18 How do I specify a proxy server when making an XML-RPC request?
2.19 Is a client proxy thread-safe?
2.20 How do I call an XML-RPC method with a variable number of parameters?
2.21 Can I configure the use of <int> instead of <i4>?
2.22 Does XML-RPC.NET accept non-standard XML-RPC responses?
2.23 Can I configure method names at runtime?
2.24 What is the Expect100Continue property used for?
2.25 What is the KeepAlive property used for?
2.26 Why does XML-RPC.NET throw XmlRpcIllFormedXmlException?
2.27 How can I stop a WebException being thrown?
2.28 Can a proxy interface contain overloaded methods?
2.29 How do I implement a client in Boo?
2.30 Can I configure the client to not use the <string> tag?
2.31 How do I configure client support for Accept-Encoding?
2.32 How do I prevent an empty params element in a request?
2.33 Can I retrieve the HTML response headers and cookies?
2.34 How do I call an XML-RPC method which requires named parameters in a struct?
2.35 Can I use the NonSerialized attribute on struct members?

3. Servers

3.1 What are the different ways in which an XML-RPC server can be implemented?
3.2 How do I implement an XML-RPC server in IIS?
3.3 How do I implement an XML-RPC server using .NET Remoting?
3.4 How do I implement an XML-RPC server in IIS using .NET Remoting?
3.5 Do XML-RPC.NET servers implement the XML-RPC Introspection API?
3.6 What is Automatic Documentation?
3.7 How do I support authentication in my XML-RPC service?
3.8 Can I implement a server which supports both XML-RPC and SOAP?
3.9 Can I run XML RPC.NET services with other web servers?
3.10 Can I implement services in other languages??
3.11 Can I implement a service in an ASHX file??
3.12 How do I implement an XML-RPC server using HttpListener??
3.13 Can I customise the XML returned by a service??

4. Error Handling

4.1 How are XML-RPC Fault Responses represented?
4.2 How are other types of error returned?
4.3 What happens if the return value of a proxy method is incorrect?

5. Debugging

5.1 How do I monitor XML-RPC calls across the network?
5.2 How do I debug an XML-RPC.NET service?

6. Miscellaneous

6.1 Which XML Encodings are Supported?
6.2 Which Code Access Security Permissions are Required?
6.3 Why is the key file not included in the distribution?
6.4 How do I verify an XML-RPC.NET assembly is genuine?
6.5 Can I define an interface from which both the proxy and server classes are derived?
6.6 How do I implement a client where reflection is not allowed?
6.7 Why does my client throw exception "Invoke on non-existent proxy method"?
6.8 Does XmlRpcClientProtocol.Invoke use params for the array of parameters?
6.9 How do I manually implement asynchronous requests?
6.10 Does XML-RPC.NET work with Mono?
6.11 Does XML-RPC.NET work with .Net Compact Framework?
6.12 How does the XML-RPC.NET license affect my product?
6.13 How do I build XML-RPC.NET?

7. Resources

7.1 XML-RPC Specification
7.2 Books
7.3 Websites
7.4 Mailing Lists
7.5 Articles and Tutorials
7.6 Sample Services

1. Introduction

1.1 What is XML-RPC?

To quote the XML-RPC.com site:

"It's a spec and a set of implementations that allow software running on disparate operating systems, running in different environments to make procedure calls over the Internet. It's remote procedure calling using HTTP as the transport and XML as the encoding. XML-RPC is designed to be as simple as possible, while allowing complex data structures to be transmitted, processed and returned.";

1.2 What is XML-RPC.NET?

XML-RPC.NET is a .NET class library for implementing XML-RPC clients and servers.

1.3 Why use XML-RPC instead of SOAP?

If your clients and servers are all running in the .NET environment there is no point in using XML-RPC: .NET provides excellent support for SOAP and XML-RPC doesn't have any features not provided by SOAP (other than simplicity).

If you use .NET clients and want to connect to XML-RPC servers running under any OS then XML-RPC.NET is a good choice.

If you want to implement a server in the .NET environment which is to be connected to by clients running in other environments, say Unix or Java, then XML-RPC may be an appropriate choice. SOAP is supported in many different environments but is considerably more complicated than XML-RPC and presents more opportunity for interop problems.

1.4 Where do I obtain XML-RPC.NET from?

XML-RPC.NET can be obtained from the XML-RPC.NET home page.

Updates are announced at Cook Computing and the Yahoo XMLRPCNET group.

1.5 How do I install XML-RPC.NET?

XML-RPC.NET is used as a single assembly which contains both client and server classes. When used by another program, installation is simply a matter of ensuring that the assembly is in the same directory as the program using it or referred to using the program's config file if in another directory. There is one build of the assembly: CookComputing.XmlRpcV2.dll which runs on .NET 2.0 onwards.

In the case of an XML-RPC web service running in IIS, the assembly is placed in the bin sub-directory of the virtual directory which is being used for the web service.

1.6 Can I install XML-RPC.NET in the GAC?

XML-RPC.NET is built with a strong name and so can be added to the Global Assembly Cache (GAC). To do this use the gacutil utility:

gacutil /i CookComputing.XmlRpcV2.dll

Alternatively the dll can be dragged and dropped into the winnt\assembly directory using Windows Explorer.

1.7 How do I build with XML-RPC.NET?

When compiling code which uses any of the classes in the XML-RPC.NET assembly, a reference to the assembly must be specified.

In Visual Studio .NET this is is achieved by using the References dialog which is invoked from the References item in the Solution Explorer. If compiling from the command line, the XmlRpc assembly is referenced like this:

csc /r:CookComputing.XmlRpcV2.dll myprogram.cs

1.8 How does XML-RPC.NET represent XML-RPC requests and responses?

XML-RPC.NET represents an XML-RPC endpoint as a .NET interface whose methods map onto the corresponding XML-RPC methods. For example:

using CookComputing.XmlRpc;

public struct SumAndDiffValue 
{
  public int sum; 
  public int difference; 
}

[XmlRpcUrl("http://www.cookcomputing.com/sumAndDiff.rem")] 
public interface ISumAndDiff
{ 
  [XmlRpcMethod] 
  SumAndDiffValue SumAndDifference(int x, int y);
} 

A server implementation implements these methods. A client implementation automatically generates a proxy class which derives from the interface.

1.9 How are XML-RPC simple types mapped onto .NET data types?

XML-RPC simple types are mapped to and from the following .NET types:

<i4> or <int> System.Int32 XML-RPC.NET by default outputs <i4>
<i8> System.Int64 Extension to XML-RPC.
<boolean> System.Boolean  
<string> System.String XML-RPC.NET always outputs the <string> element instead of just a <value> element with text content
<double> System.Double  
<dateTime.iso8601> System.DateTime  
<base64> System.Byte[]  

1.10 How are XML-RPC structs represented as .NET types?

An XML-RPC struct is a dictionary of name+member pairs and so is more flexible than a struct in C++ or C#. Depending on the particular XML-RPC method, the members of a struct are not necessarily fixed: a struct might contain a fixed set of members, a subset of a known set of members, or even an arbitrary set of members created at runtime.

For cases where the members of the struct are fixed, the XML-RPC struct can be mapped onto a .NET struct or class, for example:

<struct>
  <member>
    <name>code</name>
    <value><int>2</int></value>
  </member>
  <member>
    <name>description</name>
    <value><string>File missing.</string></value>
  </member>
</struct>

could map onto this C# struct:

struct errStruct
{ public int code; public string description; }

or this C# class:

class errClass
{ public int code; public string description; }

When mapping from an XML-RPC struct to a .NET struct or class, XML-RPC.NET ignores any members which are only in the XML-RPC struct, but throws an exception if a member is defined in the .NET type but is not in the XML-RPC struct (although it is possible to specify that members are optional, see question 1.15)

When mapping from a .NET struct or class to an XML-RPC struct, XML-RPC.NET simply maps every member of the .NET type to the XML-RPC struct (except where the NonSerializable attribute is used, see question 2.35).

In cases where the usage of the struct in the XML-RPC call is too flexible to be represented by a fixed data type, the XmlRpcStruct type can be used. This is a derivation of the .NET hashtable type and consists of name/member pairs representing the members of the XML-RPC struct. For example:

XmlRpcStruct bounds = new XmlRpcStruct();
bounds.Add("lowerBound", 18);
bounds.Add("upperBound", 139);
...
lowerBound = (int)bounds["lowerBound"];
upperBound = (int)bounds["upperBound"];

1.11 What if the XML-RPC struct member name is not valid in .NET?

In some cases the name of a member in an XML-RPC struct might be invalid in the .NET programming language being used. To handle this the XmlRpcMember attribute is available. This allows an XML-RPC member name to be mapped to and from a different .NET name. For example:

public struct SumAndDiffValue
{ 
  [XmlRpcMember("sample.sum")] 
  public int sum; 
  [XmlRpcMember("sample.difference")] 
  public int difference; 
}

1.12 How are XML-RPC arrays represented as .NET types?

Where possible XML-RPC.NET maps XML-RPC arrays onto arrays of .NET types. Where this is not possible, for example where the members of the XML-RPC array are not of the same type, the mapping is to an instance of System.Object[].

XML-RPC.NET does not support "jagged" arrays - arrays of arrays - because these are not CLS compliant.

1.13 Is XML-RPC.NET CLS Compliant?

XML-RPC.NET is fully Common Language Specification (CLS) compliant. This means that it can be used from any .NET language which is also CLS compliant, for example C#, VB.NET, or Managed Extensions for C++.

1.14 Why are my struct members ignored?

A common mistake with structs is to define them like this in C#:

public struct SumAndDiffValue
{ 
  int sum;
  int difference; 
}

or like this in VB.NET:

Public Structure SumAndDiffValue
  sum As Integer 
  difference As Integer 
End Structure

The mistake is that the members are not defined as public. This means the XML-RPC.NET library cannot recognize them without requiring extra security permissions associated with reflection. This might not be available in all circumstances, for example where the XML-RPC.NET assembly is downloaded by a client running in the Internet security zone, and so struct members are required to have public visibility. To take the C# case, the correct version of the struct would be:

public struct SumAndDiffValue
{ 
  public int sum;
  public int difference; 
}

1.15 Can I specify struct members as optional?

By default when XML-RPC.NET deserializes XML-RPC structs to .NET structs or classes it assumes that former will contain members for all the public members defined in the latter (deserialization occurs when the server processes a request and when the client processes a response). However, some APIs use structs which have optional members. For example a struct might always contain an "title" and "link" member but the "description" member might be optional. If the following struct is used as the return value of a method:

public struct SampleStruct
{
  public string title;
  public string link;
  public string description;
} 

And the response from the server does not contain a "description" member, an exception will be thrown when the client attempts to deserialize the struct. The solution is to attribute the member in the C# struct so that XML-RPC.NET knows that it is ok for the member to be missing:

public struct SampleStruct
{
  public string title;
  public string link;
  [XmlRpcMissingMapping(MappingAction.Ignore)]
  public string description;
} 

If there are many optional members in a struct, it is easier to apply MappingAction.Ignore to the whole struct and then mark the members which are not optional. For example:

[XmlRpcMissingMapping(MappingAction.Ignore)]
public struct SampleStruct
{
  [XmlRpcMissingMapping(MappingAction.Error)]
  public string title;
  [XmlRpcMissingMapping(MappingAction.Error)]
  public string link;
  public string description;
} 

If an XML-RPC struct member is optional and it is a reference type such as string, the .NET struct member will be set to null if the member is missing from the XML-RPC struct. Conversely if an optional .NET struct member is null, the corresponding member will not be output in the XML-RPC struct. In the case of a value type such as integer or bool, the .NET struct member will be set to the default value of the value type, e.g. zero for integer, if the member is missing from the XML-RPC struct. However when serializing a value type the XML-RPC struct member will always be set because there is no equivalent of the null value. The solution in this case is to use nullable value types.

Nullable Types

For the .NET 2.0 version of XML-RPC.NET onwards it is possible to use the nullable int?, bool?, double?, and DateTime? types, as well as nullable struct types, to represent optional struct members. When these are used, if an XML-RPC struct member is missing its corresponding .NET struct member will be set to null instead of the default value for the type if a non-nullable type had been used, for example null instead of zero for an integer. And going the other way, if the nullable .NET struct member is null, the resulting member will be omitted from the XML-RPC struct.

public struct FooStruct
{
  public int x;
}

[XmlRpcMissingMapping(MappingAction.Ignore)]
public struct SampleStruct
{
  public int? optionalIntMember;
  public bool? optionalBoolMember;
  public double? optionalDoubleMember;
  public DateTime? optionalDateTimeMember;
  public FooStruct? optionalStructMember;
} 

1.16 How do I specify data whose type is not known until runtime?

Sometimes the type of a parameter, return value, or struct member is not known until runtime. In this scenario the System.Object datatype should be used. For return values the actual type can be determined at runtime and handled appropriately.

1.17 With which versions of .NET is XML-RPC.NET compatible??

As of version 2.5.0 of XML-RPC.NET the distribution contains a single assembly named CookComputing.XmlRpcV2.dll which is built for .NET 2.0 and so can be used with this and later versions of .NET.

2. Clients

2.1 How do I implement an XML-RPC client?

To make calls to an XML-RPC server it is necessary to use an instance of a proxy class.

First devise an interface which represents the methods of XML-RPC server endpoint and derive it from IXmlRpcProxy. Mark each of the methods representing an XML-RPC method call with the XmlRpcMethod attribute. For example:

using CookComputing.XmlRpc;

public struct SumAndDiffValue 
{
  public int sum; 
  public int difference; 
}

[XmlRpcUrl("http://www.cookcomputing.com/sumAndDiff.rem")] 
public interface ISumAndDiff : IXmlRpcProxy
{ 
  [XmlRpcMethod] 
  SumAndDiffValue SumAndDifference(int x, int y);
} 

Note: IXmlRpcProxy was introduced in version 1.0 of XML-RPC.NET. Before then it was necessary to cast the proxy to XmlRpcClientProtocol and then set the required properties. Interfaces which don't derive from IXmlRpcProxy can still be used although casting will still be required.

Second, create an instance of a dynamically created proxy class:

ISumAndDiff proxy = XmlRpcProxyGen.Create<ISumAndDiff>();

Third, call a method on the interface:

SumAndDiffValue ret = proxy.SumAndDifference(2, 3);

Note: for version one of XML-RPC.NET the non-generic form of Create must be used:

ISumAndDiff proxy = (ISumAndDiff)XmlRpcProxyGen.Create(typeof(ISumAndDiff));

2.2 What if the XML-RPC method name is not valid in my programming language?

Sometimes the XML-RPC method name cannot be used as a method name in the proxy class. For example, it is common practice for XML-RPC method names to have the form namespace.methodname, such as sample.SumAndDifference In these cases a different constructor is used for the XmlRpcMethod attribute, taking a string which specifies the XML-RPC method name. For example:

[XmlRpcUrl("http://www.cookcomputing.com/sumAndDiff.rem")] 
public interface ISumAndDiff : IXmlRpcProxy
{ 
  [XmlRpcMethod("sample.sumAndDifference")]  
  SumAndDiffValue SumAndDifference(int x, int y);
} 

2.3 Can I specify the server endpoint URL at runtime?

Yes, proxy classes are derived from IXmlRpcProxy and so inherit a Url property. This means that the XmlRpcUrl attribute can be omitted from the definition of the proxy class and instead the Url property is then set on an instance of the proxy class:

ISumAndDiff proxy = (ISumAndDiff)XmlRpcProxyGen.Create(typeof(ISumAndDiff));
proxy.Url = "http://www.cookcomputing.com/SumAndDiff.rem";
SumAndDiffValue ret = proxy.SumAndDifference(2, 3);

The port connected to will default to 80 for a http Url and 443 for a https Url. To use a different port add ':' followed by the port number to the host name. For example:

proxy.Url = "http://www.cookcomputing.com:8080/SumAndDiff.rem";

2.4 How do I set a timeout on a proxy method call?

Proxy classes are derived from IXmlRpcProxy and so inherit a Timeout property. This takes an integer which specifies the timeout in milliseconds. For example, to set a 5 second timeout:

ISumAndDiff proxy = (ISumAndDiff)XmlRpcProxyGen.Create(typeof(ISumAndDiff));
proxy.Timeout = 5000;
SumAndDiffValue ret = proxy.SumAndDifference(2, 3);

2.5 How do I supply authentication credentials?

Proxy classes are derived from IXmlRpcProxy and so inherit a Credentials property. This is used where the XML-RPC server authenticates the caller. The property is used in exactly the same way as the same property of the System.Net.WebRequest class. For example:

ISumAndDiff proxy = (ISumAndDiff)XmlRpcProxyGen.Create(typeof(ISumAndDiff));
proxy.Credentials = new NetworkCredential("jsmith","password");
SumAndDiffValue ret = proxy.SumAndDifference(2, 3);

2.6 Can I specify custom HTTP headers?

Yes, proxy classes are derived from IXmlRpcProxy and so inherit a Headers property of type WebHeaderCollection. This can be used to specify custom headers which will be added to the HTTP request. For example:

ISumAndDiff proxy = (ISumAndDiff)XmlRpcProxyGen.Create(typeof(ISumAndDiff));
proxy.Headers.Add("TestHeader", "this_is_a_test");
SumAndDiffValue ret = proxy->SumAndDifference(2, 3);

2.7 How do I send cookies with a request?

Proxy classes are derived from IXmlRpcProxy and so inherit a CookieContainer property of type System.Net.CookieContainer, like the corresponding property of System.Net.HttpWebRequest. Instances of System.Net.Cookie added to the container will sent with the HTTP request. For example:

ISumAndDiff proxy = (ISumAndDiff)XmlRpcProxyGen.Create(typeof(ISumAndDiff));
Cookie cookie = new Cookie("foo", "bar", "/", "www.cookcomputing.com")
proxy.CookieContainer.Add(cookie);
SumAndDiffValue ret = proxy->SumAndDifference(2, 3);

2.8 How do I make an asynchronous XML-RPC request?

Although XML-RPC itself only supports synchronous method calls, XML-RPC.NET has support for asynchronous calls on proxy classes.

There are two ways of handling asynchronous calls: polling to determine when the call has completed, and using a delegate to receive a callback when the call has completed.These are discussed in the following answers.

The interface which represents the methods of XML-RPC server endpoint is extended with Begin and End methods for each XML-RPC method to be called asynchronously. Two attributes are used for this, the XmlRpcBeginAttribute, which is used to indicate which methods used to start async calls, and the XmlRpcEndAttribute, which is used to indicate methods which end async calls. For example:

using CookComputing.XmlRpc;

struct SumAndDiffValue 
{
  public int sum; 
  public int difference; 
}

[XmlRpcUrl("http://www.cookcomputing.com/sumAndDiff.rem")] 
public interface ISumAndDiff : IXmlRpcProxy
{ 
  [XmlRpcMethod] 
  SumAndDiffValue SumAndDifference(int x, int y);
  
  [XmlRpcBegin]
  IAsyncResult BeginSumAndDifference(int x, int y);

  [XmlRpcBegin]
  IAsyncResult BeginSumAndDifference(int x, int y, AsyncCallback acb);

  [XmlRpcBegin]
  IAsyncResult BeginSumAndDifference(int x, int y, AsyncCallback acb,
    object state);

  [XmlRpcEnd]
  SumAndDiffValue EndSumAndDifference(IAsyncResult iasr);
} 

The name of each Begin method is the name of the XML-RPC method name prefixed by "Begin": the XML-RPC.NET runtime code strips off the "Begin" to determine the name of the XML-RPC method to be called. In the case where the XML-RPC method name prefixed by "Begin" is not suitable, a different XmlRpcBeginAttribute constructor can be used to specify the XML-RPC method name. For example:

  [XmlRpcBegin("sample.sumAndDifference")] 
  IAsyncResult BeginSumAndDifference(int x, int y); 

The name of each End method is not used in the same way - all that matters is that the parameter is IAsyncResult and the return value represents the return value of the corresponding XML-RPC method. However it is worth following following the convention that the name is similar to the name of the corresponding Being method, with "End" replacing the "Being" prefix.

Where a callback is required when the method completes it is necessary to pass a callback delegate to the method.

[XmlRpcBegin] 
IAsyncResult BeginSumAndDifference(int x, int y, AsyncCallback acb); 

The AsyncCallback parameter must follow all the normal parameters to the method. Finally, where some state is required to be held during the async call, for example where the same callback delegate is being used to handle multiple calls and the target of the delegate has to distinguish between calls, another parameter can be specified to pass the state into the call. This is of type System.Object and must follow the AsyncCallback parameter, for example:

  [XmlRpcBegin] 
  IAsyncResult BeginSumAndDifference(int x, int y, AsyncCallback acb, 
    object state); 

If a proxy async method has been defined with the AsyncCallback parameter and/or the state parameter and they are not required in a call they can be passed as null.

2.9 How do I poll for the result of an asynchronous call?

When polling the last two parameters of BeginSumAndDifference are not required and can be passed as null. The asynchronous call would begin like this:

IAsyncResult asr;
asr = proxy.BeginSumAndDifference(5, 3, null, null);

An instance of the IAsyncResult is returned. This has several public properties, the interesting one for polling being the boolean property IsCompleted. The value of this property can be checked as required until is found to be true, for example:

while (asr.IsCompleted == false) 
{ 
  Thread.Sleep(1000); 
} 

Once the call has completed the result of the call can be obtained by calling EndSumAndDifference, passing in the instance of IAsyncResult returned from the call to BeginSumAndDifference:

try 
{ 
  Result ret = theProxy.EndSumAndDifference(asr); 
} 
catch(Exception ex) 
{ 
  // handle the exception 
} 

Note that a try-catch block is placed around the call to EndSumAndDifference. This is because any exceptions thrown during the asynchronous processing of the call, for example a network error or because the server returned a Fault Response, are stored until the XmlRpcClientProtocol method EndInvoke is called, at which point the the exception is rethrown.

2.10 How do I receive a callback on completion of an asynchronous call?

When a callback approach is used, a method must be defined and used with a delegate to take the callback:

void SumAndDiffCallback(IAsyncResult asr) 
{ 
  XmlRpcAsyncResult clientResult = (XmlRpcAsyncResult)asr;
  ISumAndDiff proxy = (ISumAndDiff)clientResult.ClientProtocol;
  try 
  { 
    Result ret = proxy.EndSumAndDifference(asr); 
  } 
  catch(Exception ex) 
  { 
    // handle the exception 
  } 
} 

This time when calling BeginSumAndDifference an AsyncCallback delegete must be created and passed into the call:

theProxy.BeginSumAndDifference(5, 3, SumAndDiffCallback, theProxy); 

The IAsyncResult returned from the call is ignored because all further handling of the call is done via the callback. When the call is completed, the callback method is called and, as its implementation suggests, the original SumAndDiffProxy used to make the call is retrieved from XmlRpcAsyncResult instance (cast to this from the IAsyncResult interface) interface so that the EndSumAndDifference method can be called to retrieve the result.

2.11 What is the asyncState parameter used for?

The fourth parameter to BeginInvoke and the proxy methods that call this method is an object which can optionally be used to hold some state during the lifetime of the asynchronous call. In many cases this will be unnecessary and can be passed as null.

2.12 How do I implement a client in VB.NET?

The client implemented in C# in section 2.1 can be implemented similarly in VB.NET:

Imports CookComputing.XmlRpc

Public Structure SumAndDiffValue
  Public sum As Integer
  Public difference As Integer
End Structure

<XmlRpcUrl("http://www.cookcomputing.com/sumAndDiff.rem")> _
Public Interface SumAndDiffItf 
  Inherits IXmlRpcProxy
  <XmlRpcMethod("sample.sumAndDifference")> _
  Function SumAndDifference(ByVal x As Integer, _
                            ByVal y As Integer) _
                            As SumAndDiffValue
End Interface

Module SumAndDiffVB
  Sub Main()
    Dim proxy As SumAndDiffItf
    proxy = CType(XmlRpcProxyGen.Create(GetType(SumAndDiffItf)), SumAndDiffItf)
    Dim ret As SumAndDiffValue
    ret = proxy.SumAndDifference(2, 3)
    Console.WriteLine("sum = {0}  diff = {1}", ret.sum, ret.difference)
    End Sub
End Module

Remember to add a reference to CookComputing.XmlRpcV2.dll to your project.

2.13 Why does the following VB code cause an exception?

When using arrays in VB the following mistake is easy to make and will cause an exception at runtime:

XmlRpcMethod("db.listCollections")_
Public Function listCollections(ByVal name As String) As String()
  Dim coll() As String = {}
  Dim param(1) As Object
  param(0) = New String(name)
  coll = Invoke("listCollections", param)
  Return coll
End Function

The line defining param actually defines an array with two elements, the first element being the required string, the second element being null. It should be correctly coded as:

Dim param(0) As Object

2.14 How do I implement a client in Managed C++?

TBD

2.15 How do I implement a client in JScript.NET?

TBD

2.16 Do proxies support the Introspection API?

Yes, support for the XML-RPC Introspection API is built into proxies. Any class derived from XmlRpcClientProtocol or just an instance of XmlRpcClientProtocol can be used to make Introspection requests.

Three public methods expose the three methods of the API:

SystemListMethods is used to call the system.listMethods method on the server. It simply returns an array of strings containing the XML-RPC names of the methods supported by this endpoint on the server.

string[] methods = proxy.ListMethods();

SystemMethodSignature is used to call the system.methodSignature method on the server. It returns an array of Object, each member of the array being an instance of an array of strings. This could have been represented more accurately as a jagged array - System.String[][] - but jagged arrays are not CLS compliant.

object[] signatures = proxy.SystemMethodSignature("sample.sumAndDifference"); 
foreach (string[] signature in signatures) 
  foreach (string param in signature)
Console.WriteLine(param);

Finally, SystemMethodHelp calls the system.methodHelp method on the server and returns a help string for the specified method.

string s = proxy.SystemMethodHelp("sample.sumAndDifference");

2.17 Can I define a proxy method to return void?

XML-RPC methods must always return a value. However there are some situations in which an XML-RPC method would have been defined to return void if this were possible and in these cases a dummy value may be returned, for example an empty string. The proxy method could be defined to return a corresponding type but it is perhaps more clear to specify the method as returning void, in which case the dummy return value is discarded. For example:

[XmlRpcMethod] 
void SumAndDifference(int x, int y);

2.18 How do I specify a proxy server when making an XML-RPC request?

Sometimes the XML-RPC client is behind a firewall and must send requests via a proxy server. There are two methods of achieving this with XML-RPC.NET.

The first method is to set the Proxy property of the proxy class. In a similar way to setting the Proxy property of an instance of class System.Net.WebRequest, the property is set to an instance of the IWebProxy interface, this usually being the interface on an instance of the System.Net.WebProxy class. For example:

ISumAndDiff proxy = (ISumAndDiff)XmlRpcProxyGen.Create(typeof(ISumAndDiff));
proxy.Proxy = new WebProxy("http://proxyserver:8000");    
SumAndDiffValue ret = proxy.SumAndDifference(2, 3); 

The second method is to set a global default proxy for all requests by using the System.Net.GlobalProxySelection class:

GlobalProxySelection.Select = "http://proxyserver:8000";

2.19 Is a client proxy thread-safe?

The thread safety of a proxy is essentially the same as that of the underlying System.Net.WebRequest object:

"Any public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe."

If you need to make concurrent calls, use a separate proxy for each call. Note that it is ok to make multiple calls to XmlRpcProxyGen.Create for the same type because the dynamically generated proxy class is cached and reused in following calls to Create.

2.20 How do I call an XML-RPC method with a variable number of parameters?

The params keyword can be used to call an XML-RPC method which take a variable number of parameters. For example, if an XML-RPC method takes a variable number number of integer parameters it could be defined like this:

[XmlRpcUrl("http://www.cookcomputing.com/notimpl.rem")] 
public interface IParams : IXmlRpcProxy
{ 
  [XmlRpcMethod] 
  int UseNumbers(params int[] numbers);
} 

And called like this:

IFoo proxy = (IFoo)XmlRpcProxyGen.Create(typeof(IFoo));
proxy.SendMultipleParameters(1);
proxy.SendMultipleParameters(1, 2, 3);

The resulting XML-RPC requests would look like this:


<methodCall>
  <methodName>SendMultipleParameters</methodName>
  <params>
    <param>
      <value>
        <i4>1</i4>
      </value>
    </param>
  </params>
</methodCall>


<methodCall>
  <methodName>SendMultipleParameters</methodName>
  <params>
    <param>
      <value>
        <i4>1</i4>
      </value>
    </param>
    <param>
      <value>
        <i4>2</i4>
      </value>
    </param>
    <param>
      <value>
        <i4>3</i4>
      </value>
    </param>
  </params>
</methodCall>

Alternatively the parameters in this example can be supplied as an array of type int[]:

int[] parameters = new int[] { 1, 2, 3 };
proxy.SendMultipleParameters(parameters);

Where the parameters are not of the same type it is necessary to define the params array as having type object[], for example:

[XmlRpcUrl("http://www.cookcomputing.com/notimpl.rem")] 
public interface IParams : IXmlRpcProxy
{ 
  [XmlRpcMethod] 
  int UseParameters(params object[] parameters);
} 

2.21 Can I configure the use of <int> instead of <i4>?

When XML-RPC.NET generates an XML-RPC request containing integer values, by default it uses the <i4> tag instead of the <int> tag for integers. Both tags are valid XML-RPC but some other XML-RPC server implementations do not support the <i4> form. If this is the case, the UseIntTag property of IXmlRpcProxy can be used to configure the use of <int>, for example:

ISumAndDiff proxy = (ISumAndDiff)XmlRpcProxyGen.Create(typeof(ISumAndDiff));
proxy.UseIntTag = true;

2.22 Does XML-RPC.NET accept non-standard XML-RPC responses?

Some XML-RPC server implementations return XML-RPC responses which do not comply with the XML-RPC specification. The XmlRpcClientProtocol class has a property called NonStandard which can be set to one of or a combination of the flags in the XmlRpcNonStandard enumeration:

[Flags]
public enum XmlRpcNonStandard
{
    None = 0x00,
    AllowStringFaultCode = 0x01,
    AllowNonStandardDateTime = 0x02,
    IgnoreDuplicateMembers = 0x4,
    MapZerosDateTimeToMinValue = 0x8,
    MapEmptyDateTimeToMinValue = 0x10,
    AllowInvalidHttpContent = 0x20;
    All = 0x7fff,
}
The flags have the following effect:

For example:

ISumAndDiff proxy = (ISumAndDiff)XmlRpcProxyGen.Create(typeof(ISumAndDiff));
proxy.NonStandard = XmlRpcNonStandard.AllowStringFaultCode
                    & XmlRpcNonStandard.IgnoreDuplicateMembers;

2.23 Can I configure method names at runtime?

The method name used when making an XML-RPC request is statically defined by the associated method's name in the interface or class used to create the proxy. However, there are some XML-RPC APIs which require the method name to be generated dynamically at runtime, for example to prefix the method name with a session id. In this infrequent situation the XmlRpcMethod property of IXmlRpcProxy can be used to override the statically defined method name before a request is made. In this example the method name sent in the XML-RPC request will be "Id1234_SumAndDifference" instead of the statically defined "SumAndDifference"

ISumAndDiff proxy = (ISumAndDiff)XmlRpcProxyGen.Create(typeof(ISumAndDiff));
proxy.XmlRpcMethod = "Id1234_SumAndDifference"
proxy.SumAndDifference(3, 4);

2.24 What is the Expect100Continue property used for?

If the Expect100Continue property on proxies is set to true, the header "Expect: 100-Continue" is set on each XML-RPC request. According to the HTTP 1.1 protocol, when this header is sent the server immediately responds with a response with the status "100 Continue". This allows the client to determine that the connection to the server has succeeded before it sends the body of the request. The client waits in the order of hundreds of milliseconds for the "100 Continue" response. The idea behind this is that POST requests may not be idempotent and a client cannot resend the data if error occurs after it has started sending the data in the body of the request. Ensuring that a response has been received before sending the data reduces the chance that the server receives only part of the data.

The Expect100Continue property defaults to false, i.e. the "Expect: 100-Continue" header is not sent. There have been several reports of XML-RPC servers which cannot handle this header and anyway it does not serve any real purpose in the context of XML-RPC. If the server receives only part of the request then it will fail to parse the XML-RPC request and will return an error. Futhermore use of the header results in each XML-RPC request taking hundreds of milliseconds longer than without the header.

2.25 What is the KeepAlive property used for?

The KeepAlive proxy property determines whether the connection to the server is kept open after the initial connection (assuming the server supports this). The default value is true, keeping the connection open, but in some cases it may be necessary to set it to false. An example of this is where the server sends spurious bytes after the end of the XML-RPC response which means that XML-RPC.NET reads these bytes as if they are at the beginning of the next response and so throws an exception whose message is "The server committed a protocol violation. Section=ResponseStatusLine".

2.26 Why does XML-RPC.NET throw XmlRpcIllFormedXmlException?

If your code makes a call on a proxy and an XmlRpcIllFormedXmlException is thrown with the message "Response from server does not contain valid XML." it means that the XML-RPC response from the server cannot be parsed as a valid XML document (parsing is performed by the .NET XmlDocument class). It is not a problem with the client. See section 5.1 on how to investigate what the server is sending across the network.

Section 2.22 describes the AllowInvalidHttpContent flag which can be used to prevent the XmlRpcIllFormedXmlException exception in some circumstances.

2.27 How can I stop a WebException being thrown?

The Underlying Connection Was Closed

When an instance of WebException is thrown with this message "The underlying connection was closed: A connection that was expected to be kept alive was closed by the server", try setting the KeepAlive property on the proxy to false.

Protocol Violation

One of the issues involving XML-RPC.NET that turns up fairly frequently is when the library throws an instance of System.Net.WebException with the message "The server committed a protocol violation". This usually occurs because from .NET 1.1 SP1 onwards the parsing of HTTP responses became much more strict, as a security measure to prevent attacks which exploit malformed HTTP status lines and headers. The strict behaviour can be switched off via the application config file (or similarly with the web config file):

<?xml version ="1.0"?>
<configuration>
  <system.net>
    <settings>
      <httpWebRequest useUnsafeHeaderParsing="true" />
    </settings>
  </system.net>
</configuration>

From .NET 2.0 this configuration property can be set programmatically using the HttpWebRequestElement useUnsafeHeaderParsing property. This is used in the 2.0 configuration infrastructure to set the value in the config file. Once you do this the new value applies to the current running application as well as any instances launched afterwards. The property can be used like this:

Configuration config = ConfigurationManager.OpenExeConfiguration(
  ConfigurationUserLevel.None);
SettingsSection section = (SettingsSection)config.GetSection(
  "system.net/settings");
section.HttpWebRequest.UseUnsafeHeaderParsing = true;
config.Save();

ConfigurationUserLevel.None specifies that the configuration file in the same directory as the executable should be modified so this file has to be writable. The other options PerUserRoaming and PerUserRoamingAndLocal can be used in different scenarios.

Finally, the following code can be used with the .NET 2.0 runtime if you don't want to use the config file. It uses reflection to set the private field useUnsafeHeaderParsing to true and so may not be suitable in all scenarios where the relevant code access security permission is not available. (Note: add System.Configuration.dll as a reference to your project.)

public static bool SetAllowUnsafeHeaderParsing()
{
  //Get the assembly that contains the internal class
  Assembly aNetAssembly = Assembly.GetAssembly(
    typeof(System.Net.Configuration.SettingsSection));
  if (aNetAssembly != null)
  {
    //Use the assembly in order to get the internal type for 
    // the internal class
    Type aSettingsType = aNetAssembly.GetType(
      "System.Net.Configuration.SettingsSectionInternal");
    if (aSettingsType != null)
    {
      //Use the internal static property to get an instance 
      // of the internal settings class. If the static instance 
      // isn't created allready the property will create it for us.
      object anInstance = aSettingsType.InvokeMember("Section",
        BindingFlags.Static | BindingFlags.GetProperty 
        | BindingFlags.NonPublic, null, null, new object[] { });
      if (anInstance != null)
      {
        //Locate the private bool field that tells the 
        // framework is unsafe header parsing should be 
        // allowed or not
        FieldInfo aUseUnsafeHeaderParsing = aSettingsType.GetField(
          "useUnsafeHeaderParsing", 
          BindingFlags.NonPublic | BindingFlags.Instance);
        if (aUseUnsafeHeaderParsing != null)
        {
          aUseUnsafeHeaderParsing.SetValue(anInstance, true);
          return true;
        }
      }
    }
  }
  return false;
}

2.28 Can a proxy interface contain overloaded methods?

An interface can contain overloaded methods: methods with the same name but with with different parameter signatures. For example:

[XmlRpcUrl("http://www.cookcomputing.com/sumAndDiff.rem")] 
public interface ISumAndDiff
{ 
  [XmlRpcMethod] 
  SumAndDiffValue SumAndDifference(int x, int y);
  [XmlRpcMethod] 
  SumAndDiffValue SumAndDifference(string x, string y);
} 

Note that in this example, the server must be able to handle either two integers or two strings as the method parameters for its SumAndDifference method. If it is implemented using XML-RPC.NET then the .NET parameters in the server implementation should be declared as type object so that the actual type of the parameters sent by the client can be determined at runtime.

2.29 How Do I Implement a Client in Boo?

This sample implements a simple client in the Boo programming language:

import System
import CookComputing.XmlRpc from CookComputing.XmlRpc

[XmlRpcUrl("http://www.cookcomputing.com/xmlrpcsamples/RPC2.ashx")]
interface IStateName:
        [XmlRpcMethod("examples.getStateName")]
        def GetName(num as int) as string

obj as IStateName = XmlRpcProxyGen.Create(typeof(IStateName))
Console.WriteLine(obj.GetName(1))

2.30 Can I configure the client to not use the <string> tag?

When XML-RPC.NET generates an XML-RPC request containing string values, by default it uses the <string> tag for string values. However this is not required by the XML-RPC standard: it is possible to just include the text of the string as a child of the outer <value> tag. To configure the client to not use the <string> tag, the UseStringTag property of IXmlRpcProxy can be used, for example:

ISumAndDiff proxy = XmlRpcProxyGen.Create<ISumAndDiff>();
proxy.UseStringTag = false;

2.31 How do I configure client support for Accept-Encoding?

Some servers may support compression of XML-RPC responses. The client indicates that it can accept a compressed response by setting the HTTP Accept-Encoding header:

ISumAndDiff proxy = XmlRpcProxyGen.Create<ISumAndDiff>();
proxy.EnableCompression = true;

The content-codings compress and gzip are supported.

2.32 How do I prevent an empty params element in a request?

The XML-RPC spec is unclear about what should be sent in a request if the method call does not take any parameters. By default XML-RPC.NET sends an empty params element:

<?xml version=""1.0""?>
<methodCall>
  <methodName>Foo</methodName>
  <params />
</methodCall>

However, some servers expect the params element not to be sent if there are no parameters:

<?xml version=""1.0""?>
<methodCall>
  <methodName>Foo</methodName>
</methodCall>

To support these servers, set the UseEmptyParamsTag property of IXmlRpcProxy to false (the default is true):

ISumAndDiff proxy = XmlRpcProxyGen.Create<ISumAndDiff>();
proxy.UseEmptyParamsTag = false;

2.33 Can I retrieve the HTML response headers and cookies?

To retrieve the HTML response headers and cookies, use the ResponseHeaders and ResponseCookies properties of IXmlRpcProxy. For example, assuming the proxy interface ISumAndDiff is derived from IXmlRpcProxy (which is recommended):

ISumAndDiff proxy = XmlRpcProxyGen.Create<ISumAndDiff>();
SumAndDiffValue ret = proxy.SumAndDifference(2, 3);
WebHeaderCollection headers = proxy.ResponseHeaders;
CookieCollection cookies = proxy.ResponseCookies; 

The response headers and cookies retrieved are those associated with the last call made by the proxy. When making an asynchronous call the headers and cookies can be retrieved as follows:

Result ret = theProxy.EndSumAndDifference(asr); 
WebHeaderCollection headers = ((XmlRpcAsyncResult)iasr).ResponseHeaders;
CookieCollection cookies = ((XmlRpcAsyncResult)iasr).ResponseCookies;

2.34 How do I call an XML-RPC method which requires named parameters in a struct?

Some XML-RPC APIs use a struct as a single parameter to methods, so that the members of the struct acts as named parameters to the method. For example, the Last.fm API has a method called "artist.getInfo" which has two named parameters, "artist" and "api_key". The XML-RPC request XML for this method looks like this example:

<?xml version=""1.0""?>
<methodCall>
  <methodName>artist.getInfo</methodName>
  <params>
    <param>
      <value>
        <struct>
          <member>
            <name>artist</name>
            <value>
              <string>Bob Dylan</string>
            </value>
          </member>
          <member>
            <name>api_key</name>
            <value>
              <string>abcd1234</string>
            </value>
          </member>
        </struct>
      </value>
    </param>
  </params>
</methodCall>

This could be implemented in XML-RPC.NET by using a struct parameter but the StructParams attribute allows the method to be defined using multiple parameters which are automatically mapped to an XML-RPC struct at runtime, the names of the method parameters in the interface definition being used as the names of the members in the XML-RPC struct. For example, "artist.getInfo" could be defined like this:

public interface ILastFM : IXmlRpcProxy
{ 
    // ...

    [XmlRpcMethod("artist.getInfo", StructParams = true)]
    public string getInfo(string artist, string api_key);

    // ...
}

2.35 Can I use the NonSerialized attribute on struct members?

Yes, the System.NonSerialized attribute can be used to prevent a struct member being serialized or deserialized. For example instances of the following struct will only have the member "x" serialized into the XML-RPC struct:

struct MyStruct
{
  public int x;
  [NonSerialized]
  public int y;
}    

3. Servers

3.1 What are the different ways in which an XML-RPC server can be implemented?

There are three ways of implementing an XML-RPC server using XML-RPC.NET:

  1. In IIS using a class derived from XmlRpcService.
  2. Using an XML-RPC formatter with .NET Remoting.
  3. In IIS using an XML-RPC formatter with .NET Remoting.

3.2 How do I implement an XML-RPC server in IIS?

Class XmlRpcService implements an HTTP Handler which exposes the IHttpHandler and IRequiresSessionState interfaces. When a class derived from XmlRpcService is configured via a web.config file, incoming XML-RPC requests will be directed to the handler by the ASP.NET runtime.

Implementing the Service

XmlRpcService is derived from, adding the custom application function of the Service. The derived class contains one or more public methods which represent the required XML-RPC methods. For example, the SumAndDifference example would be implemented like this:

using System; 
using CookComputing.XmlRpc; 

struct SumAndDiffValue 
{ 
  public int sum; 
  public int difference; 
}
 
class SumAndDiffService : XmlRpcService
{ 
  [XmlRpcMethod("sample.sumAndDifference")] 
  public SumAndDiffValue SumAndDifference(int x, int y) 
  { 
    SumAndDiffValue ret; 
    ret.sum = x + y; 
    ret.difference = x – y; 
    return ret; 
  } 
} 

If this code is saved to a file called sumanddiff.cs the Service can be built using the following command line:

csc /r:system.web.dll /r:CookComputing.XmlRpcV2.dll /target:library sumanddiff.cs  

This will build a dll assembly called sumanddiff.dll.

Configuring the Service

The Service has to be placed in a virtual directory, say xmlrpc in this case, which has a sub-directory called bin. A configuraton file called web.config is created in the virtual root directory containing the following information to specify that the Service should be invoked when a HTTP request arrives for this URL:

<configuration>
  <system.web> 
    <httpHandlers>
      <add verb="*" path="SumAndDiff.rem" 
         type="SumAndDiffService, sumanddiff" />
    </httpHandlers>
  </system.web>
</configuration>

The config file specifies that if the final segment of the URL is SumAndDiff.rem the handler in the class SumAndDifference will be invoked. Note that the assembly qualified name of the class is used so that ASP.NET knows which assembly to load the class from.

The HTTP verb is specified by a wildcard. The implementation in XmlRpcService handles both POST for XML-RPC method calls and GET to return an automatically generated documentation on the Service. XmlRpcService will reject any other requests with the appropriate HTTP response code.

The extension used for the URL is “.rem”. This is for convenience because ASP.NET is configured by default to handle a number of extensions including .rem, .aspx, and .asmx. Other extensions could be used, for example .xmlrpc would be an obvious choice, but this involves changing the configuration of the virtual directory via the IIS management snap-in.

Once the service is configured a quick check can be made by pointing your browser at the URL and verifying that the automatically generated help page is displayed.

3.3 How do I implement an XML-RPC server using .NET Remoting?

XML-RPC.NET includes a Remoting formatter sink provider, the class XmlRpcServerFormatterSinkProvider. When configured this enables the Remoting infrastructure to handle incoming XML-RPC requests as well as SOAP requests.

using System;
using System.Runtime.Remoting;
using CookComputing.XmlRpc;

public struct SumAndDiffValue 
{ 
  public int sum; 
  public int difference; 
}

public class SumAndDiff : MarshalByRefObject 
{ 
  [XmlRpcMethod("sample.sumAndDifference")] 
  public SumAndDiffValue SumAndDifference(int x, int y) 
  { 
    SumAndDiffValue ret; 
    ret.sum = x + y; 
    ret.difference = x - y; 
    return ret; 
  } 
} 

Note that instead of deriving the service class from XmlRpcService, it is now derived from MarshalRefByObject.

class XmlRpcServer

{
  static void Main(string[] args) 
  { 
    // for CookComputing.XmlRpcV2
    RemotingConfiguration.Configure("SumAndDiff.exe.config", false); 
    // for CookComputing.XmlRpc
    //RemotingConfiguration.Configure("SumAndDiff.exe.config"); 
    RemotingConfiguration.RegisterWellKnownServiceType(
	  typeof(SumAndDiff), 
      "SumAndDiff.rem",
      WellKnownObjectMode.Singleton); 
    Console.WriteLine("Press to shutdown"); 
    Console.ReadLine(); 
  } 
}

A config file is needed to specify that the Remoting infrastructure uses the XML-RPC.NET formatter:

<configuration> 
  <system.runtime.remoting>
    <application>      
      <channels>         
        <channel ref="http" port="5678">
          <serverProviders>
<formatter
type="CookComputing.XmlRpc.XmlRpcServerFormatterSinkProvider, CookComputing.XmlRpcV2" /> <formatter ref="soap" /> </serverProviders> </channel> </channels> </application> </system.runtime.remoting> </configuration>

Note that the default SOAP formatter is the second formatter so that if the XML-RPC formatter does not recognize the request it can pass the request onto the next formatter. The file also specifies that the server listens on port 5678.

To limit access to the service to clients on the local machine only, specify localhost as the bindTo address in the config file:

<channel ref="http" port="5678" bindTo="127.0.0.1">

Finally, in some scenarios other code in the application may be required to interact with the service object, for example to subscribe to events on the service object and receive notifications when a request is processed. The code above makes this difficult because the application is not explicitly instantiating the service object. Vitor Silva has suggested this alternative:

    RemotingConfiguration.Configure("SumAndDiff.exe.config"); 
    MyRemObj myremobj = new MyRemObj();
    RemotingServices.Marshal(myremobj, "MyRemObjUri", typeof(myremobj));

3.4 How do I implement an XML-RPC server in IIS using .NET Remoting

A virtual directory is created and the assemblies placed in a sub-directory called bin. The config file is called web.config in this case and specifies two aspects of the server: the service element specifies the server class and its URL, and the channels element specifies that two formatters are supported, the default SOAP formatter and the XML-RPC formatter.

<configuration> 
  <system.runtime.remoting> 
    <application> 
      <service> 
        <wellknown mode="Singleton"    
                   type="SumAndDifference, sumanddiff" 
                   objectUri="SumAndDiff.rem" /> 
      </service> 
      <channels> 
        <channel ref="http">    
          <serverProviders>    
            <formatter    
type="CookComputing.XmlRpc.XmlRpcServerFormatterSinkProvider, CookComputing.XmlRpcV2" /> 
            <formatter ref="soap" /> 
          </serverProviders>    
        </channel>  
      </channels> 
    </application> 
  </system.runtime.remoting> 
</configuration> 

Obviously the URL used by the client should be changed to connect to IIS, for example:

SumAndDifference svr = (SumAndDifference)Activator.GetObject(
  typeof(SumAndDifference), 
"http://localhost/xmlrpc/SumAndDiff.rem");

3.5 Do XML-RPC.NET servers implement the XML-RPC Introspection API?

The base class for implementing all types of XML-RPC server is XmlRpcServerProtocol. This implements the Introspection API and so all XML-RPC.NET endpoints automatically expose this API.

3.6 What is Automatic Documentation?

XmlRpcHttpServerProtocol is the base class for implementing an XML-RPC endpoint in an HTTP server. This class handles GET requests by dynamically generating a help page for the endpoint using reflection.

The following attributes each take an optional named parameter called Description in their constructor:

- XmlRpcService
- XmlRpcMethod
- XmlRpcParameter
- XmlRpcReturnValue

The automatic documentation is generated using the method names of the class, the parameter types, and the values of the Description property of all attributes which hae been defined.

3.7 How do I support authentication in my XML-RPC service?

Authentication is not provided by standalone .NET Remoting and if required must be implemented by the developer. On the other hand IIS does support authentication and so the two IIS-based methods on implementing servers can be used where authentication is required. Configuration is exactly the same as for normal web pages and is described in the IIS online documentation.

3.8 Can I implement a server which supports both XML-RPC and SOAP?

Yes, if using .NET Remoting and the soap formatter is configured as well as the XML-RPC formatter, the server will handle both XML-RPC and SOAP requests.

<configuration> 
    <system.runtime.remoting>    
        <application> 
            <channels> 
                <channel ref="http" port="5678"> 
                    <serverProviders>
                       <formatter
type="CookComputing.XmlRpc.XmlRpcServerFormatterSinkProvider, CookComputing.XmlRpc"/>            
                        <formatter ref="soap" />       
                    </serverProviders> 
                </channel> 
            </channels> 
        </application> 
    </system.runtime.remoting> 
</configuration>

3.9 Can I run XML-RPC.NET services with other web servers?

Yes - as long as the web server supports ASP.NET. This is not as implausible as it might sound because it is fairly easy to host ASP.NET using the .NET implementation of System.Web.Hosting. An example of this is the Cassini Web Server implemented by the ASP.NET team.

One point worth mentioning when running Cassini is that assemblies by default must be placed in a directory called bin under the virtual root. For example, if the URL of the service is http://localhost/xmlrpc/math.rem assemblies are loaded from virtual /bin and not virtual /xmlrpc/bin. In this example the config file is placed in the virtual /xmlrpc directory and would look like this:

<configuration>
  <system.web>
    <httpHandlers>
      <add verb="*" path="math.rem" type="MathService, MathService" />
    </httpHandlers> 
  </system.web>
</configuration>

3.10 Can I implement Services in other languages?

Services can be implemented in any CLS compliant language as the samples in this section illustrate.

VB.NET

Imports CookComputing.XmlRpc

Public Structure SumAndDiffValue
  Public sum As Integer
  Public difference As Integer
End Structure


Public Class SumAndDiffService
  Inherits XmlRpcService


 <XmlRpcMethod("sample.sumAndDifference")> _
 Public Function SumAndDifference(ByVal x As Integer, _
                                  ByVal y As Integer) _
                                  As SumAndDiffValue
   Dim ret As SumAndDiffValue
   ret.difference = x - y
   ret.sum = x + y
   Return ret
 End Function

End Class

3.11 Can I implement a service in an ASHX file?

ASHX files provide a very simple way to deploy XML-RPC services without building assemblies and configuring a web.config file. Create a file like this with a .ashx extension and place it in a web directory which has a sub-directory called bin containing CookComputing.XmlRpcV2 assembly:

<%@ WebHandler Language= "VB" Class="Test" %>
<%@ Assembly Name="CookComputing.XmlRpcV2" %>

Imports CookComputing.XmlRpc

<XmlRpcService> _
Public Class Test Inherits XmlRpcService
    <XmlRpcMethod> _
    Public Function Foo(ByVal x as Integer) As Integer
        Return x * x
    End Function
End Class

ASHX web handlers can be written in C# a similar way.

3.12 How do I implement an XML-RPC server using HttpListener?

The .Net System.Net.HttpListener class can be used as the basis for an XML-RPC server implemented using XML-RPC.NET. First, the service functionality is implemented in a class deriving from the CookComputing.XmlRpc.XmlRpcListenerService class:

public class StateNameService : XmlRpcListenerService
{
  [XmlRpcMethod("examples.getStateName")]
  public string GetStateName(int stateNumber)
  {
    if (stateNumber < 1 || stateNumber > m_stateNames.Length)
      throw new XmlRpcFaultException(1, "Invalid state number");
    return m_stateNames[stateNumber - 1];
  }

  string[] m_stateNames
    = { "Alabama", "Alaska", "Arizona", "Arkansas",
        "California", "Colorado", "Connecticut", "Delaware", "Florida",
        "Georgia", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa", 
        "Kansas", "Kentucky", "Lousiana", "Maine", "Maryland", "Massachusetts",
        "Michigan", "Minnesota", "Mississipi", "Missouri", "Montana",
        "Nebraska", "Nevada", "New Hampshire", "New Jersey", "New Mexico", 
        "New York", "North Carolina", "North Dakota", "Ohio", "Oklahoma",
        "Oregon", "Pennsylviania", "Rhose Island", "South Carolina", 
        "South Dakota", "Tennessee", "Texas", "Utah", "Vermont", "Virginia", 
        "Washington", "West Virginia", "Wisconsin", "Wyoming" };
}

Acquiring the request synchronously via the HttpListener GetContext method, the top level code could look like this:

using System;
using System.IO;
using System.Net;
using CookComputing.XmlRpc;

class _
{
  public static void Main(string[] prefixes)
  {
    HttpListener listener = new HttpListener();
    listener.Prefixes.Add("http://127.0.0.1:11000/");
    listener.Start();
    while (true)
    {
      HttpListenerContext context = listener.GetContext();
      XmlRpcListenerService svc = new StateNameService();
      svc.ProcessRequest(context);
    }
  }
}

Note that the HttpListener class can also be used asynchronously.

3.13 Can I customise the XML returned by a service?

The format of the XML returned by a service can be customised by setting the following atttributes on the service class:

  1. Indentation - uses to define the number of spaces worth of indentation for response elements; the default is 2.
  2. UseIndentation - if set to true responses are formatted across multiple lines; if set to false a response is formatted as a single line; the default is true.
  3. UseIntTag - if set to true integer values in responses are formatted as <int> if set to false they are formatted as <i4>; the default is false.
  4. UseStringTag - if set to true string values in responses are formatted as <string>; if set to false they are formatted as simply the text contained by the <value> element; the default is true.
  5. XmlEncoding - this is used to specify the text encoding of responses. By default UTF-8 is used.

For example:

using System; 
using CookComputing.XmlRpc; 

struct SumAndDiffValue 
{ 
  public int sum; 
  public int difference; 
}

[XmlRpcService(XmlEncoding="ISO-8859-1", Indentation=1, 
    UseStringTag=false, UseIntTag=true, UseIndentation=true)] 
class SumAndDiffService : XmlRpcService
{ 
  [XmlRpcMethod("sample.sumAndDifference")] 
  public SumAndDiffValue SumAndDifference(int x, int y) 
  { 
    SumAndDiffValue ret; 
    ret.sum = x + y; 
    ret.difference = x – y; 
    return ret; 
  } 
} 

4. Error Handling

4.1 How are XML-RPC Fault Responses represented?

An XML-RPC Fault Response contains a struct with two members: a fault code and a fault description:

<?xml version="1.0"?>
<methodResponse>
  <fault>
    <value>
      <struct>
        <member>
          <name>faultCode</name>
          <value><int>4</int></value>
        </member>
        <member>
          <name>faultString</name>
          <value><string>Too many parameters.</string></value>
        </member>
      </struct>
    </value>
  </fault>
</methodResponse>

XML-RPC.NET maps Fault Responses onto .NET exceptions, more specifically a type called XmlRpcFaultException. This is derived from System.ApplicationException and contains two properties: int FaultCode and string FaultDescription. Server application code simply throws an instance of this exception where required and XML-RPC.NET catches it and returns it as a Fault Response. For example:

throw new XmlRpcFaultException(100, "Invalid argument"); 

On the client side XML-RPC.NET receives the Fault Response, extracts the code and description, and throws a corresponding instance of XmlRpcFaultException. Client code can catch this exception using a try-catch block. For example:

SumAndDiffProxy sdprxy = new SumAndDiffProxy();
try
{
  SumAndDiffValue ret = sdprxy->SumAndDifference(2, 3);
}
catch (XmlRpcFaultException fex)
{
  Console.WriteLine("Fault Response: {0} {1}", 
    fex.FaultCode, fex.FaultString);
}

4.2 How are other types of error returned?

Error conditions can occur at other stages of an XML-RPC call. These fall into two categories, the first being networking errors, for example the client failing to connect to the server because the URL is invalid or the server is down. The second category is where the XML-RPC request reaches the server but cannot be processed for some reason, for example because it is not a valid XML-RPC request or the server application code crashes while processing the request.

Unfortunately XML-RPC does not provide a way of differentiating between an application level error and a protocol level or internal error, for example if the request is not a valid XML-RPC request. One approach is to define a well-known set of error codes which will be used by all XML-RPC implementations but this suffers from the drawback that this set of error codes cannot be guaranteed to never conflict with the error codes that application code may need to return. Application code can certainly choose its own error codes but may also need to return error codes from third party code, for example from a database.

Currently XML-RPC.NET returns a fault code of zero when a protocol or internal error occurs, leaving all other error codes available for application level error reporting.

4.3 What happens if the return value of a proxy method is incorrect?

If a proxy method is defined to return the wrong data type an instance of XmlRpcTypeMismatchException is thrown when the response is parsed. For example, if the sample.SumAndDifference method was incorrectly defined to return a string:

[XmlRpcUrl("http://www.cookcomputing.com/sumAndDiff.rem")] 
public interface ISumAndDiff : IXmlRpcProxy
{ 
  [XmlRpcMethod] 
  string SumAndDifference(int x, int y);
} 

an instance of XmlRpcTypeMismatchException would be thrown, containing the message "param element contains unexpected struct element". This is because the XML-RPC response contains a struct but the deserializer is expecting a string (it knows this from reflecting on the return value of the proxy method).

5. Debugging

5.1 How do I monitor XML-RPC calls across the network?

A very useful tool for monitoring the HTTP requests and responses associated with an XML-RPC call is tcptrace. This enables you to view the headers and content of HTTP requests. Configure it to use an unused port on your machine and set the destination server and destination port to those of the XML-RPC endpoint. Point your client at the local port you have chosen and all XML-RPC requests will pass through tcptrace, which will display in particular the request and response XML documents.

Perhaps even more useful is the HTTP debugging proxy called Fiddler. This allows you to look at requests and responses as text, hex, or xml.

Finally, proxies expose two events - RequestEvent and ResponseEvent - which provide access to the streams containing the request and response XML for each XML-RPC call. The delegates used to subscribe to these events are:

public delegate void XmlRpcRequestEventHandler(
  object sender, 
  XmlRpcRequestEventArgs args);

public delegate void XmlRpcResponseEventHandler(
  object sender, 
  XmlRpcResponseEventArgs args);

XmlRpcRequestEventArgs has properties which provide information for logging the request: ProxyID, a Guid uniquely identify the proxy instance; RequestNum, an ascending number uniquely identifying the request within the current AppDomain; and RequestStream, a stream containing the XML request which will be sent to the server.

XmlRpcResponseEventArgs has similar properties, the difference being that it has a ResponseStream property instead of RequestStream.

The library contains a helper class - XmlRpcLogger - which simplifies attaching logging code to a proxy. For example, to log the content of requests and responses to the current trace listener(s) this class derived from XmlRpcLogger can be used:

public class Tracer : XmlRpcLogger
{
  protected override void OnRequest(object sender, 
    XmlRpcRequestEventArgs e)
  {
    DumpStream(e.RequestStream);
  }

  protected override void OnResponse(object sender, 
    XmlRpcResponseEventArgs e)
  {
    DumpStream(e.ResponseStream);
  }

  private void DumpStream(Stream stm)
  {
    stm.Position = 0;
    TextReader trdr = new StreamReader(stm);
    String s = trdr.ReadLine();
    while (s != null)
    {
      Trace.WriteLine(s);
      s = trdr.ReadLine();
    }
  }
}

Then once you have created a proxy attach an instance of Tracer:

IStateName proxy = (IStateName)XmlRpcProxyGen.Create(
  typeof(IStateName));
Tracer tracer = new Tracer();
tracer.Attach(proxy);
string ret = proxy.GetStateName(45);

The XML-RPC.NET assembly contains class Tracer as well as class RequestResponseLogger which can be used to dump the contents of request and responses to individual files. This is useful when it is necessary to examine the exact content that it is being sent to and returned from the server. RequestResponseLogger has a Directory property to specify where the files should be written to, the default being the current directory. The filenames for requests and response pairs look like this:

632880530803281250-0002-request-351884cb-cbde-417e-906e-b1424f617d89.xml 632880530803281250-0002-response-351884cb-cbde-417e-906e-b1424f617d89.xml

The first number is the number obtained from DateTime.Now.Ticks, the second number is the id of the request, and the guid is the id of the proxy used to make the call.

RequestResponseLogger is used in the same way as the Tracer class (see LoggingSample in the distribution):

IStateName proxy = (IStateName)XmlRpcProxyGen.Create(
  typeof(IStateName));
RequestResponseLogger dumper = new RequestResponseLogger();
dumper.Attach(proxy);
string ret = proxy.GetStateName(45);

5.2 How do I debug an XML-RPC.NET service?

XML-RPC.NET services under IIS run within the aspnet_wp.exe process and so must be debugged by attaching a debugger to this process.

Using the SDK Debugger

To attach to aspnet_wp.exe from the .NET SDK debugger - dbgclr.exe - perform these steps:

  1. Call the service to ensure aspnet_wp.exe is running and the service is loaded.
  2. Launch the debugger.
  3. Use the File...Open File menu item to open the source file for the page you want to debug.
  4. From the Tools menu, choose Debug Processes. Check the Show system processes checkbox, if it is not checked (this may not be necessary, depending on the account aspnet_wp.exe is running under).
  5. Find the aspnet_wp.exe process and double-click it to attach to it.
  6. Close the Processes dialog.

To debug the service, place breakpoints in the source file and call the service.

Using the Visual Studio .NET Debugger

To attach to aspnet_wp.exe from Visual Studo .NET, perform the following steps:

  1. Call the service to ensure aspnet_wp.exe is running and the service is loaded.
  2. Open the project which implements the service you want to debug.
  3. From the Debug menu, choose Processes.
  4. Find the aspnet_wp.exe process and double-click it
  5. Check Common Language Runtime on the Attach to Process dialog which then appears and click OK. (It is ok to leave Native checked.)
  6. Close the Processes dialog.

To debug the service, place breakpoints in the source file and call the service.

Using Cassini

The easiest method of debugging a service is to use the Cassini web server. In either the SDK debugger or Visual Studio set the program to be run as the Cassini executable and set the arguments as required by Cassini, <physical-path> <port> <virtual-path>, for example:

c:\cassini\wwwroot   82  /

Set breakpoints and then select Debug..Start or hit F5. The advantage of using Cassini is that you don't have to re-attach the debugger each time you rebuild the service.

6. Miscellaneous

6.1 Which XML Encodings are Supported?

XML-RPC.NET uses compliant XML parsers and writers. It outputs XML in the UTF-8 encoding by default and accepts various encodings when reading XML, for example UTF-8, UTF-16, ISO-8859-1, etc.

String handling in XML-RPC is problematic because the XML-RPC standard is inconsistent in this area. XML-RPC.NET handles the issue by specifying that the string value element can contain any Unicode character which can be contained in XML text content.

When sending a request it is possible to specify the encoding by setting the XmlEncoding property of the proxy class. For example:

SumAndDiffProxy proxy = new SumAndDiffProxy();
proxy.XmlEncoding = new System.Text.ASCIIEncoding();
SumAndDiffValue ret = proxy.SumAndDifference(2, 3);

Refer to the .NET Framework documentation for the encodings that are supported.

6.2 Which Code Access Security Permissions are Required?

XML-RPC.NET needs a minimal set of Code Access Security (CAS) permissions, in particular networking permission to connect to a server. In the case of downloadable smart clients this could be restricted to connecting to the server from which the client was downloaded.

6.3 Why is the key file not included in the distribution?

Building XML-RPC.NET from the distribution will fail because of a missing file called CookComputing.key. This contains the public/private key pair used to sign the CookComputing.XmlRpcV2.dll assembly with a strong name. The file is not distributed because this would enable anyone else to build a malicious version of the assembly and pass it off as originating from Cook Computing.

To generate your own key file using the sn.exe tool as follows:

sn -k mykeyfile.snk

and modify the relevant line in assemblyinfo.cs:

[assembly: AssemblyKeyFile("mykeyfile.snk")]

Alternatively, comment out this line if you do not need to sign your assembly with a strong name.

6.4 How do I verify an XML-RPC.NET assembly is genuine?

Use the sn.exe tool to extract the public key token from the assembly:

sn -T cookcomputing.xmlrpcV2.dll

The token should be the same as this if the assembly was built using the Cook Computing key file:

a7d6e17aa302004d

6.5 Can I define an interface from which both the proxy and server classes are derived?

Yes, although you will need to derive a class from the interface which also derives from IXmlRpcProxy for use with XmlRpcProxyGen, for example:

public interface ISumAndDiff
{ 
  [XmlRpcMethod] 
  SumAndDiffValue SumAndDifference(int x, int y);
} 

public interface ISumAndDiffClient : ISumAndDiff, IXmlRpcProxy
{ 
} 

6.6 How do I implement a client when code generation is not allowed?

Sometimes client code will need to run without the security permissions for code generation which are necessary to create proxy classes using XmlRpcProxyGen.Create, for example when running in the untrusted internet security zone. In this scenario it is necessary to implement proxies manually.

using System.Reflection;
using CookComputing.XmlRpc;

struct SumAndDiffValue 
{
  public int sum; 
  public int difference; 
}

[XmlRpcUrl("http://www.cookcomputing.com/sumAndDiff.rem")] 
class SumAndDiffProxy : XmlRpcClientProtocol 
{ 
  [XmlRpcMethod] 
  SumAndDiffValue SumAndDifference(int x, int y) 
  { 
    return (SumAndDiffValue)Invoke(MethodBase.GetCurrentMethod(), 
                                   new Object[]{ x, y }); 
  } 
} 

The SumAndDiffValue is defined to represent the result of the sample.sumAndDifference XML-RPC call. Each member of the struct represents a member of the XML-RPC struct returned by the call. Note that members must be defined as public.

The XmlRpcUrl attribute is applied to the proxy class to specify the URL of the server endpoint.

The class being defined derives from XmlRpcClientProtocol to inherit the required proxy functionality.

Each method representing an XML-RPC method is marked with the XmlRpcMethod attribute.

The SumAndDifference method is defined to represent the XML-RPC call. The member function Invoke (inherited from XmlRpcClientProtocol) is called, passing the current function and the parameters to the call in an array of type Object. The value returned from Invoke is cast to the required return type for the function and returned.

Note that in cases where MethodBase.GetCurrentMethod() is not available, for example with the Compact Framework, the name of the currentmethod should be passed instead (NOT the name of the XML-RPC method which might be different).

Use the proxy class like this:

SumAndDiffProxy proxy = new SumAndDiffProxy();
SumAndDiffValue ret = proxy.SumAndDifference(2, 3);

The proxy class can also be manually coded in VB.NET:

Imports CookComputing.XmlRpc
Module SumAndDiffSample
  Public Structure SumAndDiffValue
    Public sum As Integer
    Public difference As Integer
  End Structure
<XmlRpcUrl("http://www.cookcomputing.com/sumAndDiff.rem")> _ Public Class SumAndDiffProxy Inherits XmlRpcClientProtocol
<XmlRpcMethod("sample.sumAndDifference")> _ Public Function SumAndDifference(ByVal x As Integer, _ ByVal y As Integer) _ As SumAndDiffValue Return Invoke(MethodBase.GetCurrentMethod(), New Object() { x , y }) End Function End Class Sub Main() Dim proxy As New SumAndDiffProxy() Dim strct As New SumAndDiffValue() proxy.SumAndDifference(2, 3) End Sub End Module

6.7 Why does my client throw exception "Invoke on non-existent proxy method"?

This problem can occur when the first parameter to Invoke is the current method name and not the return value from MethodBase.CurrentMethod(). When manually implementing a proxy method there are two method names involved: the name of the proxy method and the name of the XML-RPC method. These names are not necessarily the same, and if the first parameter of Invoke is the XML-RPC method name, and not the proxy method name, an exception is thrown with the message: "Invoke on non-existent proxy method". This problem can be avoided by following these rules when using the method name with Invoke:

  1. The call to Invoke always passes the name of the proxy method.
  2. If the the name of XML-RPC method is not the same as the name of the proxy method, the XML-RPC method name is specified by passing it to the XmlRpcMethod attribute.

The reason for this is that there are two stages of serialization when making an XML-RPC call. The first is performed by the implementation of the proxy method, converting the call into a method name and an array of type Object which contains the parameters.This representation of the call is then passed to the XmlRpcClientProtocol class using the Invoke method. The second stage is when the method name and parameter array are converted into the XML request.

For the second stage to work effectively it needs to how the parameters should be mapped onto the params element of the XML request and what method name should be specified in the methodCall element. The first point is handled by using reflection on the proxy method, hence the need for the proxy method name, and the second point is handled by using the name specified in the XmlRpcMethod attribute (or the proxy method name if a name is not specified in the attribute).

6.8 Does XmlRpcClientProtocol.Invoke use params for the array of parameters?

When calling XmlRpcClientProtocol.Invoke, the parameter which passes the array of method parameters is defined with the params keyword. This means that instead of calling Invoke with an explcitly declared array of type object[], we can pass the method parameters as individual parameters to Invoke. For example, this proxy method:

[XmlRpcMethod] SumAndDiffValue SumAndDifference(int x, int y)
{
  return (SumAndDiffValue)Invoke("SumAndDifference", new Object[]{ x, y }); 
} 

can be coded as:

[XmlRpcMethod] SumAndDiffValue SumAndDifference(int x, int y)
{
  return (SumAndDiffValue)Invoke("SumAndDifference", x, y); 
} 

6.9 How do I manually implement asynchronous requests?

For cases where a manually implemented proxy is required it is possible to make asynchronous calls via the BeginInvoke and EndInvoke methods of XmlRpcClientProtocol.

In both cases two new methods must be implemented in the proxy class for each XML-RPC method. For example:

[XmlRpcUrl("http://www.cookcomputing.com/sumAndDiff.rem")]
class SumAndDiffProxy : XmlRpcClientProtocol 
{
  [XmlRpcMethod("sample.sumAndDifference")] 
  SumAndDiffValue SumAndDifference(int x, int y) 
  { 
    return (SumAndDiffValue)Invoke("SumAndDifference", new Object[]{ x, y }); 
  } 
   
  public IAsyncResult BeginSumAndDifference(int x, int y, AsyncCallback callback,    
                                            object asyncState) 
  { 
    return BeginInvoke("SumAndDifference", new object[]{x, y}, callback, asyncState);    
  } 

  public Result EndSumAndDifference(IAsyncResult asr) 
  { 
    return (Result)EndInvoke(asr); 
  } 
} 

6.10 Does XML-RPC.NET work with Mono?

Although XML-RPC.NET is not developed and tested in a Mono environment, there should be no problem running with Mono, either on Windows or Linux.

6.11 Does XML-RPC.NET work with .Net Compact Framework?

The XML-RPC.NET distribution contains an assembly which provides support for the .NET Compact Framework: CookComputing.XmlRpc.CF.dll. Note that this is an experimental version and is mostly untested. Also, because the Compact Framework does not support reflection it is necessary to implement XML-RPC.NET proxies manully.

6.12 How does the XML-RPC.NET license affect my product?

XML-RPC.NET is released under the terms of the MIT X11 license:

The MIT License

Copyright (c) 2006 Charles Cook

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

This license is not "viral" and so does not affect the licensing of any product which uses XML-RPC.NET. The only requirement is that any copyright notices contain a copyright notice for XML-RPC.NET, for example:

"XML-RPC.NET Copyright (c) 2006 Charles Cook".

6.13 How do I build XML-RPC.NET?

As of version 2.0.0 XML-RPC.NET is built using MSBuild. This allows the same project files to be used either from the command line using MSBuild or from within Visual Studio 2005 (note that Visual Studio 2003 cannot be used).

Additional tasks and targets are provided by the MSBuild Community Tasks Project. For running unit tests in the build it is necessary to install version 2.2.7 of NUnit.

To build CookComputing.XmlRpc.dll - the assembly built using the .NET 1.0 compiler it is necessary to build from the command line:

msbuild xml-rpc.net.proj /t:BuildXmlRpc1_0

7. Resources

7.1 XML-RPC Specification

Dave Winer's XML-RPC specification is available here.

7.2 Books and Tutorials

The following book is worth reading if you are working with XML-RPC. As well as clearing up some of the issues in the spec it includes chapters on several of the XML-RPC toolkits.

Programming Web Services with XML-RPC - Simon St. Laurent, Edd Dumbill, Joe Johnston (O'Reilly)

7.3 Websites

XML-RPC.com - specfications, implementations, services, etc.

XML-RPC.NET Site - home of XML-RPC.NET

Cook Computing - Charles Cook's website and blog often has posts relating to XML-RPC.NET.

7.4 Mailing Lists

There are two relevant Yahoo groups:

xml-rpc - " This list provides a forum for discussing and implementing the XML-RPC specification as a cross-platform protocol."

XMLRPCNET - "Discussion of the XML-RPC.NET library."

7.5 Articles and Tutorials

Eric Kidd's XML-RPC HOWTO provides useful information on implementing clients and servers in a variety of languages.

7.6 Sample Services

The XML-RPC.NET Demos page contains links to some XML-RPC services implemented using XML-RPC.NET.