views:

179

answers:

3

I'm experimenting with using Google Checkout and am having a problem posting to the checkout server. Here is my code:

XNamespace ns = XNamespace.Get("http://checkout.google.com/schema/2");

XDocument cart = new XDocument();
XElement rootElement = new XElement(ns + "checkout-shopping-cart",
    new XElement("shopping-cart",
        new XElement("items",
            new XElement("item",
                new XElement("item-name", "doodad"),
                new XElement("item-description", "Description for the doodad"),
                new XElement("unit-price", 9.99, new XAttribute("currency", "GBP")),
                new XElement("quantity", 1)
            )
         )
    )
);

cart.Add(rootElement);

string authKey = "111222333444:NOTAREALKEY";
authKey = EncodeToBase64(authKey);

HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://checkout.google.com/cws/v2/Merchant/111222333444/merchantCheckout");

request.Method = "POST";
byte[] byteArray = Encoding.UTF8.GetBytes(cart.ToString());
request.ContentType = "application/xml; charset=UTF-8";
request.ContentLength = byteArray.Length;
request.Headers.Add("Authorization: Basic " + authKey);
request.Accept = "application/xml; charset=UTF-8";

Stream dataStream = request.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();

HttpWebResponse response = (HttpWebResponse)request.GetResponse(); // Exception here!
dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader(dataStream);
string responseText = reader.ReadToEnd();

reader.Close();
dataStream.Close();
response.Close();

When I call GetResponse(), I get a (400) Bad Request.

Any assistance on this would be gratefully received.

+2  A: 

Not knowing anything about the Google Checkout API, are you sure you don't need the namespace on each of those elements?

XElement rootElement = new XElement(ns + "checkout-shopping-cart",
    new XElement(ns + "shopping-cart"),
        new XElement(ns + "items",
                     // etc

That's certainly what the Checkout API guide suggests to me - note that "xmlns=..." means that's the namespace for this element and all descendant elements unless otherwise specified.

Jon Skeet
I dont think so, according to the API docs: http://code.google.com/apis/checkout/developer/Google_Checkout_XML_API.html#checkout_integration_options
DavidGouge
@DavidGouge: I think you've missed the fact that it's xmlns="..." rather than xmlns:foo="...".
Jon Skeet
Not sure I follow, but having double checked the xml I'm generating, it seems I'm getting a blank namespace on the children of the root element. Wonder if that is causing the problems.<checkout-shopping-cart xmlns="http://checkout.google.com/schema/2"> <shopping-cart xmlns="" /> <items xmlns=""> <item> <item-name>doodad</item-name> <item-description>Description for the doodad</item-description> <unit-price currency="GBP">9.99</unit-price> <quantity>1</quantity> </item> </items></checkout-shopping-cart>
DavidGouge
@DavidGouge: Yes, that's because you haven't specified a namespace - it's effectively "undoing" the xmlns="..." from the parent. Have you tried my suggestion?
Jon Skeet
Oh I see! Thanks, I'll give it a try now. :D
DavidGouge
Ok, I've added the 'ns + ' to each element (and also fixed a bug that was creating an empty 'shopping-cart' element) but I get the same Bad Request error. I'm starting to think that it's not the content of the post that's the problem as I would expect *a* response from google telling me it's rubbish.
DavidGouge
The fact that it's returning you "bad request" *is* telling you it's rubbish. That's the point of the bad request status code. Not including the namespaces may well not be the *only* problem, but I think it was *a* problem.
Jon Skeet
Thank you so much for the help. Seems it was a combination of the xml being incorrect and me using a sandbox merchant ID with the live url. Thanks very much for the help and the push in the right direction. :D
DavidGouge
+2  A: 

Your XML looks broken as Jon Skeet points out :-). In order to further aid debugging - there may be more information about the error in the response. WebException has a Response object that might have a more detailed error message that can be read by calling its GetResponseStream() method.

Duncan Smart
Aha! Thank you, the error in the WebException's Response did indeed point me in the right direction. (Although it may as well have said 'Dave, you're being an idiot!'). I was using a sandbox merchant ID, but the live url. Thanks ever so much for the help.
DavidGouge
A: 

You still can read response message, if exception is WebException. This will give you more information on what's wrong:

try {
   response = (HttpWebResponse)request.GetResponse();
}
catch (WebException ex1) {
   response = ex1.Response();
}
Tomas Kirda