EzDev.org

refit

refit - The automatic type-safe REST library for Xamarin and .NET Refit: The automatic type-safe REST library for .NET Core, Xamarin and .NET | Refit the automatic type-safe rest library for xamarin and .net


Refit.ApiException Error Handling

How do I get to the content of Refit.ApiException?

Depending on what the inner content is, I want to let the user know how to proceed. So I see that thrown exception has the following content ...

Content "{\"error\":\"invalid_grant\",\"error_description\":\"The user name or password is incorrect.\"}"

The question is, how do I access that?


Source: (StackOverflow)

Call API using Refit and deserialize to dynamic

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?


Source: (StackOverflow)

Xamarin PCL Refit 3.0.1 , Doesn't look like a Refit interface

I recently started working on a Xamarin Android/iOS project with a PCL class where I want to put all the logic in. Like my Refit interfaces, ReactiveUI ViewModels et cetera, but every time when trying to execute my code I get a error saying that my interface is not a Refit interface. Currently my interface looks like this.

public interface IMyApi
{
    [Post("/authenticate")]
    IObservable<Models.ApiResponses.AuthenticationResponse> SigninRaw([Body] JObject credentials);

    [Get("/service")]
    IObservable<Models.ApiResponses.MyListResponse> GetServiceListRaw();

    [Get("/service/{id}/idstatus")]
    IObservable<Models.ApiResponses.IdResponse> GetIdStatusRaw(string Id);
}

As far as I know this looks good and this also works when I'm trying to load this from a specific platform like iOS project. But when trying to do it from a PCL if fails! I have installed the Refit package in both of my platform specific project Android & iOS and I referenced a dll in the PCL, what did I miss?

If there is need for more information or you have any question, please do not hesitate to ask. Well without further ado, thank you for reading and hopefully someone can assist me with this, because I starting to loose my mind the past couple of days.

Edit: added calling method. Here I calling it from a ViewModel

var client = new HttpClient(NetCache.UserInitiated)
{
    BaseAddress = new Uri("https://api.address.com")
};

var api = RestService.For<IMyApi>(client); <= here it crashes
var response = api.SigninRaw(token);

Source: (StackOverflow)

Refit - Dynamic AND Static Header

I am using Refit and would like to set both a dynamic AND a static header. For this one specific call I need to set a content-type of application/json (for others, I do not), but I also need to pass a dynamic bearer token.

I'm getting a 500 error it almost seems like the one header is erasing the other.

Is this valid and will it pass both content-type AND authorization: bearer ?

[Headers("Content-Type: application/json")]
[Post("api/myendpoint")]
Task<bool> GetUser([Body]int id, [Header("Authorization")] string bearerToken);

Thanks!


Source: (StackOverflow)

Pass json params in get requests

I have:

public class Query {...}
public interface IClient
{
    [Get("/api/endpoint?data={query}")]
    Task<Result> GetData(Query query);
}

but Refit on the Query instance calls ToString instead of using the serializer. Is there any way to achieve this without using a wrapper class?


Source: (StackOverflow)

How to set timeout in Refit library

I am using Refit library in my Xamarin App, I want to set 10 seconds timeout for the request. Is there any way to do this in refit?

Interface:

interface IDevice
{
  [Get("/app/device/{id}")]
  Task<Device> GetDevice(string id, [Header("Authorization")] string authorization);
}

Invoking the API

var device = RestService.For<IDevice>("http://localhost");              
var dev = await device.GetDevice("15e2a691-06df-4741-b26e-87e1eecc6bd7", "Bearer OAUTH_TOKEN");

Source: (StackOverflow)

How do I set the User-Agent at runtime with refit?

If my user agent is a constant string, I can use [Headers("User-Agent: Awesome Octocat App")] to set it.

However, My user agent is generated by a method (because it includes the device and OS version), which means I can't put it inside the Headers attribute.

The other mentioned method is as described in the Dynamic Headers section, which is less than optimal since this is a global header for me. I'd rather not manually add this header to the 60+ API methods.

How would I go about doing this? Is it a supported scenario? Using a custom HttpClient is an acceptable solution (if possible).

I'm also open to other similar products if you know of any that may serve my purpose.


Source: (StackOverflow)

How should I serialize JSON from Refit in an F# project?

I'm using Refit in a C# project to create an API client. I'd prefer to do everything with F# but Refit doesn't fully support F# yet.

