35

I'm attempting to use the documentation on the RestSharp GitHub wiki to implement calls to my REST API service but I'm having an issue with the ExecuteAsync method in particular.

Currently my code looks like this for the API class:

public class HarooApi
{
    const string BaseUrl = "https://domain.here";

    readonly string _accountSid;
    readonly string _secretKey;

    public HarooApi(string accountSid, string secretKey)
    {
        _accountSid = accountSid;
        _secretKey = secretKey;
    }

    public T Execute<T>(RestRequest request) where T : new()
    {
        var client = new RestClient();
        client.BaseUrl = BaseUrl;
        client.Authenticator = new HttpBasicAuthenticator(_accountSid, _secretKey);
        request.AddParameter("AccountSid", _accountSid, ParameterType.UrlSegment);
        client.ExecuteAsync<T>(request, (response) =>
        {
            return response.Data;
        });
    }
}

I'm aware this slightly deviates from what is on the GitHub page but I'm using this with WP7 and believe the example is for C# hence the usage of the ExecuteAsync method.

My problem is with what the ExecuteAsync command should contain. I can't use return response.Data because I'm warned:

'System.Action<RestSharp.RestResponse<T>,RestSharp.RestRequestAsyncHandle>' returns void, a return keyword must not be followed by an object expression

Does anyone have any insight on how to fix this or a tutorial that may assist?

joshcollie
  • 471
  • 1
  • 4
  • 9

6 Answers6

50

Old question but if you are using C# 5 you can have a generic execute class by creating a TaskCompleteSource that resturns a Task of T. Your code could look like this:

public Task<T> ExecuteAsync<T>(RestRequest request) where T : new()
    {
        var client = new RestClient();
        var taskCompletionSource = new TaskCompletionSource<T>();
        client.BaseUrl = BaseUrl;
        client.Authenticator = new HttpBasicAuthenticator(_accountSid, _secretKey);
        request.AddParameter("AccountSid", _accountSid, ParameterType.UrlSegment);
        client.ExecuteAsync<T>(request, (response) => taskCompletionSource.SetResult(response.Data));
        return taskCompletionSource.Task;
    }

And use it like this:

private async Task DoWork()
    {
        var api = new HarooApi("MyAcoountId", "MySecret");
        var request = new RestRequest();
        var myClass = await api.ExecuteAsync<MyClass>(request);

        // Do something with myClass
    }
Gusten
  • 882
  • 1
  • 7
  • 14
  • I needed a string response for my case. But this line really helped me: client.ExecuteAsync(request, (response) => taskCompletionSource.SetResult(response.Data)); I wasn't sure how to return the response directly instead of using a callback before and this is the way to go. If someone wants to use this just swap the respone.Data with response.Content and remove the T from everywhere – Alek Arsovski Jun 30 '15 at 13:18
  • I have to ask - how do you get it past the NotYetExecuted status? Been trying with this sample today and cannot get any results. Any help much appreciated. – Richard Griffiths Mar 30 '16 at 09:41
33

As an alternative (or complement) to the fine answer by Gusten. You can use ExecuteAsync. This way you do not manually have to handle TaskCompletionSource. Note the async keyword in the signature.

Update: As of 106.4.0 ExecuteTaskAsync is obsolete. Since 104.2 you should use ExecuteAsync instead:

public async Task<T> ExecuteAsync<T>(RestRequest request) where T : new()
{
    var client = new RestClient();
    client.BaseUrl = BaseUrl;
    client.Authenticator = new HttpBasicAuthenticator(_accountSid, _secretKey);
    request.AddParameter("AccountSid", _accountSid, ParameterType.UrlSegment);
    IRestResponse<T> response = await client.ExecuteAsync<T>(request);
    return response.Data;
}

Old Answer:

