HttpClient await hangs on PostAsync with async void method - c#

I'm still trying to wrap my head around async and I'm wondering why the following code is causing a deadlock. My use case is this: I have a service interface which attempts to abstract how the service is implemented. One of the services is an OAuth based web-service. The service interface has a method Connect() which anyone using the interface must do prior to using it.
On my client side I create my concrete service object and call Connect() in my view constructor (this is a prototype, so I'm just trying to get a proof of concept going). In the OAuth-based service, the connect call requires retrieving an access token, so it (attempts) to do this asynchronously. This Connect() call never returns, though, and the application is deadlocked (but the UI is active). I'm guessing I'm messing up and trying to synchronously use my client somewhere, but I'm not sure where.
Control
public class MainWindow
{
public MainWindow()
{
InitializeComponent();
_webService = new OAuthBasedWebService();
_webService.ShowAuthorizationPage += _webService_ShowAuthorizationPage; // this is defined on the concrete object -- i know, bad design
_webService.Connect();
}
}
OAuth based webservice
public class OAuthBasedWebService()
{
private OAuthWrapper _wrapper;
public async void Connect()
{
var uri = await _wrapper.GetAuthorizationUri();
OnShowAuthorizationPage(uri);
}
}
internal class OAuthWrapper
{
public async Task<Uri> GetAuthorizationUri()
{
var uri = await _consumer.GetAuthorizationUriAsync();
return uri;
}
}
internal class OAuthConsumer
{
public async Task<Uri> GetAuthorizationUriAsync()
{
using (var client = new HttpClient())
{
client.BaseAddress = "webservicebaseaddress";
var content = new FormUrlEncodedContent(new []
{
CreateParameter("oauth_consumer_key", "consumerkey"),
CreateParameter("oauth_consumer_secret", "consumersecret")
// etc., etc.
});
var response = await client.PostAsync("/method_path", content).ConfigureAwait(false);
var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
// parse authorization uri from responseContent
return authorizationUri;
}
}
}
I know the design needs a little work but I'm trying to figure out why this is deadlocking. I'm guessing it is because _webService.Connect() is not being called asynchronously but I also cannot await that because it doesn't return anything and the rest of the program doesn't depend on it.

I'm not sure why you are using a event here, if the problem was just because you couldn't make the constructor "async" then just move the conect call to another method:
public class MainWindow
{
public MainWindow()
{
InitializeComponent();
Init();
}
public async void Init(){
_webService = new OAuthBasedWebService();
Uri uri=await _webService.Connect();
_webService_ShowAuthorizationPage(uri);
}
}
public class OAuthBasedWebService()
{
private OAuthWrapper _wrapper;
public async Task<Uri> Connect()
{
return await _wrapper.GetAuthorizationUri();
}
}

Related

Mirror of gRPC calls

I want to be able to mirror all gRPC calls for some services to another set of services with same interface, in C#.
I think about writing extension method for GrpcClientFactory.CreateClient, to return class which would do two calls in parallel. Result from mirror is not needed, so I would return result from first call.
Is it best aproach for the task, or it is possible to make it better?
Pretty much what you described, in your case you can make use of IHttpClientFactory for creating http clients
public class GrpResponse
{
public string client { get; set; }
public HttpResponseMessage response { get; set; }
}
private async void ExecuteGrpRequest()
{
var payLoad = new HttpRequestMessage();
var grpTasks = new List<Task<GrpResponse>>
{
SendAsyc("real", payLoad),
SendAsyc("mock", payLoad)
};
var responses = await Task.WhenAll(grpTasks);
}
private async Task<GrpResponse> SendAsyc(string client, HttpRequestMessage message )
{
// IHttpClientFactory is _httpClientFacotry; injected from ctor
var httpClient = _httpClientFacotry.CreateClient(client);
return new GrpResponse
{
client = client,
response = await httpClient.SendAsync(new HttpRequestMessage())
};
}

Set a default header to each http client call

I want to set a default header for every method in the UserHttpClient but I don`t want that every method is doing that, I want to do it in a general way.
The problem I see with the current implementation is, that when I call one method the _client gets disposed thus at the next call within a Http Request the _client is not initialized, as this happens within the constructor.
The UserHttpClient is registered via DI as per Http Request.
I also do not want to create a private/base method where I pass the _client and do the header addition there.
How would you solve that problem?
public class UserHttpClient : IUserRemoteRepository
{
private readonly string baseUrl = ConfigurationManager.AppSettings["baseUrl"];
private readonly string header = ConfigurationManager.AppSettings["userHeader"];
private readonly HttpClient _client;
public ServiceProductDataProvider(string toolSystemKeyHeader)
{
_client = new HttpClient();
_client.DefaultRequestHeaders.Add(header, token);
}
public async Task<List<UserDto>> GetUsers(UserRequestDto dto)
{
using (_client)
{
// do stuff
var users = await _client.GetAsync("url here");
}
}
public async Task<UserDto> GetUser(Guid userId)
{
using (_client)
{
// do stuff
var users = await _client.GetAsync("url here");
}
}
}
The class UserHttpClient has a member that is IDisposable (private readonly HttpClient _client;). That means that the UserHttpClient should also implement IDisposable:
public void Dispose()
{
_client.Dispose();
}
Then, the class/code that is using UserHttpClient is responsible for Disposing it after it's done with it. If the instance is injected, then the DI framework you use probably handles disposing it automatically at the end of the request. What's left for you then is to simply remove the using blocks from the implementation:
public async Task<List<UserDto>> GetUsers(UserRequestDto dto)
{
// do stuff
var users = await _client.GetAsync("url here");
}
---- EDIT ----
You could also work around the issue by not reusing the HttpClient:
private string _toolSystemKeyHeader;
public ServiceProductDataProvider(string toolSystemKeyHeader)
{
_toolSystemKeyHeader = toolSystemKeyHeader
}
private HttpClient GetClientInstance()
{
HttpClient _client = new HttpClient();
_client.DefaultRequestHeaders.Add(header, _toolSystemKeyHeader); //?? in your original code, the toolSystemKeyHeader is not used, but I guess it is the token..?
return _client;
}
And:
public async Task<List<UserDto>> GetUsers(UserRequestDto dto)
{
using (var _client = GetClientInstance())
{
// do stuff
var users = await _client.GetAsync("url here");
}
}

Aborting WCF proxy that has non-cached ChannelFactory with CancellationToken causes deadlock

So here's how it is.
There is a WCF service. I've generated a proxy for it by "Add Service Reference" with task-based operations.
Endpoint address for that service might change for different users. I have no control over this service, vendor just does that this way.
Then I wrap that service into another type and through that type interaction with WCF service occurs.
It all looks like this:
//Generated code
public partial class MyServiceClient: System.ServiceModel.ClientBase<IMyService>, IMyService
{
public async Task<ResultDataContractType> GetResultsAsync(ArgsDataContractType args)
{
return base.Channel.GetResultsAsync(args);
}
}
...
...
...
//end of generated code
public class ClientFactory
{
public static IMyService CreateClient(string url)
{
var binding = new BasicHttpBinding();
var address = new EndpointAddress(url);
var client = new MyServiceClient(binding, address);
return client;
}
}
public class Wrapper()
{
public async Task<ResultType> GetResultsAsync(string url, ArgsType args, CancelationToke cancelationToken)
{
var client = ClientFactory.CreateClient(url);
try
{
cancellationToken.Register(target =>
{
var communicationObject = target as ICommunicationObject;
if (communicationObject != null)
{
communicationObject.Abort();
}
}, client);
ArgsDataContractType requestArgs = MapArgs(args);
ResultDataContractType result = await client.GetResultsAsync(args);
}
}
}
public class Consumer
{
public async void DoWork()
{
var args = new ArgsType
{
...
};
var cts = new CancellationTokenSource()
var wrapper = new Wrapper();
Task<ResultType> task = wrapper.GetResultsAsync("http://someaddress.com", args, cts.Token);
cts.Cancel(); //This is made intentionaly, normaly there is timeout timespan for token source
await task;
...
...
...
}
}
Consumer is actually the NUnit unit test, but calling the same code from ASP.NET application would also end up in a deadlock. It gets stuck on await task;
What I have noticed, that if I would set MyServiceClient.CacheSetting = CacheSetting.AlwaysOn; will make that code run without deadlocking.
Also, if I would configure MyServiceClient from App.config or Web.config will make code running without deadlocking. But if I would set MyServiceClient.CacheSetting = CacheSetting.AlwaysOff; before instantiating MyServiceClient this code will deadlock.
Also, configuring awaiter like this:
ResultDataContractType result = await client.GetResultsAsync(args).ConfigureAwait(false)
Will make code run without deadlocking.
Could you please enlighten me with any idea why's that deadlock doesn't happens when ChannelFactory for MyServiceClient is cached, and will happen if it is not cached?

async httpclient operation

I am trying to design a browser that will fetch site updates programmatically. I am trying to do this with async/await methods but when I try and run the program it seems to just hang on response.Wait();. not sure why or whats happening.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var urls = sourceUrls();
Task<HttpResponseMessage> response = login(urls[0]);
response.Wait();
Console.Write( "Complete" );
}
private List<Site> sourceUrls()
{
var urls = new List<Site>();
urls.Add(new Site("http://yahoo.com", "test", "test"));
return urls;
}
}
browser class::
static public class Browser
{
private static CookieContainer cc = new CookieContainer();
private static HttpClientHandler handler = new HttpClientHandler();
public static HttpClient browser = new HttpClient(handler);
static Browser()
{
handler.CookieContainer = cc;
}
static public async Task<HttpResponseMessage> login(Site site)
{
var _postData = new Dictionary<string, string>
{
{"test", "test"}
};
FormUrlEncodedContent postData = new FormUrlEncodedContent(_postData);
HttpResponseMessage response = await browser.PostAsync(site.url, postData);
return response;
}
}
Also, for my intended purposes, is it ok to make browser a static function, or does that not make sense? Sorry for the questions, new to c#
It's a bad idea to call Wait on a Task in a UI thread, it results in a deadlock.
You can simply await the response which will achieve what you want. The await unwraps the response from the Task so your return type is now just HttpResponseMessage. Because you can't mark constructors as async you can move the functionality to another method that kicks off the operation.
public MainWindow()
{
InitializeComponent();
LoadUrlsAsync();
}
public async Task LoadUrlsAsync()
{
var urls = sourceUrls();
HttpResponseMessage response = await login(urls[0]);
Console.Write( "Complete" );
}
See this article for best practices when using async/await.
Alternatively you can use the Task.ConfigureAwait extension method to configure the continuation not to run on the current SyncrhronizationContext which should also avoid the deadlock.
public MainWindow()
{
InitializeComponent();
var urls = sourceUrls();
Task<HttpResponseMessage> response = login(urls[0]).ConfigureAwait(false);
response.Wait();
Console.Write( "Complete" );
}
Wait causes a deadlock that I explain in full on my blog. The best solution is to use await as Ned suggested.
In your case, constructors cannot be async, so that's not possible. This should be an indication that what you're trying to do may not be the best thing to do. In particular, you're trying to block the UI thread waiting for a download to complete; this is almost never a good idea.
Instead, have your constructor start the asynchronous operation and (synchronously) load a view that shows no data - e.g., a "loading" screen or an empty view, whatever makes the most sense for your problem domain. Then, when the asynchronous operation completes, it should update the view with the new data. I have an article on async data binding that explores one possible technique.
Both GetUrl() and GetUrl2(), below, accomplish what you're looking to do in slightly different ways. Be aware, however, that Task.Wait will block the current thread (in this case, the UI thread) until the task completes. I'm guessing this isn't what you want to do.
using System.Diagnostics;
using System.Net.Http;
using System.Threading.Tasks;
using System.Windows;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
GetUrls();
GetUrls2();
}
private void GetUrls()
{
var response = Task.Run(() => Browser.login("http://yahoo.com"));
response.Wait();
Debug.WriteLine("Complete GetUrls()");
}
private void GetUrls2()
{
var browseTask = Browser.login("http://yahoo.com");
browseTask.ContinueWith((r) => Debug.WriteLine("Complete GetUrls2()"));
}
}
static public class Browser
{
static public async Task<HttpResponseMessage> login(string site)
{
var browser = new HttpClient();
return await browser.GetAsync(site);
}
}

Async is becoming a pain in the behind because I'm trying to make a re-usable library that doesn't suck

Because Post requests to APIs need to run asynchronously on windows phone, I am struggling to create a lean easy to use library to interact with an API.
The issue is that people using the library will always need to supply a callback function.
Let's take a look at some pseudo code:
PostRequest Class to help me with POST requests:
class PostRequest
{
private Action<MemoryStream> Callback;
public PostRequest(string urlPath, string data, Action<MemoryStream> callback)
{
Callback = callback;
// Form the URI
UriBuilder fullUri = new UriBuilder(urlPath);
if (!string.IsNullOrEmpty(data))
fullUri.Query = data;
// Initialize a new WebRequest
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(fullUri.Uri);
request.Method = "POST";
// Set up the state object for the async request
DataUpdateState dataState = new DataUpdateState();
dataState.AsyncRequest = request;
// Start the asynchronous request
request.BeginGetResponse(new AsyncCallback(HandleResponse),
dataState);
}
private void HandleResponse(IAsyncResult asyncResult)
{
// Get the state information
DataUpdateState dataState = (DataUpdateState)asyncResult.AsyncState;
HttpWebRequest dataRequest = (HttpWebRequest)dataState.AsyncRequest;
// End the async request
dataState.AsyncResponse = (HttpWebResponse)dataRequest.EndGetResponse(asyncResult);
if (dataState.AsyncResponse.StatusCode.ToString() == "OK")
{
// Create a stream from the response
Stream response = dataState.AsyncResponse.GetResponseStream();
TextReader textReader = new StreamReader(response, true);
string jsonString = textReader.ReadToEnd();
MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(jsonString));
// Send the stream through to the callback function
Callback(stream);
}
}
}
public class DataUpdateState
{
public HttpWebRequest AsyncRequest { get; set; }
public HttpWebResponse AsyncResponse { get; set; }
}
The API Access Object classes:
class APIAuthenticationCredentials
{
public String Username { get; set; }
public String Password { get; set; }
}
class APIAO
{
private String AuthUrl = "http://api.example.com/";
public static Auth Auth = new Auth();
//...
public static void Authenticate( String data, APIAuthenticationCredentials credentials, Action<MemoryStream> callback )
{
PostRequest request = new PostRequest(AuthURL, data, callback);
}
//...
}
You will notice I have to pass a callback function all the way through this so that once the data is returned by the HandleResponse method in my PostRequest class, the data is forwarded onto some controller that makes the screen do something with the data. At the moment, it's not ultra horrid to use:
private void DisplayData(MemoryStream stream)
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Auth));
APIAO.Auth = (Auth)serializer.ReadObject(stream);
}
//...
APIAuthenticationCredentials credentials = new APIAuthenticationCredentials {
Username = "whatever",
Password = "whatever"
}
APIAO.Authenticate( credentials, DisplayData );
//...
The problem is I want to create some kind of repository style pattern... Let's say the API returned different json models, one call returned an array of products... the problem is that I want to create one lovely repository call eg:
IProductRepository productRepository = new ProductRepository();
productRepository.GetAll();
But I've gotta put some GOSH DARN callback function in it too and that means every repository method of any object type returned by the API is going to have this MemoryStream callback... and if I ever want to change that functionality, I've gotta update that stuff everywhere yo. :(
Has anyone seen a better way of doing this crap.
This is starting to become far too complex
--crying
A simpler answer using newer language constructs would be:
public static Task<string> GetData(string url, string data)
{
UriBuilder fullUri = new UriBuilder(url);
if (!string.IsNullOrEmpty(data))
fullUri.Query = data;
WebClient client = new WebClient();
client.Credentials = CredentialCache.DefaultCredentials;//TODO update as needed
return client.DownloadStringTaskAsync(fullUri.Uri);
}
In a 4.0 project you can use a TaskCompletionSource to translate a non-Task asynchronous model into a Task:
public static Task<string> GetData2(string url, string data)
{
UriBuilder fullUri = new UriBuilder(url);
if (!string.IsNullOrEmpty(data))
fullUri.Query = data;
WebClient client = new WebClient();
client.Credentials = CredentialCache.DefaultCredentials;//TODO update as needed
var tcs = new TaskCompletionSource<string>();
client.DownloadStringCompleted += (s, args) =>
{
if (args.Error != null)
tcs.TrySetException(args.Error);
else if (args.Cancelled)
tcs.TrySetCanceled();
else
tcs.TrySetResult(args.Result);
};
client.DownloadStringAsync(fullUri.Uri);
return tcs.Task;
}
The caller now has a Task<string> that represents the results of this asynchronous operation. They can wait on it synchronously and get the result using the Result property, they can add a callback that will execute when the operation finishes using ContinueWith, or they can await the task in an async method which, under the hood, will wire up the remainder of that method as a continuation of that task, but without creating a new method or even a new scope, i.e.
public static async Task Foo()
{
string result = await GetData("http://google.com", "");
Console.WriteLine(result);
}
This will start the asynchronous task, add a callback (or continuation) to that task so that when it runs it will continue executing code where it left off, at which point it will then write the results to the console and mark the Task that this method returns as completed, so that any continuations to this method will then execute (allowing for composition of async methods).

Categories

Resources