If I create my User model in C# everything is fine but I'd prefer to be able to express which properties are optional and handle them appropriately.

If I add FSharp.Core and use FSharpOption<string> or similar then assertions that try to access those members fail with a NullReferenceException but only if the JSON response contains something optional.

If I create a separate F# project that contains a User model I always get a NullReferenceException when trying to deserialize.

Admittedly, keeping any models as part of the C# project seems easier but I don't want to sacrifice knowing which members are optional on the F# side.

What is the best way to go about this?


Source: (StackOverflow)

How to disable urlencoding get-params in Refit?

I use Refit for RestAPI. I need create query strings same api/item?c[]=14&c[]=74

In refit interface I created method

[Get("/item")]
Task<TendersResponse> GetTenders([AliasAs("c")]List<string> categories=null);

And create CustomParameterFormatter

string query = string.Join("&c[]=", values);

CustomParameterFormatter generated string 14&c[]=74

But Refit encoded parameter and generated url api/item?c%5B%5D=14%26c%5B%5D%3D74

How disable this feature?


Source: (StackOverflow)

Concurrent HttpClient calls throwing 500 internal server error

I'm using Refit with 1-2 interfaces and generate my client RESTful classes for Web API requests.

public interface IApiClient<T> where T : new()
    {
        [Get("")]
        Task<IEnumerable<T>> GetInitialOrUpdatedData(string clientId);
    }

In a class I have 60 properties like below.

public IApiClient<Order> Orders { get; private set; }
public IApiClient<OrderDetail> OrderDetails { get; private set; }
public IApiClient<Company> Companies { get; private set; }
public IApiClient<User> Users { get; private set; }
public IApiClient<Address> Addresses { get; private set; }
public IApiClient<Product> Products { get; private set; }
// ...

And intialized like below.

Orders  = RestService.For<IApiClient<Order>>(GetHttpClient("/Order"));
OrderDetails = RestService.For<IApiClient<OrderDetail>>(GetHttpClient("/OrderDetail"));
Companies = RestService.For<IApiClient<Company>>(GetHttpClient("/Company"));
Users = RestService.For<IApiClient<User>>(GetHttpClient("/User"));
// ...

The GetHttpClient(string) returns a new HttpClient instance for each resource endpoint.

private const string BaseUrlAddress = @"http://yourURL/api";

private HttpClient GetHttpClient(string address)
{
    HttpClient httpClient = new HttpClient(new NativeMessageHandler())
    {
        BaseAddress = new Uri(BaseUrlAddress + address),
        Timeout = TimeSpan.FromMinutes(3)
    };
    httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    return httpClient;
}

Somewhere in a galaxy far away I have repositories that will make concurrent calls to all these APIs in the following manner, note that I'm using Punchclock to limit the calls to 5 at a time.

private OperationQueue _queue = new OperationQueue(5 /* at a time */);
private const int LowPriority = 1;
private const int NormalPriority = 5;
private const int HighPriority = 10;

The list of tasks in a method call.

IEnumerable<Task> tasks = new List<Task>
            {
                _queue.Enqueue(NormalPriority, () => Orders .GetAllAsync(clientId)),
                _queue.Enqueue(NormalPriority, () => OrderDetails .GetAllAsync(clientId)),
                _queue.Enqueue(NormalPriority, () => Companies .GetAllAsync(clientId)),
                _queue.Enqueue(NormalPriority, () => Users .GetAllAsync(clientId)),
                _queue.Enqueue(NormalPriority, () => Addresses .GetAllAsync(clientId))
        };

        await Task.WhenAll(tasks).ConfigureAwait(false);

The above will throw 500 internal server errors to random tables as I noticed. Changing the calls to serially asynchronous works great!

await Orders.GetAllAsync(workerId).ConfigureAwait(false);
await OrderDetails .GetAllAsync(workerId).ConfigureAwait(false);
await Companies .GetAllAsync(workerId).ConfigureAwait(false);
await Users .GetAllAsync(workerId).ConfigureAwait(false);
await Addresses .GetAllAsync(workerId).ConfigureAwait(false);

It is kinda impossible to understand the 500 internal server when it is not consistent and since my server works handling the calls one by one I'm trying to understand if this is a client side problem of the APIs I'm using or my server needs special configuration to handle the requests, which 5 at a time is descent to handle.

