5

I'm calling a REST service using Refit and I want to deserialize the JSON that is returned as a dynamic type.

I tried defining the interface as

[Get("/foo")]
Task<dynamic> GetFoo();

but the call times out.

I know I can deserialize to a dynamic like this

var mockString = "{ title: { name: 'fred', book: 'job'} }";
dynamic d = JsonConvert.DeserializeObject(mockString);

but I can't figure out what to pass to Refit to get it to do the same.

Another option would be to get Refit to pass the raw JSON back so I can deserialize it myself but I can't see a way to do that either.

Any ideas?

Steve Chadbourne
  • 6,873
  • 3
  • 54
  • 82
  • why do you need to? what's wrong about a strong type? – Thomas Sep 12 '17 at 09:24
  • 1
    Timeout sounds odd - are you sure that the issue is with the `dynamic` return type? I was able to specify it in a refit interface and got back a `dynamic` (under the hood, a `JObject` - as JSON.NET handles the deserialization) back fine. – rdavisau Sep 12 '17 at 12:25
  • @Thomas I don't know the shape of the JSON ahead of time so can't provide a strong type. If I return a dynamic I can navigate around the data. – Steve Chadbourne Sep 12 '17 at 23:48
  • @rdavisau it seems to be something to do with the endpoint I'm using. Other endpoints work fine. – Steve Chadbourne Sep 12 '17 at 23:50

2 Answers2

4

You can define your interface to return a string and get the raw JSON that way:

[Get("/foo")]
Task<string> GetFoo();

As described here: https://github.com/paulcbetts/refit#retrieving-the-response

Steven Thewissen
  • 2,971
  • 17
  • 23
  • I'm trying this but my response is coming through with an extra layer of escaped strings. for example i'm expecting: `{"someField": "value1"}` but i'm getting `"{\r\n \"someField\": \"value1\"\r\n}"`. Any way around this? – DLeh Sep 03 '21 at 17:29
3

Refit uses JSON.NET under the hood, so any deserialization that works with that will work with Refit, including dynamic. The interface you have described is exactly right.

Here's a real working example:

public interface IHttpBinApi
{
    [Get("/ip")]
    Task<dynamic> GetIp();
}

var value = await RestService.For<IHttpBinApi>("http://httpbin.org").GetIp();

If you are using iOS and Refit 4+, you might be seeing this bug: https://github.com/paulcbetts/refit/issues/359

As Steven Thewissen has stated, you can use Task<string> as your return type (or Task<HttpResponseMessage>, or even Task<HttpContent>) to receive the raw response and deserialize yourself, but you shouldn't have to -- the whole point of Refit is that it's supposed to save you that hassle.

[UPDATED: 02/2023]

Refit now uses System.Text.Json by default (see the comment below), but the approach here should still work.

Bennor McCarthy
  • 11,415
  • 1
  • 49
  • 51
  • Your example works fine. I'm using this endpoint http://mockbin.org/bin/ef5fc5d9-bd0a-4fca-9ce0-ce49ec12b4d6 and it times out when trying return dynamic but works when returning a string. – Steve Chadbourne Sep 12 '17 at 23:46
  • 1
    Note that as of [v6](https://github.com/reactiveui/refit#breaking-changes-in-6x), Refit uses [`System.Text.Json`](https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-overview) by default instead. – Bondolin Feb 18 '23 at 20:41