2

I have created a function that returns an object using async/await. I would like to make the function generic so that it can return whatever object that I pass in. The code is boilerplate except for the objects being returned. I would like to be able to call GetAsync and have it return the correct object

public Patron getPatronById(string barcode)
{
    string uri = "patrons/find?barcode=" + barcode;
    Patron Patron =  GetAsync(uri).Result;
    return Patron;
}

private async Task<Patron> GetAsync(string uri)
{
    var client = GetHttpClient(uri);
    var content = await client.GetStringAsync(uri);
    JavaScriptSerializer ser = new JavaScriptSerializer();
    Patron Patron = ser.Deserialize<Patron>(content);
    return Patron;
}
4
  • object is root object? msdn.microsoft.com/en-us/library/system.object(v=vs.110).aspx Commented Aug 30, 2016 at 19:32
  • You shouldn't use .Result on the result of GetAsync. If you call it on the UI thread, you'll get a deadlock. Commented Aug 30, 2016 at 19:34
  • 2
    Why is getPatronById not async? It should either be async and you don't use .Result or GetAsync should not be async and you should use WebClient instead of HttpClient and use it's syncronous methods. Using .Result will likely cause your program to lock up. Commented Aug 30, 2016 at 19:35
  • Also a .ConfigureAwait(false) on the .GetStringAsync(uri) would not hurt either. Commented Aug 30, 2016 at 19:37

2 Answers 2

6

What about a generic method?

private async Task<T> GetAsync<T>(string uri)
{
    var client = GetHttpClient(uri);
    var content = await client.GetStringAsync(uri);
    var serializer = new JavaScriptSerializer();
    var t = serializer.Deserialize<T>(content);
    return t;
}

Normally, you should place this method into another class and make it public, in order it can be used by methods in different classes.

Regarding the way you call this method, you could try the following:

 // I capitalized the first letter of the method, 
 // since this is a very common convention in .NET
 public Patron GetPatronById(string barcode)
 {
     string uri = "patrons/find?barcode=" + barcode;
     var Patron =  GetAsync<Patron>(uri).Result;
     return Patron;
 }

Note: In the above snippet I assumed that you haven't moved the GetAsync into another class. If you move it, then you have to make a slight change.

Update

I'm not following what you mean by your note. Do I need to make GetPatronById a task function as well - like Yuval has done below?

I mean something like this:

// The name of the class may be not the most suitable in this case.
public class Repo
{
    public static async Task<T> GetAsync<T>(string uri)
    {
        var client = GetHttpClient(uri);
        var content = await client.GetStringAsync(uri);
        var serializer = new JavaScriptSerializer();
        var t = serializer.Deserialize<T>(content);
        return t;
    }
}

public Patron GetPatronById(string barcode)
{
     string uri = "patrons/find?barcode=" + barcode;
     var Patron =  Repo.GetAsync<Patron>(uri).Result;
     return Patron;
}
Sign up to request clarification or add additional context in comments.

1 Comment

I'm not following what you mean by your note. Do I need to make GetPatronById a task function as well - like Yuval has done below?
2

Generic can be easily done with:

private async Task<T> GetAsync(string uri)
{
    var client = GetHttpClient(uri);
    var content = await client.GetStringAsync(uri);
    return JsonConvert.DeserializeObject<T>(content);
}

Things to note:

  1. JavaScriptSerializer has been deprecated for ages, avoid using it. Try out Json.NET instead.

  2. This:

    Patron Patron =  GetAsync(uri).Result;
    

    is dangerous and can cause potential deadlocks, especially in Web API. You need to go "async all the way":

    public Task<Patron> GetPatronByIdAsync(string barcode)
    {
       string uri = $"patrons/find?barcode={barcode}";
       return GetAsync<Patron>(uri);
    }
    

And only your top most level invoker need await on the Task. Possibly some controller action:

public async Task SomeAction()
{
     await GetPatronByIdAsync("hello");
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.