I'm using Web API 2 server.

I'm also thinking if I can reuse the same HttpClient instance with different endpoint configuration with my setup.

Any thoughts much appreciated.


Source: (StackOverflow)

Refit Update package on Xamarin

I've just updated a Xamarin solution using the refit package (2.3.0. -> 2.4.1) and now the build is complaining:

RefitStubs.g.cs(37,27): error CS0102: The type `Sample.App.Api' already contains a definition for `Client'
    RefitStubs.cs(37,27): (Location of the symbol related to previous error)

I've tried reverting the package version but same error occurs. I've cleaned the solution but still the same issue


Source: (StackOverflow)

Using Refit in Core/Android/IOS I encountered System.NotImplementedException error

System.NotImplementedException: You've somehow included the PCL version of Refit in your app. You need to use the platform-specific version! 

Currently using MVVMCross framework referenced the Core Project

I have tried this in multiple ways:

  • Different versions of refit tested (all the same versions used).
  • Tried to setup the DI within the Setup.cs (android platform), instead of the a PCL.
  • I even tried to use a shared project instead of a PCL. Only xamarin android had refit installed - no logical way a PCL could break it, but still gave the same error..
  • I checked the actual Refit for Android \app\packages\refit.2.4.1\lib\MonoAndroid\Refit.dll
  • I checked the actual Refit for IOS \app\packages\refit.2.4.1\lib\Xamarin.iOS10\Refit.dll

Have I missed something?


Source: (StackOverflow)

Policy Handle issues in conjunction with Refit package and Xamarin

I have set up my Xamarin core project with a lot of the tips I read from here.

I have a simple service that I'm using to see if an entered url for a server is valid: IValidateUrlService

I'm trying to use the Polly library to do something like this:

var request = new PingUrlRequest();
var validateUrlTask = apiService.UserInitiated.ValidateUrl(request);

var response = await Policy
    .Handle<ApiException>()
    .RetryAsync(retryCount: 5)
    .ExecuteAsync(async () =>
        await validateUrlTask);

reachable = HandleServerResponse(response);

This works fine unless I get an Exception. For instance, when I was getting an ApiException on one server I was testing against; the above code did not absorb the error! It just threw the exception and crashed the program. I could only get the code to work properly by doing this:

try
{
    var request = new PingUrlRequest();
    var validateUrlTask = apiService.UserInitiated.ValidateUrl(request);

    var response = await Policy
        .Handle<ApiException>()
        .RetryAsync(retryCount: 5)
        .ExecuteAsync(async () =>
            await validateUrlTask);

    reachable = HandleServerResponse(response);
}
catch (ApiException e)
{
    Mvx.Trace(e.StackTrace);
}

But that doesn't feel correct... What's the point of having the Handle parameter up top if it doesn't do anything? I have to be implementing this wrong! Any suggestions?


Source: (StackOverflow)

Refit / HttpClient / ModernHttpClient - 400 Bad Request

Recently started with ReactiveUI and so far so good. While trying to figure out stuff I came across a HttpClient / Refit problem. I have a long list and every item in that list have to make a request to a API as follows.

This is a ReactiveObject

public SearchResult()
{
    LoadStats = ReactiveCommand.CreateAsyncTask(_ => DownloadMultipleCalls(this.IdText, this.DisplayText));

    LoadStats
        .ThrownExceptions
        .SubscribeOn(RxApp.MainThreadScheduler)
        .Subscribe(ex => UserError.Throw("Couldn't load stats", ex));

    _avaText = LoadStats.Select(x => x.Ava).ToProperty(this, x => x.AvaText, string.Empty);
    _perText = LoadStats.Select(x => x.Per).ToProperty(this, x => x.PerText, string.Empty);

    this.WhenAnyValue(x => x.IdText)
        .Where(x => !string.IsNullOrWhiteSpace(x))
                //.Select(_ => Observable.Timer(DateTimeOffset.MinValue, TimeSpan.FromSeconds(1), RxApp.MainThreadScheduler))
        .Retry(5)
        .InvokeCommand(LoadStats);
}

In DownloadMultipleCalls the following is happening.

