RestSharp PUT XML, RestSharp is sending it as GET? - c#

I am attempting to edit a product using the prestashop API, using RestSharp in C#, using XML. The documentation's instructions are as follows:
To edit an existing resource: GET the full XML file for the resource you want to change (/api/customers/7), edit its content as needed, then PUT the whole XML file back to the same URL again.
I am attempting to edit /customers/1.
My GET calls are working fine to retrieve the data. I am now deserializing the data, editing it as needed, and re-saving to an XML file. All seems to be going well. The only fields I am attempting to change right now are firstname and lastname. The rest of the data is untouched. Here is a copy of the XML I am using:
<prestashop xmlns:xlink="http://www.w3.org/1999/xlink">
<customer>
<id><![CDATA[1]]></id>
<id_default_group xlink:href="http://heatherfazelinia.com/api/groups/3"><![CDATA[3]]></id_default_group>
<id_lang xlink:href="http://heatherfazelinia.com/api/languages/1"><![CDATA[1]]></id_lang>
<newsletter_date_add><![CDATA[2013-12-13 08:19:15]]></newsletter_date_add>
<ip_registration_newsletter></ip_registration_newsletter>
<last_passwd_gen><![CDATA[2014-06-20 16:56:30]]></last_passwd_gen>
<secure_key><![CDATA[6a9b9eab95448d74a026b869d8cd723e]]></secure_key>
<deleted><![CDATA[0]]></deleted>
<passwd><![CDATA[6028853eb1033578f7432015042fa486]]></passwd>
<lastname>newLastName</lastname>
<firstname>newFirstName</firstname>
<email><![CDATA[pub#prestashop.com]]></email>
<id_gender><![CDATA[1]]></id_gender>
<birthday><![CDATA[1970-01-15]]></birthday>
<newsletter><![CDATA[1]]></newsletter>
<optin><![CDATA[1]]></optin>
<website></website>
<company></company>
<siret></siret>
<ape></ape>
<outstanding_allow_amount><![CDATA[0.000000]]></outstanding_allow_amount>
<show_public_prices><![CDATA[0]]></show_public_prices>
<id_risk><![CDATA[0]]></id_risk>
<max_payment_days><![CDATA[0]]></max_payment_days>
<active><![CDATA[1]]></active>
<note></note>
<is_guest><![CDATA[0]]></is_guest>
<id_shop><![CDATA[1]]></id_shop>
<id_shop_group><![CDATA[1]]></id_shop_group>
<date_add><![CDATA[2014-08-01 13:20:37]]></date_add>
<date_upd><![CDATA[2014-08-01 13:20:37]]></date_upd>
<associations>
<groups node_type="groups">
<groups xlink:href="http://heatherfazelinia.com/api/groups/3">
<id><![CDATA[3]]></id>
</groups>
</groups>
</associations>
</customer>
</prestashop>
That file is saved as EditedXML.xml. Again, according to the documentation (that I pasted above), to edit a resource I am supposed to use PUT to put the XML back to the same URL (which is /customers/1). So I am using the following code right before creating this topic to try to do just that:
// PUT call
var putRequest = new RestRequest("/customers/1", Method.PUT);
var body = System.IO.File.ReadAllText("EditedXML.xml");
request.AddBody(body);
IRestResponse putResponse = client.Execute(putRequest);
Console.WriteLine("Response: " + putResponse.Content);
Now comes my problem. I am getting the error (originally in HTML form, I opened it as HTML to post it more readable:)
Method Not Implemented
GET to /api/customers/1 not supported.
Additionally, a 404 Not Found error was encountered while trying to use an ErrorDocument to handle the request.
That error I find VERY confusing for 2 reasons:
1) It seems that even though my request is Method.PUT, it is being read as GET?
2) What it is claiming isn't even true? I have to call a GET function on that same resource to get the initial data?
Just incase anyone would like to see the GET call, here it is:
request = new RestRequest(Method.GET);
request.Resource = "/customers/1";
IRestResponse<customer> newResponse = client.Execute<customer>(request);
Anyone have any idea what is going on? I'm not sure how to debug this, I'm not sure if the PUT call is working at all, or if the arguments with my PUT call are wrong, or what...

