Formatting of multipart HTTP request body output with restsharp - c#

I am creating a restsharp request in order to trigger a batch direct send push request off to Azure notification hub.
I am receiving a 400 Bad Request response, with the message; Could not find 'notifications' part in the multipart content supplied.
The request looks like such;
const string multipartContentType = "multipart/form-data; boundary=\"simple-boundary\"";
const string authSignature = "myvalidauthsignature";
const string url = "mynotificanhuburl";
const string message = "Some message";
var restClient = new RestClient
{
BaseUrl = new Uri(url),
Proxy = new WebProxy("127.0.0.1", 8888),
};
var request = new RestSharp.RestRequest(Method.POST)
{
RequestFormat = DataFormat.Json,
AlwaysMultipartFormData = true
};
request.AddHeader("Content-Type", multipartContentType);
request.AddHeader("Authorization", authSignature);
request.AddHeader("ServiceBusNotification-Format", "gcm");
request.AddParameter("notification", JsonConvert.SerializeObject(new { data = new { message } }), ParameterType.GetOrPost);
request.AddParameter("devices", JsonConvert.SerializeObject(new List<string> { "123", "456" }), ParameterType.GetOrPost);
var response = restClient.Execute(request);
I can see the raw request via Fiddler;
POST https://xxxxx.servicebus.windows.net/xxx/messages/$batch?direct&api-version=2015-04 HTTP/1.1
Authorization: [redacted]
ServiceBusNotification-Format: gcm
Accept: application/json, application/xml, text/json, text/x-json, text/javascript, text/xml
User-Agent: RestSharp/105.2.3.0
Content-Type: multipart/form-data; boundary=-----------------------------28947758029299
Host: [redacted]
Content-Length: 412
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
-------------------------------28947758029299
Content-Disposition: form-data; name="notification"
{"data":{"message":"Some message"}}
-------------------------------28947758029299
Content-Disposition: form-data; name="devices"
["123","456"]
-------------------------------28947758029299--
Which looks about right. If I copy this into postman with the headers etc, I can see the same error response. HOWEVER in postman when I remove the quote marks around the parameter names, it works and returns a 201 Created response.
So this works....
Content-Disposition: form-data; name=notification
This doesn't
Content-Disposition: form-data; name="notification"
Which seems really peculiar. As we are using restsharp however I don't think I have any direct control over the raw output for the request body. I am wondering;
Is there a restsharp setting to manage these quote, perhaps a formatting setting
Why would the Azure endpoint reject a parameter name with quotes
It is possible that the issue is elsewhere and this is a red herring, but this does seem to be responsible.
Appreciate any help...

According our documentation, request should look like this:
POST https://{Namespace}.servicebus.windows.net/{Notification Hub}/messages/$batch?direct&api-version=2015-08 HTTP/1.1
Content-Type: multipart/mixed; boundary="simple-boundary"
Authorization: SharedAccessSignature sr=https%3a%2f%2f{Namespace}.servicebus.windows.net%2f{Notification Hub}%2fmessages%2f%24batch%3fdirect%26api-version%3d2015-08&sig={Signature}&skn=DefaultFullSharedAccessSignature
ServiceBusNotification-Format: gcm
Host: {Namespace}.servicebus.windows.net
Content-Length: 431
Expect: 100-continue
Connection: Keep-Alive
--simple-boundary
Content-Type: application/json
Content-Disposition: inline; name=notification
{"data":{"message":"Hello via Direct Batch Send!!!"}}
--simple-boundary
Content-Type: application/json
Content-Disposition: inline; name=devices
["Device Token1","Device Token2","Device Token3"]
--simple-boundary--
So, the name parameter's value is not quoted (name=devices). I've not found any RFC which would explicitly specify requirements regarding the situation. However, in examples inside of RFCs a values appear quoted. And because of that I'm going to fix the service to support both options. Fix should come with next deployment in a week or so.

