/POST a gzipped body to an ASP.NET Web API application host - c#

Problem:
Web API 2.2 Controller won't deserialize a POST body that is gzipped; deserializes without issue if the body is not Encoded.
Question
Why will my DelegatingHandler not pick up when a POST body is gzipped
Anecdote:
Let's say I have 2 services (A and B) that represent a sequence.
+GET/A returns A'
+POST/B requires A' and returns B'
A.cs
public class AController : ApiController
{
[HttpGet]
[Route("A")]
public HttpResponseMessage GetA()
{
APrime _aprime = new APrime("A'");
return Request.CreateResponse(HttpStatusCode.OK, new[]{_aprime});
}
}
B.cs
public class BController : ApiController
{
[HttpPost]
[Route("B")]
public HttpResponseMessage PostAReturnB([FromBody]IEnumerable<APrime> aprime)
{
if(aprime == null)return Request.CreateResponse(HttpStatusCode.BadRequest, "aprime required");
BPrime _bprime = new BPrime("B'");
return Request.CreateResponse(HttpStatusCode.OK, new[]{_bprime});
}
}
No Delegating Handler
Unencoded Communication
/GET+http://localhost:8880/A
Accept: application/json
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 20257
[{...A'...}]
/POST+http://localhost:8880/B
Accept: application/json
Content-Type: application/json
Content-Length: 20257
[{...A'...}]
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 59466
[{...B'...}]
Encoded Communication
/GET+http://localhost:8880/A
Accept: application/json
Accept-Encoding: gzip
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 4000
<binary data representing a gzip encoded "A'">
/POST+http://localhost:8880/B
Accept: application/json
Content-Type: application/json
Content-Length: 4000
Content-Encoding: gzip
<binary data representing a gzip encoded "A'">
HTTP/1.1 400 Bad Request
Content-Type: application/json; charset=utf-8
Content-Length: 15
aprime required
With a Delegating Handler
public class MyRequestHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (request.Method == HttpMethod.Post)
{
//Do Stuff that checks if the body is compressed.
//Decompress it
}
return base.SendAsync(request, cancellationToken);
}
}
Unencoded Communication
Handler is invoked, service fires normally
Encoded Communication
Handler never fires. Fiddler displays a 504
I thought I had an A-Ha when it finally dawned on me that I was passing my Response bodies through my clipboard, so I tried to implement a custom rule in Fiddler to perform the gzip compression on the clear body content.
if(oSession.requestBodyBytes != null && (oSession.oRequest.headers.Exists("Client.Request-Encoding")))
{
oSession["ui-italics"] = "true";
if(oSession.oRequest["Client.Request-Encoding"] == "gzip")
{
oSession.requestBodyBytes = Utilities.GzipCompress(oSession.requestBodyBytes);
oSession["Content-Length"] = oSession.requestBodyBytes.Length.ToString();
oSession.oRequest["Client.CustomRule"] = "[Fiddler][Custom Rule.GZip]";
oSession["ui-color"] = "green";
oSession["ui-italics"] = "false";
oSession["ui-bold"] = "true";
}else{
oSession["ui-color"] = "crimson";
oSession["ui-italics"] = "true";
oSession.oRequest["Client.Request-Encoding.Error"] = "Rule not processed. gzip is the only supported Request-Encoding value";
}
}
My requests that process through this rule just go off into the nether.

Related

C# .NET 7 - How to connect to WCF service using HTTPS and cookie authentication

I am struggling with this for weeks now, tried everything I could find on internet, but nothing works.
Biggest problems is - it works seamlessly in .NET 4.8 with default WCF scaffold, however .NET Core has WCF reworked and this one I can not figure out.
So, the authentication process has three parts.
Get XSFR token from web page, this is simple HttpClient.GetAsync towards web page which returns XSFR cookie in response.
Get SessionID by calling REST auth method, also simple and works with HttpClient.PostAsync.
Call HTTPS WCF service by sending XSFR token and SessionID as cookies. No go.
I used Visual Studio 2022 (17.4.3) to scaffold wsdl file.
I tried different bindings and I learned that Security.Mode has to be System.ServiceModel.SecurityMode.Transport otherwise I get error that "http" is expected but "https" found in URL and does not work.
However, when I do set security mode to Transport, I get error:
'The HTTP request was forbidden with client authentication scheme 'Anonymous'.'
Anonymous changes depending on Security.Transport.ClientCredentialType.
As for sending cookies, I tried two different methods:
OperationContextScope:
using (new OperationContextScope(port.InnerChannel)) {
var endPoint = new EndpointAddress(Config.URL_APP_ORIGIN);
var httpRequest = new HttpRequestMessageProperty();
httpRequest.Headers.Add(HEADER_X_XSRF_TOKEN, xsrfToken?.Value);
httpRequest.Headers.Add(HttpRequestHeader.Cookie, sessionId?.ToString());
httpRequest.Headers.Add(HttpRequestHeader.Cookie, xsrfToken?.ToString());
OperationContext.Current.OutgoingMessageProperties.Add(HttpRequestMessageProperty.Name, httpRequest);
await IspisVerzije(port);
// await IspisAllowedValues(port);
port.Close();
}
HttpHeaderMessageInspector
// Implementation of partial method in scaffolded web service reference
static partial void ConfigureEndpoint(System.ServiceModel.Description.ServiceEndpoint serviceEndpoint, System.ServiceModel.Description.ClientCredentials clientCredentials) {
var headers = new Dictionary<string, string> {
["HEADER_X_XSRF_TOKEN"] = Program.xsrfToken?.ToString(),
["Cookie"] = "Basic " + Program.sessionId?.ToString(),
["Cookie"] = "Basic " + Program.xsrfToken?.ToString()
};
var behaviour = new AddHttpHeaderMessageEndpointBehavior(headers);
serviceEndpoint.EndpointBehaviors.Add(behaviour);
}
}
public class HttpHeaderMessageInspector : IClientMessageInspector {
private Dictionary<string, string> Headers;
public HttpHeaderMessageInspector(Dictionary<string, string> headers) {
Headers = headers;
}
public void AfterReceiveReply(ref Message reply, object correlationState) { }
public object BeforeSendRequest(ref Message request, IClientChannel channel) {
// ensure the request header collection exists
if (request.Properties.Count == 0 || !request.Properties.ContainsKey(HttpRequestMessageProperty.Name)) {
request.Properties.Add(HttpRequestMessageProperty.Name, new HttpRequestMessageProperty());
}
// get the request header collection from the request
var HeadersCollection = ((HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name]).Headers;
// add our headers
foreach (var header in Headers) HeadersCollection[header.Key] = header.Value;
return null;
}
}
public class AddHttpHeaderMessageEndpointBehavior : IEndpointBehavior {
private IClientMessageInspector HttpHeaderMessageInspector;
public AddHttpHeaderMessageEndpointBehavior(Dictionary<string, string> headers) {
HttpHeaderMessageInspector = new HttpHeaderMessageInspector(headers);
}
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { }
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) {
clientRuntime.ClientMessageInspectors.Add(HttpHeaderMessageInspector);
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { }
public void Validate(ServiceEndpoint endpoint) { }
}
I used Fiddler to inspect outgoing requests and cookies are present in request.
This is raw request sent by working .NET Framework 4.8 version:
POST https://zupit-test.gov.hr/services/integration/v2 HTTP/1.1
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; MS Web Services Client Protocol 4.0.30319.42000)
X-XSRF-TOKEN: 7280e4c2-6dd1-4ed4-9a35-91c22c172dfd
VsDebuggerCausalityData: uIDPo0dR90lQHnFDopiVLjbd/0IAAAAAxYMKfS4zuEWC0d5bf6byLKVx4ImkhWZLr+qCOPCMN3gACQAA
Content-Type: application/soap+xml; charset=utf-8; action=""
Host: zupit-test.gov.hr
Cookie: XSRF-TOKEN=7280e4c2-6dd1-4ed4-9a35-91c22c172dfd; JSESSIONID=B232706D460BE6C5FC5981826B36E9EB; TS01a2529c=01402d66b9a555cd86492a154020763ed07f0c7bbe2dbd6487ca2abfa0cfa1b3c533cde8a1335c973f7c6d5c24cdee6f743a38b5b5c0b26948152fee150d6abba41ea0e8cd
Content-Length: 301
Expect: 100-continue
<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><getVersion xmlns="http://zupit.gov.hr/integration/v2" /></soap:Body></soap:Envelope>
And this is raw request sent by .NET 7 version:
POST https://zupit-test.gov.hr/services/integration/v2 HTTP/1.1
Host: zupit-test.gov.hr
Cache-Control: no-cache, max-age=0
X-XSRF-TOKEN: e62fe08b-e7ea-4fd7-88d7-28f58aa45018
Cookie: JSESSIONID=77C6A62B4A0B62DDDFAD8C534EA9D2A9,XSRF-TOKEN=e62fe08b-e7ea-4fd7-88d7-28f58aa45018
Accept-Encoding: gzip, deflate
Content-Type: application/soap+xml; charset=utf-8
Content-Length: 573
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing"><s:Header><a:Action s:mustUnderstand="1">http://zupit.gov.hr/integration/v2/IntegrationWSv2/getVersionRequest</a:Action><a:MessageID>urn:uuid:3aef24b7-6c08-4a85-bff4-fd0dbcf7ce1d</a:MessageID><a:ReplyTo><a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address></a:ReplyTo><a:To s:mustUnderstand="1">https://zupit-test.gov.hr/services/integration/v2</a:To></s:Header><s:Body><getVersion xmlns="http://zupit.gov.hr/integration/v2"/></s:Body></s:Envelope>
And this is server response for .NET 7 request:
HTTP/1.1 403
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Set-Cookie: XSRF-TOKEN=915dea61-d5a4-4c63-ad85-51f92df31f67; Path=/
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Type: application/json;charset=UTF-8
Date: Thu, 22 Dec 2022 07:42:34 GMT
Strict-Transport-Security: max-age=16070400; includeSubDomains
Set-Cookie: TS01a2529c=01402d66b972abf2e18b994c3e4a4342cb1a60809c602d5bd0ebfb7953d22b3d635225a9b013d6108d2efd22d658d57c1de898f2709b920c1a01fefeda45b6c6746a57884d; Path=/
Transfer-Encoding: chunked
8e
{"timestamp":"2022-12-22T07:42:35.272Z","error":"Forbidden","message":"Forbidden","path":"/services/integration/v2","showServerMessage":false}
0
Is this HTTPS issue or difference of generated SOAP XML in .NET 7?
Any ideas how to solve this?
Thanks,
Mario

How do I post simple JSON data with a file upload?

I'm trying to set up a file upload request in a ServiceStack TypeScript client that also includes the month for which the file is relevant. How do I set up the request so that both come through to the server?
I've tried various changes, including manually changing headers to try to force Content-Type to be application/json, which didn't work (but I suspect would break the file upload even if it did).
Client-side API:
export const serviceApi = {
importData: (month: string, file: File) => {
var client = new JsonServiceClient("");
var request = new DTOs.ImportData();
// At this point, the month has a value
request.month = month.replace('/', '-').trim();
let formData = new FormData();
formData.append('description', file.name);
formData.append('type', 'file');
formData.append('file', file);
const promise = client.postBody(request, formData);
return from(promise);
},
};
DTO definition:
[Route("/api/data/import/{Month}", "POST")]
public class ImportData : IReturn<ImportDataResponse>
{
public string Month { get; set; }
}
public class ImportDataResponse : IHasResponseStatus
{
public ResponseStatus ResponseStatus { get; set; }
}
Server-side API:
[Authenticate]
public object Post(ImportData request)
{
if (Request.Files == null || Request.Files.Length <= 0)
{
throw new Exception("No import file was received by the server");
}
// This is always coming through as null
if (request.Month == null)
{
throw new Exception("No month was received by the server");
}
var file = (HttpFile)Request.Files[0];
var month = request.Month.Replace('-', '/');
ImportData(month, file);
return new ImportDataResponse();
}
I can see that the file is coming through correctly on the server side, and I can see an HTTP request going through with the month set in the query string parameters as "07-2019", but when I break in the server-side API function, the month property of the request is null.
Update, here are the HTTP Request/Response headers:
Request Headers
POST /json/reply/ImportData?month=07-2019 HTTP/1.1
Host: localhost:40016
Connection: keep-alive
Content-Length: 7366169
Origin: http://localhost:40016
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryI8CWlbw4tP80PkpZ
Accept: */*
Referer: http://localhost:40016/data
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8
Cookie: _ga=GA1.1.673673009.1532913806; ASP.NET_SessionId=gtwdk3wsvdn0yulhxyblod3g; __utmc=111872281; __utmz=111872281.1533684260.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); ss-opt=perm; __utma=111872281.673673009.1532913806.1550789161.1550794391.20; _gid=GA1.1.893581387.1558389301; ss-id=kfq4G0GYb3WldSdCaRyJ; ss-pid=aZ400sqM4n3TQgNVnHS2
Response Headers
HTTP/1.1 500 Exception
Cache-Control: private
Content-Type: application/json; charset=utf-8
Vary: Accept
Server: Microsoft-IIS/10.0
X-Powered-By: ServiceStack/5.10 NET45 Win32NT/.NET
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?RTpcVEZTXFNvdXJjZVxNZWRpc2VuXFdlYnNpdGVzXE9OaWlDU1xNYWluXFNvdXJjZVxPbmlpY3NSZWFjdC1QYXltZW50c1xPbmlpY3NSZWFjdFxPbmlpY3NSZWFjdFxqc29uXHJlcGx5XEltcG9ydE1CU0NvZGVz?=
X-Powered-By: ASP.NET
Date: Tue, 21 May 2019 21:49:03 GMT
Content-Length: 605
Query String Parameters
month=07-2019
You'll be able to upload a file using JavaScript's fetch API directly, e.g:
let formData = new FormData();
formData.append('description', file.name);
formData.append('type', 'file');
formData.append('file', file);
fetch('/api/data/import/07-2019', {
method: 'POST',
body: formData
});
Otherwise if you want to use ServiceStack's TypeScript JsonServiceClient you would need to use the API that lets you post the Request DTO with a separate request body, e.g:
formData.append('month', '07-2019');
client.postBody(new ImportData(), formData);
I don't think the month should be part of the request header, that's kinda unorthodox. It should be part of the form data.
If you did:
formData.append('Month', month.replace('/', '-').trim());
client side, then request.Month or request.content.Month should work, depending on how the request object is handled in your instance.

cURL call in c# bad request

I'm trying to do the following cURL call in a c# .net environment
curl -XPOST -d 'Metadata/Type = "sas"' http://bms.org/bcknd/republish
The C# code is as follows:
var requestContent = new FormUrlEncodedContent(new[] { new KeyValuePair<string, string>("Metadata/Type", "\"sas\""), });
HttpResponseMessage response = await client.PostAsync("http://bms.org/bcknd/republish", requestContent);
HttpContent responseContent = response.Content;
using (var reader = new StreamReader(await responseContent.ReadAsStreamAsync()))
{
Console.WriteLine(await reader.ReadToEndAsync());
}
I'm getting a 400 Bad request and when I print it out. Maybe it has something to do with the -XPOST and -d parameter from the curl call?
EDIT:
Here's the http request from curl:
POST http://bms.org/bcknd/republish HTTP/1.1
Host: bms.org/bcknd
User-Agent: curl/7.48.0
Accept: */*
Content-Length: 43
Content-Type: application/x-www-form-urlencoded
Metadata/Type = "sas"
Here's the http request from my code:
POST http://bms.org/bcknd/republish HTTP/1.1
Accept: */*
User-Agent: curl/7.48.0
Content-Type: application/x-www-form-urlencoded; charset=utf-8
Host: bms.org/bcknd
Content-Length: 43
Connection: Keep-Alive
Metadata/Type = "sas"
Short Version
Post the data as StringContent without url encoding and check the response status before trying to read the response body. Make sure the call completes before the application exits, otherwise the call will be cancelled when the application exits. That means, use async Task in Main, not async void :
class Program
{
static async Task Main(string[] args)
{
var client=new HttpClient();
var data = new StringContent("Metadata/Type=\"sas\"",Encoding.UTF8,"application/x-www-form-urlencoded");
var response = await client.PostAsync("http://www.google.com/bcknd/republish", data);
if(response.IsSuccessStatusCode)
{
var responseContent = response.Content;
var body=await response.Content.ReadAsStringAsync();
Console.WriteLine(body);
}
else
{
Console.WriteLine($"Oops! {response.StatusCode} - {response.ReasonPhrase}");
}
}
}
Explanation
In cases like this it's very important to know what's actually being sent. To do that, one can use a debugging proxy like Fiddler or Charles.
Curl with -d sends unencoded data. This call :
curl -XPOST -d 'Metadata/Type = "sas"' http://bms.org/bcknd/republish
will send :
POST http://www.google.com/bcknd/republish HTTP/1.1
Host: www.google.com
User-Agent: curl/7.55.1
Accept: */*
Connection: Keep-Alive
Content-Length: 21
Content-Type: application/x-www-form-urlencoded
Metadata/Type = "sas"
/ and " would have been replaced with other characters if URL encoding was applied. Note also the User-Agent and Accept headers
If --data-urlencode is used, the value will be URL encoded :
POST http://www.google.com/bcknd/republish HTTP/1.1
Host: www.google.com
User-Agent: curl/7.55.1
Accept: */*
Connection: Keep-Alive
Content-Length: 27
Content-Type: application/x-www-form-urlencoded
Metadata/Type =%20%22sas%22
This code on the other hand :
static async Task Main(string[] args)
{
var client=new HttpClient();
var data = new FormUrlEncodedContent(new[] { new KeyValuePair<string, string>("Metadata/Type", "\"sas\""), });
var response = await client.PostAsync("http://www.google.com/bcknd/republish", data);
var responseContent = response.Content;
var body=await response.Content.ReadAsStringAsync();
Console.WriteLine(body);
}
Will send :
POST http://www.google.com/bcknd/republish HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 25
Host: www.google.com
Metadata%2FType=%22sas%22
To get the original payload, one can use StringContent with hand-coded content:
var data = new StringContent("Metadata/Type= \"sas\"",Encoding.UTF8,"application/x-www-form-urlencoded");
The request is :
POST http://www.google.com/bcknd/republish HTTP/1.1
Content-Type: application/x-www-form-urlencoded; charset=utf-8
Content-Length: 19
Host: www.google.com
Metadata/Type= "sas"
If you want to send the User-Agent and Accept headers, you can add them to each individual message or as default request headers :
var client=new HttpClient();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*"));
client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("curl","7.55.1"));
These will add :
Accept: */*
User-Agent: curl/7.55.1
to the request
You can call remote URL as following using HttpClient
using (var httpClient = new HttpClient())
{
using (var request = new HttpRequestMessage(new HttpMethod("POST"), "http://bms.org/bcknd/republish"))
{
request.Content = new StringContent("Metadata/Type = \"sas\"", Encoding.UTF8, "application/x-www-form-urlencoded");
var response = await httpClient.SendAsync(request);
}
}
Here I have just added reference code, by using that you can create your own. I checked your curl request and it seems issue it self.

NotFound() returns 200 instead of 404

I've been stuck on this recently and can't figure out why this is happening.
I'm using an MVC Controller in .Net Core to return a NotFound() "404" response.
However, client side (using angular) if I console.log the response, it shows this...
status:200
statusText:"OK"
Is there any reason why returning NotFound() would return an error code of 200 instead of the intended 404?
This is my Controller GET.
// GET: api/cause/cause-name
[HttpGet("{name}")]
[AllowAnonymous]
public IActionResult GetCauseByName(string name)
{
var input = _service.GetCauseByName(name);
if (input == null)
{
return NotFound();
}
else
{
return Ok(input);
}
}
Any help would be appreciated! Thanks!
To be clear, for this instance assume input is null. What I'm testing is it hitting NotFound() not the return OK(input). Breakpoints have been set and it does hit the NotFound() but still returns the response code of 200.
Headers--
GET /cause/dsdasdas
HTTP/1.1
Host: localhost:48373
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/‌​webp,/;q=0.8 Accept-Encoding: gzip, deflate, sdch, br Accept-Language: en-US,en;q=0.8
HTTP/1.1
200 OK
Transfer-Encoding: chunked
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip Vary:
Accept-Encoding Server: Kestrel X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNcaXR0ZW1wNVxEZXNrdG9wXFByb2plY3RGdW5kQX‌​BwXHNyY1xQcm9qZWN0Rn‌​VuZFxjYXVzZVxkc2Rhc2‌​Rhcw==?= X-Powered-By: ASP.NET Date: Thu, 25 May 2017 14:51:29 GMT –
POSTMAN HEADERS
Content-Encoding →gzip
Content-Type →text/html; charset=utf-8
Date →Thu, 25 May 2017 15:18:31 GMT
Server →Kestrel
Transfer-Encoding →chunked
Vary →Accept-Encoding
X-Powered-By →ASP.NET
X-SourceFiles →=?UTF-8?B?QzpcVXNlcnNcaXR0ZW1wNVxEZXNrdG9wXFByb2plY3RGdW5kQXBwXHNyY1xQcm9qZWN0RnVuZFxjYXVzZVxkc2Rhc2Rhcw==?=
I have asked a similar question and received some kind of answer... NotFound() doesn't seem to work as expected
The solution Redirect("~/404.html"); returns 200.
However, there's another way.
// Wherever you want to return your standard 404 page
return Redirect("Home/StatusCode?code=404");
public class HomeController : Controller
{
// This method allows for other status codes as well
public IActionResult StatusCode(int? code)
{
// This method is invoked by Startup.cs >>> app.UseStatusCodePagesWithReExecute("/Home/StatusCode", "?code={0}");
if (code.HasValue)
{
// here is the trick
this.HttpContext.Response.StatusCode = code.Value;
}
//return a static file.
try
{
return File("~/" + code + ".html", "text/html");
}
catch (FileNotFoundException)
{
return Redirect("Home/StatusCode?code=404");
}
}
}
This does return 404.

RestSharp - issue with post request (Operation failed)

I have a problem with post request with RestSharp. I have 2 classes:
public class UnitToPost
{
public bool floating_point { get; set; }
public Dictionary<string, TranslationUnitToPost> translations { get; set; }
}
public class TranslationUnitToPost
{
public string name { get; set; }
}
And I want to send it with post request:
client = new RestClient(adresApi);
client.AddDefaultHeader("Authorization", "Bearer " + key);
IRestRequest updateProduct = new RestRequest("units", Method.POST);
ShoperModel.UnitToPost unitToPost = new ShoperModel.UnitToPost();
unitToPost.floating_point = true;
ShoperModel.TranslationUnitToPost transUnit = new ShoperModel.TranslationUnitToPost();
transUnit.name = "namename";
unitToPost.translations = new Dictionary<string, ShoperModel.TranslationUnitToPost>();
unitToPost.translations.Add("pl_PL", transUnit);
updateProduct.RequestFormat = RestSharp.DataFormat.Json;
updateProduct.AddBody(unitToPost);
IRestResponse updateProductResponse = this.client.Execute(updateProduct);
And I always get an error:
[RestSharp.RestResponse] = "StatusCode: InternalServerError,
Content-Type: application/json, Content-Length: -1)"
Content =
"{\"error\":\"server_error\",\"error_description\":\"Operation
Failed\"}"
What is the cause of it? Could it be because of Dictionary in my class?
I've run your code and it issues a request with a valid JSON body.
POST http://..../units HTTP/1.1
Accept: application/json,application/xml, text/json, text/x-json, text/javascript, text/xml
Authorization: Bearer a
User-Agent: RestSharp/105.2.3.0
Content-Type: application/json
Host: .....
Content-Length: 84
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
{"floating_point":true,"translations":[{"Key":"pl_PL","Value":{"name":"namename"}}]}
It looks like the problem may be with the receiving server. If you're not doing so already I'd suggest running Fiddler (http://www.telerik.com/fiddler) and inspecting the request/response.
Edit...
I only just realised you want the JSON body to be :-
{"floating_point":true,"translations":{"pl_PL":{"name":"namename"}}}
I did find a RestSharp issue that covers this :-
https://github.com/restsharp/RestSharp/issues/696
This includes a post where someone has used an ExpandoObject to get the required result.
http://theburningmonk.com/2011/05/idictionarystring-object-to-expandoobject-extension-method/
However, I found it easier to use JSON .NET to serialise and set the body with the following code:-
updateProduct.AddBody(JsonConvert.SerializeObject(unitToPost));

Categories

Resources