We had a similar problem, we had to use the following code to set the body correctly.
request.AddParameter("application/x-www-form-urlencoded", rawXml, ParameterType.RequestBody);

"request.AddBody(body);" seems not to be working.
Please check this example on how i'm updating customer.
// GET customer with id 1
var client = new RestClient(PrestaShopBaseUrl);
client.Authenticator = new HttpBasicAuthenticator(PrestaShopAccount, "");
RestRequest request = new RestRequest("/customers/1", Method.GET);
IRestResponse response = client.Execute(request);
XmlDocument doc = new XmlDocument();
doc.LoadXml(response.Content);
doc.Save(#"Customer.xml");
// do something with customer file
// init XMLDocument and load customer in it
doc = new XmlDocument();
doc.Load(#"Customer.xml");
// Update (PUT) customer
request = new RestRequest("/customers/1", Method.PUT);
request.Parameters.Clear();
request.AddParameter("text/xml;charset=utf-8", doc.InnerXml, ParameterType.RequestBody);
response = client.Execute(request);

Related

Sharepoint online API returns: HTTP Error 400. A request header field is too long

I have a loop that will loop through records in my DB, pulling information i need and then creating 3 folders & upload a file.
This works OK for like 40 records but then it starts erroring out with the below response back from sharepoint: <!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"\"http://www.w3.org/TR/html4/strict.dtd\">\r\n<HTML><HEAD><TITLE>Bad Request</TITLE>\r\n<META HTTP-EQUIV=\"Content-Type\" Content=\"text/html; charset=us-ascii\"></HEAD>\r\n<BODY><h2>Bad Request - Header Field Too Long</h2>\r\n<hr><p>HTTP Error 400. A request header field is too long.</p>\r\n</BODY></HTML>
I am not sure whats going on, i read online its todo with cookies but i am using HTTPClient to send the request so i dont know how that would effect it? I also seen onlne about changing the kestrel?
Can anybody shed some light on this for me? Provide me with an easy but working solution? I dont use CSOM for integrating to sharepoint online, i use HTTP Requests, below is a sample of how i interact with sharepoint.
It seems as if i get blocked or banned temporarily cause if i wait a good bit, i can then make the same request that failed previously, and it will work! So strange.
Sample code (Used to create a resource at Sharepoint):
//Set Endpoint
var sharePointEndpoint = $"https://{hostname}/sites/{site}/_api/web/folders";
//Set default headers
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", sharePointToken); //Set token
client.DefaultRequestHeaders.Add("Accept", "application/json;odata=verbose");
//Pre-Body data setup
var metaData = new MetaDataModel();
metaData.type = "SP.Folder";
//Body data setup
var bodyModel = new ExpandoObject() as IDictionary<string, object>;
bodyModel.Add("__metadata", metaData);
bodyModel.Add("ServerRelativeUrl", location + "/" + directoryName + "/");
//Set content headers
HttpContent strContent = new StringContent(JsonConvert.SerializeObject(bodyModel));
strContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
strContent.Headers.ContentType.Parameters.Add(new NameValueHeaderValue("odata", "verbose"));
// Send request, grab response
var response = await client.PostAsync(sharePointEndpoint, strContent);
//Return response message
return response;
It turns out I needed to use Content-Length header when sending the request, once done I was able to successfully communicate with sharepoint without encountering this error.
More information here: https://social.technet.microsoft.com/Forums/en-US/26459f1c-945d-4112-9200-69c5a33a37ff/sharepoint-online-rest-api-returns-http-error-400-a-request-header-field-is-too-long?forum=sharepointdevelopment
Thanks.

RestSharp PUT request parameters

I'm having issues figuring out how to create a put request using RestSharp.
I need to pass an integer followed by a JSON body in the same request.
So far I have this:
for (var i = 0; i < ReorderedTasks.Count; i++) {
var reorderedTasksJson = new JavaScriptSerializer().Serialize(ReorderedTasks[i]);
var request = new RestRequest("api/task/5/{ID}/", Method.PUT);
request.AddParameter("ID", ReorderedTasks[i].ID.ToString(), ParameterType.UrlSegment);
request.AddParameter("application/json; charset=utf-8", reorderedTasksJson, ParameterType.RequestBody);
client.Execute(request);
}
I've tested out the JSON ad requestBody on POST and it works fine. I think my issue is with the first parameter I'm trying to pass ReorderedTasks[i].ID , I'm not sure if I'm handling the passing of this correctly.
I've initialised client at the beginning of my class.
Problem is the DB isn't updating and I need to isolate the problem. Is the above the correct way in dealing with my two parameters needing passed?
I suggest to put ReorderedTasks[i].ID.ToString() directly to url path.
var request = new RestRequest($"api/task/5/{ReorderedTasks[i].ID.ToString()}/", Method.PUT);
It will help to reduce possible problems with http request format.
I'll add it here, so someone will benefit from it.
If your endpoint URL have parameters like ?param=value&param2=value that you want to pass along with request RestSharp's AddParameter(string, string) won't work with PUT method (but it works just fine with GET or if endpoint doesn't have URL parameters, so it is deceiving)
Use AddParameter(string, string, ParameterType.QueryString) in order to PUT Method work correctly.
Well it depends on what does the webApi expect..
You could use Fiddler to inspect what being sent through the wire and what response You are getting (http://www.telerik.com/fiddler)
Also - here are some sample's how other users use RestSharp
How do I use PUT in RestSharp?

Converting PHP array to C# when calling API

I've looked at several related examples on SO and tried a number of methods to get this to work, but I become more confused with each attempt.
I'm trying to search through the Wordpress.org plugin repository API and get a list of plugins from the search results.
The endpoint is: http://api.wordpress.org/plugins/info/1.0/
The two important bits of data to pass are "action" and "search." The action I'm interested in at the moment is "query_plugins", and passing a search string along in the request.
This is a PHP equivalent:
$payload = array(
'action' => 'query_plugins',
'request' => serialize(
(object)array(
'search ' => 'search-phrase',
)
)
);
$body = wp_remote_post( 'http://api.wordpress.org/plugins/info/1.0/', array( 'body' => $payload) );
The only real documentation I've been able to find is from this blog post (which is where I got the above sample code): https://dd32.id.au/projects/wordpressorg-plugin-information-api-docs/
I'm using RestSharp to build the request, with code along these lines:
var client = new RestClient("http://api.wordpress.org/");
var request = new RestRequest("plugins/info/1.0", Method.POST);
request.AddParameter("XXX", "XXX");
var response = client.Execute(request);
var content = response.Content;
the "request.AddParameter("XXX", "XXX"); above is where I'm stuck. I need to build the PHP array equivalent in C# (and serialize it properly?) so that the API will accept the request. I've tried several variants and combinations, from everything as primitive as:
request.AddParameter("action", "query_plugins");
request.AddParameter("search", "keyword");
// and variants such as request.AddParameter("request", "[{ search: keyword }]);
Which I knew wouldn't work (but took a stab with anyway), to using a Dictionary() with the action and search parameters, and attempting to serialize it in several ways (most recent involved JsonConvert.SerializeObject).
At this point I don't know which tree I should be barking up, I have a feeling I'm not even in the right vicinity. I'm not even sure if I should be serializing to JSON, XML, or just a byte-stream (as I understand that's what the PHP serialize() method does, if I'm not mistaken), and I'm not sure the best approach to package all of the data I need to send off in the request.
This seems to work. Instead of POST, use GET
See the working sample here..
https://dotnetfiddle.net/rvL9eC
var client = new RestClient("http://api.wordpress.org/");
var request = new RestRequest("plugins/info/1.0", Method.GET);
request.AddParameter("action", "query_plugins");
request.AddParameter("search", "oauth");
var response = client.Execute(request);
var content = response.Content;

Deserializing a local xml file using Rest Sharp

I have no problem deserializing an xml into my class while using the following code. I was wondering if it was possible to use the same code on a local file, as our source files are saved locally for archival purposes and are occasionally reprocessed.
This works for remote xml but not for local xml:
RestRequest request = new RestRequest();
var client = new RestClient();
//doesnt work
client.BaseUrl = directory;
request.Resource = file;
//works
client.BaseUrl = baseURL;
request.Resource = url2;
IRestResponse<T> response = client.Execute<T>(request);
return response.Data;
Is there a way to use RestSharp from a local file? I was going to try to use the same function regardless of whether the xml is local or remote and just pass it the location of the xml to read.
This is in fact possible using built in JsonDeserializer class as below. I have used this method to stub API response for testing.
// Read the file
string fileContents = string.Empty;
using (System.IO.StreamReader reader = new System.IO.StreamReader(#"C:\Path_to_File.txt"))
{
fileContents = rd.ReadToEnd();
}
// Deserialize
RestResponse<T> restResponse = new RestResponse<T>();
restResponse.Content = fileContents;
RestSharp.Deserializers.JsonDeserializer deserializer = new RestSharp.Deserializers.JsonDeserializer();
T deserializedObject = deserializer.Deserialize<T>(restResponse);
This is not possible with standard functionality. For example "file://" URLs do not work with RestSharp.
I would recommend using RestSharp do get the returned data from a Uri and having another function to deserialize this data into an object.
You can use the same funcion then to deserialize from file data.
RestSharp is a library to do REST calls, not to deserialize from arbitrary sources. Even if there is a possibility to make RestSharp believe it is talking to a website instead of a file, it would be a hack.
If you need it you could still use the XmlDeserializer from RestSharp. It expects a IRestResponse object, but it only uses the Content property from it, so it should be easy to create. It still feels like a hack though and there are more than enough other XmlSerializers out there that will do a great job

Desk.com and RestSharp (oAuth)

This feels like it should be easy but...it's not. It definitely doesn't help that there's no library for Desk.com, and the documentation is (in my opinion) extremely thin and lacking.
Anyway, I'm trying to use RestSharp to do something simple: grab recent cases. I'm using the Single Access Token method as we don't need to interact as any of our users.
Here's the code:
var client = new RestClient();
client.Authenticator = RestSharp.Authenticators.OAuth1Authenticator.ForProtectedResource("key","secret","token","token secret");
client.BaseUrl = "http://xxx.desk.com/api/v1/";
var request = new RestRequest();
request.Method = Method.GET;
request.Resource = "cases.json?count=10&status=new";
request.RequestFormat = DataFormat.Json;
var result = client.Execute(request);
Result always just says the auth request was invalid and is unauthorized. Tried a bunch of different combinations, looked through the tests that are part of the RestSharp library, and read every meager word of the Desk.com documentation. Just not sure what to try next.
You may have figured this out already, but you get that unauthorized message when you try to add the querystring to the RestRequest's Resource.
I was having the same problem. Daniel's "account/verify_credentials.json" worked for me too, so that's when I started to wonder if it had something to do with the querystring.
var request = new RestRequest();
request.Method = Method.GET;
request.Resource = "cases.json";
request.RequestFormat = DataFormat.Json;
request.AddParameter("count", 10);
request.AddParameter("status", "new");
I just wanted to say, that after following a lot of examples on making the Desk API work with C#, yours was actually the only one that did work.
I did not test with the resource you specified above, but used your code together with the "account/verify_credentials.json" resource. It returns an OK response for me, so your code works. So, first of all...thank you :)
Second (sorry if I am stating the obvious), I assume that you do not use the ("key", "secret", "token", "token secret") parameters as you specified them here, but use valid ones. You most probably do, but mayyybe there is a small chance that you may have found and copied that piece of code from somewhere else, and perhaps missed filling in your info.
EDIT: Since my first answer, I have put together a small (really small) SDK that can be used to connect to and work with the API in C#. You can grab the source code here: http://danielsaidi.github.com/desk-csharp-sdk/
Hope you get it to work.

Categories

Resources