I was plagued by this for a few days and was diligently searching for a solution with RestSharp and was unable to find one as it always default the content type to "multipart/form-data". I know the OP was looking for a way to do this with RestSharp but I don't believe there is currently.My solution comes from a few different posts over a few days so I apologize for not linking to them. Below is a sample Function to perform a multipart/related POST with json body and base64 pdf string as the file.
public static void PostBase64PdfHttpClient(string recordID, string docName, string pdfB64)
{
string url = $"baseURL";
HttpClient client = new HttpClient();
var myBoundary = "------------ThIs_Is_tHe_bouNdaRY_";
string auth = Convert.ToBase64String(Encoding.UTF8.GetBytes($"UN:PW"));
client.DefaultRequestHeaders.Add("Authorization", $"Basic {auth}");
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, $"{url}/api-endpoint");
request.Headers.Date = DateTime.UtcNow;
request.Headers.Add("Accept", "application/json; charset=utf-8");
MultipartContent mpContent = new MultipartContent("related", myBoundary);
mpContent.Headers.TryAddWithoutValidation("Content-Type", $"multipart/related; boundary={myBoundary}");
dynamic jObj = new Newtonsoft.Json.Linq.JObject(); jObj.ID = recordID; jObj.Name = docName;
var jsonSerializeSettings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore };
var json = JsonConvert.SerializeObject(jObj, jsonSerializeSettings);
mpContent.Add(new StringContent(json, Encoding.UTF8, "application/json"));
mpContent.Add(new StringContent(pdfB64, Encoding.UTF8, "application/pdf"));
request.Content = mpContent;
HttpResponseMessage response = client.SendAsync(request).Result;
}

Related

What is the equivalent HttpClient JSON POST to this RestClient JSON POST?

Given:
Uri location = ...; // Remote 3rd party HTTP Rest API
string body = "SOME JSON";
The following RestClient code generates HTTP traffic that is accepted by the server.
var client = new RestClient(location);
var request = new RestRequest(Method.POST);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("content-type", "application/json; charset=utf-8");
request.AddParameter("application/json; charset=utf-8", body,
ParameterType.RequestBody);
var restResponse = client.Execute(request);
However, the HttpClient code below must be generating different HTTP traffic (indicated by the server rejecting the request).
using (var client = new HttpClient())
{
var request = new HttpRequestMessage();
request.Method = HttpMethod.Post;
request.RequestUri = location;
var bodyContent = new StringContent(body, Encoding.UTF8, "application/json");
request.Content = bodyContent;
request.Headers.Add("cache-control", "no-cache");
client.Timeout = TimeSpan.FromMinutes(5.0);
var response = await client.SendAsync(request);
}
Why is the HttpClient code serializing differently?
A simple way to find the precise differences is to run Fiddler or another debugging proxy and check the raw request. Here's what I got with HttpClient:
POST http://example.com/ HTTP/1.1
cache-control: no-cache
Content-Type: application/json; charset=utf-8
Host: example.com
Content-Length: 4
Expect: 100-continue
Connection: Keep-Alive
test
And with RestSharp:
POST http://example.com/ HTTP/1.1
cache-control: no-cache
Content-Type: application/json; charset=utf-8
Accept: application/json, text/json, text/x-json, text/javascript, application/xml, text/xml
User-Agent: RestSharp/106.6.9.0
Host: example.com
Content-Length: 4
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
test
Your results may differ depending on your system configuration, versions etc., so you should try it yourself to make sure.

Make POST request

