So I'm writing a client API PCL (.NET 4.5, SL 5, Win8, WP8.1, WP SL 8) library and I've decided that I'm only going to allow one HTTP request at a time. Currently I use the TPL to do them:
Task.Factory.FromAsync<Stream>(httpReq.BeginGetRequestStream, httpReq.EndGetRequestStream, null).ContinueWith<Task<WebResponse>>((requestStreamTask) =>
{
return Task<WebResponse>.Factory.FromAsync(httpReq.BeginGetResponse, httpReq.EndGetResponse, null);
}).Unwrap().ContinueWith<HttpWebResponse>((getResponseTask) =>
{
return (HttpWebResponse)getResponseTask.Result;
});
So I want to add locking to prevent more than one request from going at once. I know I could simply call Monitor.Enter
before I start and call Monitor.Exit
in the last ContinueWith
. But based on Migrating lock to TPL, I can't use Monitor
like that because of threading issues possibly. I have no issue using a different blocking object like that post recommends but as far as I can tell in my PCL the only lock I have available is Monitor.
So what should I do?
EDIT: After talking with Yuval Itzchakov below I've realized the reason I only have the Monitor
class for syncing is because I have Silverlight 5 support in my PCL. If there is no other way I'll look into dropping support for SL5 but I'd rather not.
EDIT2: After messing around I realized that I do have the ManualResetEvent
class, could I use that?
Since you're writing a PCL and including some older platforms (specifically, SL5), your choices are a bit limited. TPL Dataflow is not supported on SL5, and neither is SemaphoreSlim
.
However, HttpClient
is, and so are async
/await
. These allow your code to be far, far cleaner than Task.Factory.FromAsync
+ Unwrap
+ ContinueWith
.
For portable async
-ready synchronization and/or producer/consumer queues, I recommend my own AsyncEx library. In this case, an AsyncLock
should suffice; it can be used in a similar way to SemaphoreSlim
:
private readonly HttpClient _client = new HttpClient();
private readonly AsyncLock _mutex = new AsyncLock();
public async Task<string> GetStringAsync(string url)
{
using (await _mutex.LockAsync())
{
return await _client.GetStringAsync(url);
}
}