async static Task<AvaPer> DownloadMultipleCalls(string id, string displaytext)
{
    AvaPer response = new AvaPer();
    var block = new ActionBlock<string>(async service =>
    {
        response = await DownloadCall(service, displaytext);
    },
    new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 4 });

    block.Post(id);

    block.Complete();
    await block.Completion;

    return response;
}

async static Task<AvaPer> DownloadCall(string id, string displaytext)
{
    System.Diagnostics.Debug.WriteLine($"Starting download at {DateTimeOffset.Now}");

    var client = new HttpClient(NetCache.UserInitiated)
    {
        BaseAddress = new Uri("https://api.adres.com"),
    };

    //client.Timeout = TimeSpan.FromMilliseconds(10);

    var token = GetToken;

    client.DefaultRequestHeaders.Add("authToken", token);
    var api = RestService.For<IMyApi>(client);

    AvaPer idEntries = new AvaPer();
    try
    {
        var searchResult = await api.GetAvaPerStatusRaw(id); // <== Here is the error (400 - Bad Request)

        //var parsedEntries = Task.Run(() => {
        idEntries = new AvaPer
        {
            Id = searchResult.Id.ToString() ?? string.Empty,
            display = displaytext ?? string.Empty,
            Ava = searchResult.AvailabilityStatus ?? string.Empty,
            Per = searchResult.PerformanceStatus ?? string.Empty,
            Updated = DateTimeOffset.Now.ToLocalTime().ToString() ?? string.Empty
        };
        //}).ConfigureAwait(false);

        //return idEntries;
    }
    catch (ApiException ex)
    {
        var statusCode = ex.StatusCode;
        var error = ex.GetContentAs<Models.ServiceModel.ErrorResponse>();
    }

    return idEntries;
}

Finally it goes all wrong with this line of code var searchResult = await api.GetAvaPerStatusRaw(id); The app crashes with a response "400 Bad Request" and if I look into the error it sais that the there is no id value inplace of the GET request. But when I check the initial value of id there is a value so it should not respond with that. Can anyone help me with this? If you have any question, please do not hesitate to ask. Thank you very much.

Kind regards,

Fernando


Source: (StackOverflow)

Json.Net serialise collection into named attributes

I am creating a Xamarin app with API calls managed by Refit and other Paul Betts libraries and was looking at serialising a collection of objects into a Json attributed array.

The question I have is how do I serialise the collection of MemberSlot objects in the MemberBooking type, using Json.Net, into the desired Json?

The names of the objects will always be numbers 1 -> 4 but some or all may not be present.

Question

Could I just change the List property in the MemberBooking object to a Dictionary and populate the string key appropriately?

Object heirarchy

public class MemberBookingRequest
{
    [JsonProperty("member_booking_request")]
    public MemberBooking Booking { get; set; }
}

public class MemberBooking
{
    [JsonProperty("course_id")]
    public int CourseId { get; set; }

    [JsonProperty("date")]
    public string TeeDate { get; set; }

    [JsonProperty("time")]
    public string TeeTime { get; set; }

    [JsonProperty("slots")]
    public List<MemberSlot> Slots { get; set; }
}

public class MemberSlot
{
    [JsonIgnore]
    public int Id { get; set; }

    [JsonProperty("type")]
    public BookingType Type { get; set; }

    [JsonProperty("holes")]
    public int Holes { get; set; }

    [JsonProperty("user_id")]
    public int MemberId { get; set; }
}

Current Json

{  
   "member_booking_request":{  
      "course_id":1,
      "date":"2016-09-29",
      "time":"09:00",
      "slots":[  
         {  
            "type":"Member",
            "holes":18,
            "user_id":110
         },
         {  
            "type":"Member",
            "holes":18,
            "user_id":111
         },
         {  
            "type":"Member",
            "holes":18,
            "user_id":112
         },
         {  
            "type":"Member",
            "holes":18,
            "user_id":117
         ]
      }
   }
}

Desired Json

{  
   "member_booking_request":{  
      "course_id":1,
      "date":"2016-09-29",
      "time":"09:00",
      "slots":{  
         "1":{  
            "type":"Member",
            "holes":18,
            "user_id":110
         },
         "2":{  
            "type":"Member",
            "holes":18,
            "user_id":111
         },
         "3":{  
            "type":"Member",
            "holes":18,
            "user_id":112
         },
         "4":{  
            "type":"Member",
            "holes":18,
            "user_id":117
         }
      }
   }
}

Source: (StackOverflow)