Why does RestSharp throw an error when deserializing a boolean response? - restsharp

When I make a request in RestSharp like so:
var response = client.Execute<bool>(request);
I get the following error:
"Unable to cast object of type 'System.Boolean' to type 'System.Collections.Generic.IDictionary`2[System.String,System.Object]'."
This is complete HTTP response, per Fiddler:
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Mon, 01 Apr 2013 15:09:14 GMT
Content-Length: 5
false
It appears that everything is kosher with the response, so what gives?
Also, if I'm doing something stupid with my WebAPI Controller by returning a simple value instead of an object and that would fix my problem, feel free to suggest.

RestSharp will only deserialise valid json. false is not valid json (according to RFC-4627). The server will need to return something like the following at the least:
{ "foo": false }
And you'll need a class like to following to deserialize to:
public class BooleanResponse
{
public bool Foo { get; set; }
}

Related

Retrofit 400 response shows required json but does not fall in retrofit isSuccessful block?

When I hit Login Api
data class LoginRequest(val Email: String, val Password: String )
#POST("api/signin")
suspend fun login(#Body loginRequest: LoginRequest): Response<LoginResponse>
I get following logs
I/okhttp.OkHttpClient: <-- 400 https://phonegateway.xyzdomain.com:5002/api/signin (1760ms)
I/okhttp.OkHttpClient: content-type: application/json; charset=utf-8
I/okhttp.OkHttpClient: server: Microsoft-IIS/10.0
I/okhttp.OkHttpClient: correlationid: 0bf23c3a-35a4-4f1b-9c2c-914e6303a7fb
I/okhttp.OkHttpClient: x-powered-by: ASP.NET
I/okhttp.OkHttpClient: date: Mon, 14 Jun 2021 12:09:59 GMT
I/okhttp.OkHttpClient: {"status":null,"data":null,"message":"User does not exist","code":"400"}
I/okhttp.OkHttpClient: <-- END HTTP (72-byte body)
Above logs contain required result that is all I need
I/okhttp.OkHttpClient: {"status":null,"data":null,"message":"User does not exist","code":"400"}
but retrofit response is not successful
if(response.isSuccessful) {
// I expect this block to be run...
} else {
Log.e("source- ", response.errorBody()?.source().toString())
// Now I have to extract the result from response.errorBody()?.source().toString()
}
Because response is not successful so I have to extract result from errorbody.source
E/source-: [size=72 text={"status":null,"data":null,"message":"User does not exist","codeā€¦]
And on Postman, I am receiving 400 too. Attached is the image
which is of course not a correct way. What I am doing wrong in handling response??
If the API call is wrapped into a Response then okhttp won't throw an exception, rather it will return with a response which has the attribute isSuccessful == false.
What you can do, is to add an error interceptor and throw an IoException if the response was not successful.

I get "kotlinx/coroutines/io/ByteReadChannel" when I try to decode a json on server side with ktor and moshi

In Application.kt I install moshi in Application.module
install(ContentNegotiation){
moshi()
}
I declared a simple test calss and in the route I try to decode the test class:
data class Test(val testString: String)
fun Route.test() {
post (TEST_ENDPOINT) {
val testReceive = call.receive<Test>()
call.respond(testReceive)
}
The request is post with the following Headers and Body:
Accept: */*
Accept-Encoding: gzip, deflate
Content-Type: application/json
Accept-Language: en-gb
{
"testString": "dasdada"
}
Response headers:
HTTP/1.1 500 Internal Server Error
Date: Mon, 05 Oct 2020 11:55:58 GMT
Content-Length: 37
Connection: keep-alive
Content-Type: text/plain; charset=UTF-8
Server: ktor-server-core/1.4.1 ktor-server-core/1.4.1
Response body:
kotlinx/coroutines/io/ByteReadChannel
Any suggestion or comment is appreciated.
Moshi 1.0.1 relies on some outdated Ktor API.
Consider either moving back to Ktor 1.3.2 or (better) use another JSON handler (there are several available out of the box: Gson, Jackson and kotlinx.serialization)

How to correctly handle multiple Set-Cookie headers in Hyper?

I'm using Hyper to send HTTP requests, but when multiple cookies are included in the response, Hyper will combine them to one which then fails the parsing procedure.
For example, here's a simple PHP script
<?php
setcookie("hello", "world");
setcookie("foo", "bar");
Response using curl:
$ curl -sLD - http://local.example.com/test.php
HTTP/1.1 200 OK
Date: Sat, 24 Dec 2016 09:24:04 GMT
Server: Apache/2.4.25 (Unix) PHP/7.0.14
X-Powered-By: PHP/7.0.14
Set-Cookie: hello=world
Set-Cookie: foo=bar
Content-Length: 0
Content-Type: text/html; charset=UTF-8
However for the following Rust code:
let client = Client::new();
let response = client.get("http://local.example.com/test.php")
.send()
.unwrap();
println!("{:?}", response);
for header in response.headers.iter() {
println!("{}: {}", header.name(), header.value_string());
}
...the output will be:
Response { status: Ok, headers: Headers { Date: Sat, 24 Dec 2016 09:31:54 GMT, Server: Apache/2.4.25 (Unix) PHP/7.0.14, X-Powered-By: PHP/7.0.14, Set-Cookie: hello=worldfoo=bar, Content-Length: 0, Content-Type: text/html; charset=UTF-8, }, version: Http11, url: "http://local.example.com/test.php", status_raw: RawStatus(200, "OK"), message: Http11Message { is_proxied: false, method: None, stream: Wrapper { obj: Some(Reading(SizedReader(remaining=0))) } } }
Date: Sat, 24 Dec 2016 09:31:54 GMT
Server: Apache/2.4.25 (Unix) PHP/7.0.14
X-Powered-By: PHP/7.0.14
Set-Cookie: hello=worldfoo=bar
Content-Length: 0
Content-Type: text/html; charset=UTF-8
This seems to be really weird to me. I used Wireshark to capture the response and there're two Set-Cookie headers in it. I also checked the Hyper documentation but got no clue...
I noticed Hyper internally uses a VecMap<HeaderName, Item> to store the headers. So they concatenate the them to one? Then how should I divide them into individual cookies afterwards?
I think that Hyper prefers to keep the cookies together in order to make it easier do some extra stuff with them, like checking a cryptographic signature with CookieJar (cf. this implementation outline).
Another reason might be to keep the API simple. Headers in Hyper are indexed by type and you can only get a single instance of that type with Headers::get.
In Hyper, you'd usually access a header by using a corresponding type. In this case the type is SetCookie. For example:
if let Some (&SetCookie (ref cookies)) = response.headers.get() {
for cookie in cookies.iter() {
println! ("Got a cookie. Name: {}. Value: {}.", cookie.name, cookie.value);
}
}
Accessing the raw header value of Set-Cookie makes less sense, because then you'll have to reimplement a proper parsing of quotes and cookie attributes (cf. RFC 6265, 4.1).
P.S. Note that in Hyper 10 the cookie is no longer parsed, because the crate that was used for the parsing triggers the openssl dependency hell.

Rest WCF Post Json body parameter is always null while using Fiddler

I have been struggling with this the past few days. I have researched the issue and tried the solutions posted. However it has not worked. I have REST WCF Post method that has
[OperationContract(Name = "ImportRawJson")]
WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.WrappedRequest,
ResponseFormat = WebMessageFormat.Json, RequestFormat=WebMessageFormat.Json,
UriTemplate = "ImportRawJson/username/{username}/password/{password}/fileName/{fileName}")]
string ImportRawJson(string username, string password, string fileName, string jsonStream);
I am able to consume this through web client. However when I try calling through Fiddler like below the body parameter always results in null and I get an exception.
Fiddler :
Post http://localhost/TimesheetService/Timesheet.svc/ImportRawJson/username/user/password/pwd/fileName/testfiddler
Request Headers:
User-Agent: Fiddler
Host: localhost
Content-Length: 32
Content-Type: application/json; charset=utf-8
Request Body:
{ "jsonStream":{ "ImportRaw": {"TestXml": {"xml": "test" } }}}
Error:
HTTP/1.1 400 Bad Request
Cache-Control: private
Content-Length: 127
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
Set-Cookie: ASP.NET_SessionId=wh4qxcu1x0vmiv45mmzuuaup; path=/; HttpOnly
X-Powered-By: ASP.NET
Date: Tue, 07 May 2013 14:00:58 GMT
{"ErrorCode":"Error","Message":"Procedure or function expects parameter 'jsonStream', which was not supplied."}
Any help as to how I can pass the body parameter. I truly appreciate. I am stuck at this point. Please help!! Thanks in advance
There are a couple of issues in your code. First, if by "JSON stream" you mean any JSON document, you won't be able to use the type string for your code. Instead, you'll need to take it as a Stream (which can basically accept any arbitrary input). If you take the input as a string, you should pass a JSON string to it. And since you set the body type to WrappedRequest, you need to wrap the JSON string in an object, with the parameter name being the member name, and the value you want to pass to your function the value. For example, to pass the string hello world to your operation, you'd need to pass this request body:
{"jsonStream":"hello world"}
But if I guessed correctly, and you want to take any arbitrary JSON, you need to go with the Stream parameter. The blog post at http://blogs.msdn.com/b/carlosfigueira/archive/2008/04/17/wcf-raw-programming-model-receiving-arbitrary-data.aspx has more information about how to implement it.

WCF REST: specify content-type on WebGet Attribute doesn't seem to be working

probably something i doing wrong, but i am returning XML from my WCF Rest service which is built with VS 2010. In fiddler you can see here that it returns test/html as the content-type
HTTP/1.1 200 OK
Cache-Control: private
Content-Length: 222
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Mon, 16 Aug 2010 20:49:55 GMT
So i went ahead and added the following on the webget attribute on my method but it still returns text/html ... I presume that i should return the content type of text/xml because i am in fact returning XML?
Heres my method, i added the ResponseFormat to the attribute... I wasn't sure if i needed bodystyle (i have no idea what it does but saw it in an example :-) )
[WebGet(UriTemplate = "", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Xml)]
public List<SampleItem> GetCollection()
{
// TODO: Replace the current implementation to return a collection of SampleItem instances
return new List<SampleItem>() { new SampleItem() { Id = 1, StringValue = "Hello" } };
}
anyway after the change and rebuilding of the project it still returns the wrong content type ... am i missign somthing?
HTTP/1.1 200 OK
Cache-Control: private
Content-Length: 222
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Mon, 16 Aug 2010 20:54:15 GMT
EDIT
Ok i got a working solution but the attribute method has NO EFFECT, very strange...but if i put this
WebOperationContext.Current.OutgoingResponse.ContentType = "text/xml";
Now i check fiddler and the content-type is actually text/xml.
But i need to put this in every method and the attribute method seems to have no effect.
Anybody know why?
According to this the Firefox request headers has a higher priority for text/html than text/xml, resulting in WCF service methods decorated with xml or json returning with the "wrong" response, although I can imagine it is the correct behavior.
You can force a response content type by explicitly setting
WebOperationContext.Current.OutgoingResponse.ContentType = "text/xml";
or equivalent. I guess this is the only alternative if you truly want to force a specific content type response for all browsers/clients.
See e.g.
WCF ResponseFormat For WebGet
I think you want e.g.
OutgoingWebResponseContext context =
WebOperationContext.Current.OutgoingResponse;
context.ContentType = "image/jpeg";
ResponseFormat controls something else.
Old post, but here is what I found on MSDN's Blog Getting Started with WCF WebHttp Services in .NET 4:
Your project has to use the Full .NET 4 Framework, not the Client Profile.
Once I did that, and restarted the project, I was able to add System.ServiceModel.Web from the list of References.
I hope this helps someone.