I'm trying to post to a web form defined as:
<form name="frmdata" method='post' enctype ='multipart/form-data' action ="http://www.rzp.cz/cgi-bin/aps_cacheWEB.sh">
<input type ="hidden" name ="VSS_SERV" value="ZVWSBJXML">
<input type="file" name="filename">
<input type ='submit' name ='x' value ='ODESLI'>
</form>
There is some additional documentation on the form here:
http://www.rzp.cz/docs/RZP02_XML_28.pdf
My latest try:
using (WebClient client = new WebClient())
{
NameValueCollection vals = new NameValueCollection();
vals.Add("VSS_SERV", "ZVWSBJXML");
string filecontent = #"<?xml version=""1.0"" encoding=""ISO-8859-2""?>";
filecontent = filecontent + #"
<VerejnyWebDotaz
elementFormDefault=""qualified""
targetNamespace=""urn:cz:isvs:rzp:schemas:VerejnaCast:v1""
xmlns=""urn:cz:isvs:rzp:schemas:VerejnaCast:v1"" version=""2.8"">";
filecontent = filecontent + #"
<Kriteria>
<IdentifikacniCislo>03358437</IdentifikacniCislo>
<PlatnostZaznamu>0</PlatnostZaznamu></Kriteria>";
filecontent = filecontent + #"</VerejnyWebDotaz>";
vals.Add("filename", filecontent);
client.Headers["ContentType"] = "multipart/form-data";
byte[] responseArray = client.UploadValues(#"http://www.rzp.cz/cgi-bin/aps_cacheWEB.sh", "POST", vals);
string str = Encoding.ASCII.GetString(responseArray);
}
But I can't get past this error:
<KodChyby>-1</KodChyby> (the xml filename does not contain xml defined by namespace)
How can I send this xml data to the form or rather there is a working form - http://stuff.petrovsky.cz/subdom/stuff/RZP/rzp-test-form.php - how to call and catch xml data? I would like to do the same request and get xml.
Using System.Net.Http I was able to construct the form request as a proof of concept using MultipartFormDataContent
Now initially when I tested it, I received 403 Forbidden response but I guessed that was to be expected given my location and that the endpoint might be region locked.
Raw Fiddler response
HTTP/1.1 403 Forbidden
Date: Sat, 27 Oct 2018 01:37:09 GMT
Server: IIS
Content-Length: 225
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=iso-8859-1
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>403 Forbidden</title>
</head><body>
<h1>Forbidden</h1>
<p>You don't have permission to access /cgi-bin/aps_cacheWEB.sh
on this server.</p>
</body></html>
I was wrong and the forbidden appeared to be the default response for bad requests as you commented that you received the same forbidden error from within the region. So back to the drawing board I went.
I then copied the example HTML form locally and then proceeded to compare the requests from the form (which did actually work) and my code. Gradually making changes to match I was finally able to get a 200 OK response, but the body of the response was empty.
Apparently there was an issue with the server interpreting the boundary in the content type header if it is wrapped in quotes boundary="...".
After more adjustments it then started returning a message based on the content dispositions generated.
HTTP/1.1 200 OK
Date: Sat, 27 Oct 2018 19:55:11 GMT
Server: IIS
Serial: 10.145
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/plain; charset=ISO-8859-2
Content-Length: 169
Multiple definitions of VSS_SERV encountered in input.
If you're trying to do this intentionally (such as with select),
the variable must have a "List" suffix.
So it turns out that the XML API is expecting the request to be in a very specific format. Deviate from that and the request fails.
The MultipartFormDataContent was not generating the request correctly and this caused the server to not behave as expected. Other headers were being placed before the Content-Disposition headers of the parts and the Content-Disposition parameters were also not being enclosed in quotes. So by not including the content-type it in the parts and making sure the content-disposition headers were generated correctly eventually fixed the problem.
It is important to note the order of how the headers are added to the content so that the Content-Disposition header is set first for each part.
Working Code that generates the request in the desired format and gets the XML data.
[Test]
public async Task Post_Form() {
//Arrange
var stream = getXml();
var fileContent = new StreamContent(stream);
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") {
Name = #"""filename""",
FileName = #"""req-details.xml""",
};
fileContent.Headers.ContentType = new MediaTypeHeaderValue("text/xml");
var stringContent = new ByteArrayContent(Encoding.UTF8.GetBytes("ZVWSBJXML"));
stringContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") {
Name = #"""VSS_SERV""",
};
//could have let system generate it but wanteed to rule it out as a problem
var boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x", NumberFormatInfo.InvariantInfo);
var form = new MultipartFormDataContent(boundary);
//FIX: boundary quote issue
var contentType = form.Headers.ContentType.Parameters.First(o => o.Name == "boundary");
contentType.Value = contentType.Value.Replace("\"", String.Empty);
form.Add(stringContent);
form.Add(fileContent);
//var data = await form.ReadAsStringAsync(); //FOR TESTING PORPOSES ONLY!!
var client = createHttpClient("http://www.rzp.cz/");
//Act
var response = await client.PostAsync("cgi-bin/aps_cacheWEB.sh", form);
var body = await response.Content.ReadAsStringAsync();
//Assert
response.IsSuccessStatusCode.Should().BeTrue();
body.Should().NotBeEmpty();
var document = XDocument.Parse(body); //should be valid XML
document.Should().NotBeNull();
}
The code above generated the following request, which I extracted using fiddler (Pay close attention to the working format)
POST http://www.rzp.cz/cgi-bin/aps_cacheWEB.sh HTTP/1.1
User-Agent: System.Net.Http.HttpClient
Accept-Language: en-US, en; q=0.9
Accept: text/xml, application/xml
Cache-Control: max-age=0
Content-Type: multipart/form-data; boundary=---------------------------8d63c301f3e044f
Host: www.rzp.cz
Content-Length: 574
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
-----------------------------8d63c301f3e044f
Content-Disposition: form-data; name="VSS_SERV"
ZVWSBJXML
-----------------------------8d63c301f3e044f
Content-Disposition: form-data; name="filename"; filename="req-details.xml"
Content-Type: text/xml
<?xml version="1.0" encoding="iso-8859-2"?>
<VerejnyWebDotaz xmlns="urn:cz:isvs:rzp:schemas:VerejnaCast:v1" version="2.8">
<Kriteria>
<IdentifikacniCislo>75848899</IdentifikacniCislo>
<PlatnostZaznamu>0</PlatnostZaznamu>
</Kriteria>
</VerejnyWebDotaz>
-----------------------------8d63c301f3e044f--
Which was able to get the following response.
HTTP/1.1 200 OK
Date: Sat, 27 Oct 2018 21:17:50 GMT
Server: IIS
Serial: 10.145
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/xml;charset=ISO-8859-2
Content-Length: 931
<?xml version='1.0' encoding='iso-8859-2'?>
<VerejnyWebOdpoved xmlns="urn:cz:isvs:rzp:schemas:VerejnaCast:v1" version="2.8">
<Datum>27.10.2018</Datum>
<Kriteria>
<IdentifikacniCislo>75848899</IdentifikacniCislo>
<PlatnostZaznamu>0</PlatnostZaznamu>
</Kriteria>
<PodnikatelSeznam>
<PodnikatelID>212fbf8314e01506b0d7</PodnikatelID>
<ObchodniJmenoSeznam Popis="Jméno a příjmení:">Filip Zrůst</ObchodniJmenoSeznam>
<IdentifikacniCisloSeznam Popis="Identifikační číslo osoby:">75848899</IdentifikacniCisloSeznam>
<TypPodnikatele Popis="Typ podnikatele:">Fyzická osoba</TypPodnikatele>
<AdresaPodnikaniSeznam Popis="Adresa sídla:">Vlašská 358/7, 118 00, Praha 1 - Malá Strana</AdresaPodnikaniSeznam>
<RoleSubjektu Popis="Role subjektu:">podnikatel</RoleSubjektu>
<EvidujiciUrad Popis="Úřad příslušný podle §71 odst.2 živnostenského zákona:">Úřad městské části Praha 1</EvidujiciUrad>
</PodnikatelSeznam>
</VerejnyWebOdpoved>
From there it should be small work to parse the resulting XML as needed.
Supporting code
Generate or load the stream of the XML for the form
private static Stream getXml() {
var xml = #"<?xml version=""1.0"" encoding=""ISO-8859-2""?>
<VerejnyWebDotaz
xmlns=""urn:cz:isvs:rzp:schemas:VerejnaCast:v1""
version=""2.8"">
<Kriteria>
<IdentifikacniCislo>75848899</IdentifikacniCislo>
<PlatnostZaznamu>0</PlatnostZaznamu>
</Kriteria>
</VerejnyWebDotaz>";
var doc = XDocument.Parse(xml);//basically to validate XML
var stream = new MemoryStream();
doc.Save(stream);
stream.Position = 0;
return stream;
}
Was gradually able to whittle down the headers needed for a successful request after find the match that worked. Try removing others gradually to test if more can be removed safely to reduce the amount of unnecessary code needed.
private static HttpClient createHttpClient(string baseAddress) {
var handler = createHandler();
var client = new HttpClient(handler);
client.BaseAddress = new Uri(baseAddress);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "System.Net.Http.HttpClient");
client.DefaultRequestHeaders.TryAddWithoutValidation("Accept-Language", "en-US,en;q=0.9");
client.DefaultRequestHeaders.TryAddWithoutValidation("Accept", "text/xml,application/xml");
client.DefaultRequestHeaders.ExpectContinue = false;
client.DefaultRequestHeaders.ConnectionClose = false;
client.DefaultRequestHeaders.CacheControl = new CacheControlHeaderValue() {
MaxAge = TimeSpan.FromSeconds(0)
};
return client;
}
private static HttpClientHandler createHandler() {
var handler = new HttpClientHandler();
// if the framework supports automatic decompression set automatic decompression
if (handler.SupportsAutomaticDecompression) {
handler.AutomaticDecompression = System.Net.DecompressionMethods.GZip |
System.Net.DecompressionMethods.Deflate;
}
return handler;
}
While I chose to use the asynchronous API of System.Net.Http, I found a similar question
Reference UploadFile with POST values by WebClient
With an answer that was done using WebClient that could be adapted to your question so that a request can be constructed similar to what was produced above.
I tried testing that one as well but got into the same forbidden error. Now that the correct format is know you should also be able to correctly craft a working request using WebClient/WebRequest

