RestSharp Methods Throw System.Xml.XMlException "=" is an unexpected token. The expected token is ';'

I think the error is being thrown because I'm not serializing my model objects into JSON before sending the RestRequest.

restRequest.AddJsonBody(request); will serialize the object and add the appropriate header to the request. The stack trace looks like the issue is with the response being returned as XML and what happens when it tries to desrialize it.

When I run this code, I do note that an HTTP 404 is thrown in the content section of the stack trace.

I think this means that I have an incorrect baseURl but am not sure and would like to know if this is the case or if my code has other issues?

Taking a quick look at their docs it looks like you are calling their (SOAP) XML API. So you are calling the wrong base URL, if the intention is to interact with ProPay REST Interface.

For REST they show the following

Resource URI and HTTP Methods

The request URI is constructed from a Base URI and a Resource URI appended. A Resource URI may be used differently based on the HTTP verb of the request. Consider the following Example:

ProPay Integration environment Base URI: https://xmltestapi.propay.com
Resource: /propayAPI/signup
HTTP Method: PUT
Request Endpoint: PUT https://xmltestapi.propay.com/propayapi/signup

Which would mean you need to update your code

public static async Task<ProPayResponse> MerchantSignUpForProPay() {
    var baseUrl = "https://xmltestapi.propay.com/propayapi";
    var content = await BuildMerchantTestData();
    var request = CreateRestRequest("Signup", Method.PUT);
    request.AddJsonBody(content);
    return await Execute<ProPayResponse>(request, baseUrl);
}

private static async Task<T> Execute<T>(IRestRequest request, string baseUrl) 
    where T : class, new() {
    var client = new RestClient(baseUrl);
    var response = await client.ExecuteTaskAsync<T>(request);

    if (response.ErrorException != null) {
        Console.WriteLine(
            "Error: Exception: {0}, Headers: {1}, Content: {2}, Status Code: {3}",
            response.ErrorException,
            response.Headers,
            response.Content,
            response.StatusCode);
    }

    return response.Data;
}

private static RestRequest CreateRestRequest(string resource, Method method) {
    var credentials = GetCredentials();
    var restRequest = new RestRequest(resource, method, DataFormat.Json);
    restRequest.AddHeader("Accept", "application/json");
    restRequest.AddHeader("Authorization", credentials);
    return restRequest;
}

I would suggest making the base URL configurable instead of hard coded so that it can be easily changed when going into production without having to recompile.


Following your Update 2, it looks like RestSharp is introducing an unexpected character at the start of the XML.

This is from the error message:

Content: ?<?xml version="1.0" encoding="utf-8"?>

The question mark before <?xml is the problem. It's not a valid character for XML, and is causing the XML parser to throw an error.

My best guess here is that the XML content in the response has a UTF-8 byte order mark (BOM) at the start. The BOM is not technically a valid character, and your logging code/framework is converting it to a ? for display.

You could test this by calling .ExecuteTaskAsync(request) instead of .ExecuteTaskAsync<T>(request) and looking at the data coming back in response.RawBytes. If the first 3 bytes coming back are 0xEF 0xBB 0xBF then you have a BOM in your response.

Quick fix

This should do the job, and requires minimal code changes.

restRequest.OnBeforeDeserialization = resp => {
    if (resp.RawBytes.Length >= 3 && resp.RawBytes[0] == 0xEF && resp.RawBytes[1] == 0xBB && resp.RawBytes[2] == 0xBF)
    {
        // Copy the data but with the UTF-8 BOM removed.
        var newData = new byte[resp.RawBytes.Length - 3];
        Buffer.BlockCopy(resp.RawBytes, 3, newData, 0, newData.Length);
        resp.RawBytes = newData;

        // Force re-conversion to string on next access
        resp.Content = null;
    }
};

This will ensure that the BOM is removed early on. When it's converted to a string for XML parsing, the BOM will not be present.

Lengthier fix

You can create your own deserializer for XML, which detects the BOM at the start of the XML and removes it before parsing. The steps here are:

  1. Subclass RestSharp.Deserializers.XmlDeserializer. This will need a single method override:
public override T Deserialize<T>(IRestResponse response)
{
    if (string.IsNullOrEmpty(response.Content))
        return default(T);

    if (response.Content[0] == '\uFEFF')
        response.Content = response.Content.Substring(1);

    return base.Deserialize<T>(response);
}
  1. Create an instance of the above class.
  2. Create an instance of RestSharp.Deserializers.XmlRestSerializer and call .WithXmlDeserializer() with the class from the step 2 above.
  3. Calling .AddHandler("application/xml", () => xmlRestSerializer) on your RestClient instance.
    • xmlRestSerializer is the object you created in step 3 above.
    • You may need to replace application/xml with something else, depending on what the REST API returns.