public async Task<T> ExecuteAsync<T>(RestRequest request) where T : new()
{
    var client = new RestClient();
    client.BaseUrl = BaseUrl;
    client.Authenticator = new HttpBasicAuthenticator(_accountSid, _secretKey);
    request.AddParameter("AccountSid", _accountSid, ParameterType.UrlSegment);
    IRestResponse<T> response = await client.ExecuteTaskAsync<T>(request); // Now obsolete
    return response.Data;
}
smoksnes
  • 10,509
  • 4
  • 49
  • 74
  • 1
    this is the answer I've been looking for...thanks! Much more straightforward than the other solutions (though not necessarily what the OP was after) – reidLinden Jan 05 '18 at 19:21
  • How to access to `StatusCode` from output of this method? – Mehdi Dehghani Apr 17 '18 at 11:30
  • I'm not sure if I understand. The example above doesn't use `StatusCode` at all. Instead of returning `response.Data` you could return `response`. Then you need to change return type to `Task>`. – smoksnes Apr 17 '18 at 13:19
32

Your code should look something like this:

public class HarooApi
{
    const string BaseUrl = "https://domain.here";

    readonly string _accountSid;
    readonly string _secretKey;

    public HarooApi(string accountSid, string secretKey)
    {
        _accountSid = accountSid;
        _secretKey = secretKey;
    }

    public void ExecuteAndGetContent(RestRequest request, Action<string> callback)
    {
        var client = new RestClient();
        client.BaseUrl = BaseUrl;
        client.Authenticator = new HttpBasicAuthenticator(_accountSid, _secretKey);
        request.AddParameter("AccountSid", _accountSid, ParameterType.UrlSegment);
        client.ExecuteAsync(request, response =>
        {
            callback(response.Content);
        });
    }

    public void ExecuteAndGetMyClass(RestRequest request, Action<MyClass> callback)
    {
        var client = new RestClient();
        client.BaseUrl = BaseUrl;
        client.Authenticator = new HttpBasicAuthenticator(_accountSid, _secretKey);
        request.AddParameter("AccountSid", _accountSid, ParameterType.UrlSegment);
        client.ExecuteAsync<MyClass>(request, (response) =>
        {
            callback(response.Data);
        });
    }
}

I added two methods, so you can check what you want (string content from the response body, or a deserialized class represented here by MyClass)

Pedro Lamas
  • 7,185
  • 4
  • 27
  • 35
7

Or more precisely like this:

    public async Task<IRestResponse<T>> ExecuteAsync<T>(IRestRequest request) where T : class, new()
    {
        var client = new RestClient(_settingsViewModel.BaseUrl);

        var taskCompletionSource = new TaskCompletionSource<IRestResponse<T>>();
        client.ExecuteAsync<T>(request, restResponse =>
        {
            if (restResponse.ErrorException != null)
            {
                const string message = "Error retrieving response.";
                throw new ApplicationException(message, restResponse.ErrorException);
            }
            taskCompletionSource.SetResult(restResponse);
        });

        return await taskCompletionSource.Task;
    }
Per Schondell
  • 71
  • 1
  • 1
1

The following did the job

public async Task<IRestResponse<T>> ExecuteAsync<T>(IRestRequest request) where T : class, new()
{
    var client = new RestClient
    {
        BaseUrl = _baseUrl,
        Authenticator = new HttpBasicAuthenticator(_useraname, _password),
        Timeout = 3000,
    };

    var tcs = new TaskCompletionSource<T>();
    client.ExecuteAsync<T>(request, restResponse =>
    {
        if (restResponse.ErrorException != null)
        {
            const string message = "Error retrieving response.";
            throw new ApplicationException(message, restResponse.ErrorException);
        }
        tcs.SetResult(restResponse.Data);
    });

    return await tcs.Task as IRestResponse<T>;

}
Glen Thomas
  • 10,190
  • 5
  • 33
  • 65
ageroh
  • 93
  • 1
  • 3
  • How is this implemented in the function call? is it `var myclass = await apiService.ExecuteAsync(request);`? – DogEatDog Sep 07 '17 at 23:54
1

Since public static RestRequestAsyncHandle ExecuteAsync(this IRestClient client, IRestRequest request, Action<IRestResponse> callback) has been deprecated, you should look to using public Task<IRestResponse> ExecuteAsync(IRestRequest request, CancellationToken token = default) instead.

The following code

client.ExecuteAsync(request, response => { callback(response.Content); });

Should instead become

await client.ExecuteAsync(request).ContinueWith(task => callback(task.Result.Content));
Chris Stillwell
  • 10,266
  • 10
  • 67
  • 77