Batch request - Dynamics CRM

All,
I am trying to implement a batch request to Dynamics CRM with the following source code:
public async Task<HttpResponseMessage> HttpPatchCrmApi(string resource, string data)
{
string uniq = Guid.NewGuid().ToString();
MultipartContent content = new MultipartContent("mixed", "batch_" + uniq);
HttpRequestMessage batchRequest = new HttpRequestMessage(HttpMethod.Post, CrmBaseUrl + "/api/data/v8.0/$batch");
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, CrmBaseUrl + resource);
request.Content = new StringContent(data, Encoding.UTF8, "application/json");
HttpMessageContent query = new HttpMessageContent(request);
content.Add(query);
batchRequest.Content = content;
HttpResponseMessage response = await RbWebApi.SendAsync(batchRequest);
return response;
}
The problem is that I am getting "400 Bad request"
EDIT:
As suggested in the comments here is the stack trace of the request from fiddler:
POST https://Hidden.api.crm4.dynamics.com/api/data/v8.0/$batch HTTP/1.1
Authorization: Bearer eyJ0eXAiOiJKV.... very long string
Content-Type: multipart/mixed; boundary="batch_7b6e3c60-1284-4958-a39a-4653af21833c"
Host: Hidden.api.crm4.dynamics.com
Content-Length: 313
Expect: 100-continue
--batch_7b6e3c60-1284-4958-a39a-4653af21833c
Content-Type: application/http; msgtype=request
POST /api/data/v8.0/my_recurringgifts HTTP/1.1
Host: Hidden.api.crm4.dynamics.com
Content-Type: application/json; charset=utf-8
{"my_name":"slavi"}
--batch_7b6e3c60-1284-4958-a39a-4653af21833c--
While writing the code I was inspiring myself from here and here
I think your request is wrong.
You must build the request Body EXACTLY like defined by Microsoft
This means the Blank lines must be there at the right place all the attributes must exist in the body (like "--changeset_XXX" for example) and as I see you dont meet this requirements.
I just build a Request in Postman against my CRM and it worked:
URL
https://yourTenant.api.crm.dynamics.com/api/data/v8.0/$batch
Headers
OData-MaxVersion:4.0
OData-Version:4.0
Accept:application/json
Authorization:Bearer aVeryLongStringTokenHere
Content-Type: multipart/mixed;boundary=batch_1234567
Body
--batch_1234567
Content-Type:multipart/mixed;boundary=changeset_555666
--changeset_555666
Content-Type:application/http
Content-Transfer-Encoding:binary
Content-ID:1
POST https://yourTenant.api.crm.dynamics.com/api/data/v8.0/accounts HTTP/1.1
Content-Type:application/json;type=entry
{name: 'BatchJobTest788'}
--changeset_555666
Content-Type:application/http
Content-Transfer-Encoding:binary
Content-ID:2
POST https://yourTenant.api.crm.dynamics.com/api/data/v8.0/accounts HTTP/1.1
Content-Type:application/json;type=entry
{new_name: 'BatchJobTest348'}
--changeset_555666--
--batch_1234567--
Additional Remarks:
The Content-Type of your Header holds your BatchId
The Content-Type of your Batch holds your ChangesetId (if it is a change to data)
Before starting to programm REST calls try to define them in a REST tool like POSTMAN and make them work. Then build the working request in your code.
Here a good explanation-source for the batching in CRM

How to flash a spark core from C#

I am trying to flash a spark core from a C# application. I keep getting { error: Nothing to do? } response.
Below is my code
var url = string.Format("https://api.spark.io/v1/devices/{0}", sparkDeviceID);
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accesstoken);
using (var formData = new MultipartFormDataContent())
{
HttpContent fileContent = new ByteArrayContent(Encoding.ASCII.GetBytes(rom));
//client.SendAsync()
formData.Add(fileContent, "file", "file");
var response = client.PutAsync(url, formData).Result;
if (!response.IsSuccessStatusCode)
throw new Exception("An error occurred during rom flash!");
var responseStream = response.Content.ReadAsStreamAsync().Result;
using (var reader = new StreamReader(responseStream, true))
{
var result = reader.ReadToEnd();
}
}
return true;
}
The documentation reads:
The API request should be encoded as multipart/form-data with a file field populated.
I believe the problem is the endpoint doesn't see the file. Any idea on how to resolve this?
Finally got it working.
The issue was the way .NET generated the content-disposition header for the file form data.
I used fiddler to compare the output of a successful put request to the put request that my code was generating:
Successful PUT request generated using CURL:
PUT http://127.0.0.1:8888/ HTTP/1.1
User-Agent: curl/7.33.0
Host: 127.0.0.1:8888
Accept: */*
Content-Length: 2861
Expect: 100-continue
Content-Type: multipart/form-data; boundary=------------------------5efcf64a370f13c8
--------------------------5efcf64a370f13c8
Content-Disposition: form-data; name="file"; filename="ms.ino"
Content-Type: application/octet-stream
...
My PUT request (unsuccessful):
PUT https://api.spark.io/v1/devices/{deviceid} HTTP/1.1
Authorization: Bearer {access_token}
Content-Type: multipart/form-data; boundary="135f5425-9342-4ffa-a645-99c04834026f"
Host: api.spark.io
Content-Length: 2878
Expect: 100-continue
--135f5425-9342-4ffa-a645-99c04834026f
Content-Type: application/octet-stream
Content-Disposition: form-data; name=file; filename=file.ino; filename*=utf-8''file.ino
...
If you'll notice the difference in the Content-Type for the actual file being sent:
Successful: Content-Disposition: form-data; name="file"; filename="ms.ino"
Unsuccessful: Content-Disposition: form-data; name=file; filename=file.ino; filename*=utf-8''file.ino
Most specifically, the resolution was to add quotes around the name attribute.
Resolution:
formData.Add(fileContent, "\"file\"", "file.ino");

RestClient DELETE Operation Json Error

I'm trying to make a Delete action with RestClient but I'm not able to include my Json object inside the request body. This is my code:
var client = new RestClient(WebService);
var request = new RestRequest(string.Format("/api/v1/{0}/{1}", controller, action), method);
request.AddHeader("Accept", ContentTypeApplicationJson);
request.RequestFormat = DataFormat.Json;
request.AddHeader("Content-Type", ContentTypeApplicationJson);
request.AddCookie(".ASPXAUTH", AspxAuth);
request.AddBody(jsonObjectRequest);
var response = client.Execute(request);
var jsonResponse = string.Empty;
using (var stream = new MemoryStream(response.RawBytes))
{
stream.Position = 0;
var sr = new StreamReader(stream);
jsonResponse = sr.ReadToEnd();
}
var jObjectDeserialize = GetJObjectDeserialize(jsonResponse);
In my example ContentTypeApplicationJson = application/json and jsonObject is a object which contain:
{
"BasketItemReferenceGuid": "sample string 1",
"BasketReferenceGuid": "sample string 2"
}
This is my request in Fiddler
DELETE http://local.webapi.com/api/v1/BasketV3Products/ HTTP/1.1
Accept: application/json
Content-Type: application/json
User-Agent: RestSharp 102.4.0.0
Host: local.webapi.com
Cookie: .ASPXAUTH=E6D216034E2CB1A22466A501392B1E2E46601E345B8A0E7743D76CF2270ACFC8ED3C9F1F2F477C4499267222A250E4490291381EE68FE719E094EF1ACDD619B4D792341988F80CB67E8B5037D8ACF9FBABB74DE1E75A530AB432D85722D647771C6C576F8E810257CE9E60117DCEEFBD949EAD9E64C84898BDC5D691F957CE6266CF5652C693B86ED1D55907AAC5DC68
Content-Length: 0
Accept-Encoding: gzip, deflate
Thanks
It looks like even though the HTTP spec doesn't explicitly say that a DELETE should not have a body, many web servers (or web proxies) will ignore it.
Semantically, when using DELETE, the uri should identify the resource to DELETE. This is kind of like using GET. Again, with GET, the spec does not forbid a body, but not many web servers (or web proxies) actually support a body on GET requests.
For more info, see this SO post.
So, the better way to implement your DELETE would be to place BasketItemReferenceGuid and BasketReferenceGuid in the uri template.

Categories

Resources