Better approach in management of multiple WebRequest - c#

I have an component that is processing multiple web requests each in separate thread. Each WebRequest processing is synchronous.
public class WebRequestProcessor:System.ComponentModel.Component
{
List<Worker> tlist = new List<Worker>();
public void Start()
{
foreach(string url in urlList){
// Create the thread object. This does not start the thread.
Worker workerObject = new Worker();
Thread workerThread = new Thread(workerObject.DoWork);
// Start the worker thread.
workerThread.Start(url);
tlist.Add(workerThread);
}
}
}
public class Worker
{
// This method will be called when the thread is started.
public void DoWork(string url)
{
// prepare the web page we will be asking for
HttpWebRequest request = (HttpWebRequest)
WebRequest.Create(url);
// execute the request
HttpWebResponse response = (HttpWebResponse)
request.GetResponse();
// we will read data via the response stream
Stream resStream = response.GetResponseStream();
// process stream
}
}
Now I have to find optimal way how to cancel all requests.
One way is to convert each synchronous WebRequest into async and use WebRequest.Abort to cancel processing.
Another way is to release thread pointers and allow all threads to die using GC.

If you want to download 1000 files, starting 1000 threads at once is certainly not the best option. Not only it probably won't get you any speedup when compared with downloading just a few files at a time, it will also require at least 1 GB of virtual memory. Creating threads is expensive, try to avoid doing so in a loop.
What you should do instead is to use Parallel.ForEach() along with the asynchronous versions of the request and response operations. For example like this (WPF code):
private void Start_Click(object sender, RoutedEventArgs e)
{
m_tokenSource = new CancellationTokenSource();
var urls = …;
Task.Factory.StartNew(() => Start(urls, m_tokenSource.Token), m_tokenSource.Token);
}
private void Cancel_Click(object sender, RoutedEventArgs e)
{
m_tokenSource.Cancel();
}
void Start(IEnumerable<string> urlList, CancellationToken token)
{
Parallel.ForEach(urlList, new ParallelOptions { CancellationToken = token },
url => DownloadOne(url, token));
}
void DownloadOne(string url, CancellationToken token)
{
ReportStart(url);
try
{
var request = WebRequest.Create(url);
var asyncResult = request.BeginGetResponse(null, null);
WaitHandle.WaitAny(new[] { asyncResult.AsyncWaitHandle, token.WaitHandle });
if (token.IsCancellationRequested)
{
request.Abort();
return;
}
var response = request.EndGetResponse(asyncResult);
using (var stream = response.GetResponseStream())
{
byte[] bytes = new byte[4096];
while (true)
{
asyncResult = stream.BeginRead(bytes, 0, bytes.Length, null, null);
WaitHandle.WaitAny(new[] { asyncResult.AsyncWaitHandle,
token.WaitHandle });
if (token.IsCancellationRequested)
break;
var read = stream.EndRead(asyncResult);
if (read == 0)
break;
// do something with the downloaded bytes
}
}
response.Close();
}
finally
{
ReportFinish(url);
}
}
This way, when you cancel the operation, all downloads are canceled and no new ones are started. Also, you probably want to set MaxDegreeOfParallelism of ParallelOptions, so that you aren't doing too many downloads at once.
I'm not sure what do you want to do with the files you are downloading, so using StreamReader might be a better option.

I think the best solution is "Parallel Foreach Cancellation". Please check the following code.
To implement a cancellation, you first make CancellationTokenSource and pass it to Parallel.ForEach through option.
If you want to cancel, you can call CancellationTokenSource.Cancel()
After the cancelling, OperationCanceledException will be occurred, which you need to handle.
There is a good article about Parallel Programming related to my answer, which is Task Parallel Library By Sacha Barber on CodeProject.
CancellationTokenSource tokenSource = new CancellationTokenSource();
ParallelOptions options = new ParallelOptions()
{
CancellationToken = tokenSource.Token
};
List<string> urlList = null;
//parallel foreach cancellation
try
{
ParallelLoopResult result = Parallel.ForEach(urlList, options, (url) =>
{
// Create the thread object. This does not start the thread.
Worker workerObject = new Worker();
workerObject.DoWork(url);
});
}
catch (OperationCanceledException ex)
{
Console.WriteLine("Operation Cancelled");
}
UPDATED
The following code is "Parallel Foreach Cancellation Sample Code".
class Program
{
static void Main(string[] args)
{
List<int> data = ParallelEnumerable.Range(1, 10000).ToList();
CancellationTokenSource tokenSource = new CancellationTokenSource();
Task cancelTask = Task.Factory.StartNew(() =>
{
Thread.Sleep(1000);
tokenSource.Cancel();
});
ParallelOptions options = new ParallelOptions()
{
CancellationToken = tokenSource.Token
};
//parallel foreach cancellation
try
{
Parallel.ForEach(data,options, (x, state) =>
{
Console.WriteLine(x);
Thread.Sleep(100);
});
}
catch (OperationCanceledException ex)
{
Console.WriteLine("Operation Cancelled");
}
Console.ReadLine();
}
}

Related

async task cancellation c# xamarin

I have a functionality of search users. I have provided a textview and on that textview changed method I'm firing a method to get data from web server. But I'm facing problem when user types letter, because all the api hits done in async task. Service should be hit after 100 milli-sec of wait, means if user types a letter "a" then doesn't type for 100 milli-sec then We have to hit the service. But if user types "a" then "b" then "c", so one service should be hit for "abc", not for all.
I followed the official link, but it doesn't help me
https://msdn.microsoft.com/en-us/library/jj155759.aspx
So basically here is my code
textview.TextChange+= (sender,e) =>{
CancellationTokenSource cts = new CancellationTokenSource();
await Task.Delay(500);
// here some where I have to pass cancel token
var lst = await APIClient.Instance.GetUserSearch("/user/get?searchTerm=" + newText, "application/json",cts);
if (lst != null && lst.Count > 0){
lstSearch.AddRange(lst);
}
}
Here is my method to GetUser
public async Task<JResponse> GetUserSearch<JResponse>(string uri, string contentType,CancellationToken cts)
{
try
{
Console.Error.WriteLine("{0}", RestServiceBaseAddress + uri);
string url = string.Format("{0}{1}", RestServiceBaseAddress, uri);
var request = (HttpWebRequest)WebRequest.Create(url);
request.ContentType = contentType;
if (Utility.CurrentUser != null && !string.IsNullOrWhiteSpace(Utility.CurrentUser.AuthToken))
{
request.Headers.Add("api_key", Utility.CurrentUser.AuthToken);
}
request.Method = "POST";
var payload = body.ToString();
request.ContentLength = payload.Length;
byte[] byteArray = Encoding.UTF8.GetBytes(body.ToString());
request.ContentLength = byteArray.Length;
using (var stream = await request.GetRequestStreamAsync())
{
stream.Write(byteArray, 0, byteArray.Length);
stream.Close();
}
using (var webResponse = await request.GetResponseAsync())
{
var response = (HttpWebResponse)webResponse;
using (var reader1 = new StreamReader(response.GetResponseStream()))
{
Console.WriteLine("Finished : {0}", uri);
var responseStr = reader1.ReadToEnd();
var responseObj = JsonConvert.DeserializeObject<JResponse>(
responseStr,
new JsonSerializerSettings()
{
MissingMemberHandling = MissingMemberHandling.Ignore,
NullValueHandling = NullValueHandling.Ignore
});
return responseObj;
}
}
}
catch (System.Exception ex)
{
Utility.ExceptionHandler("APIClient", "ProcessRequestAsync", ex);
}
return default(JResponse);
}
In your example, you are creating a CancellationTokenSource - you need to hold a reference to it, so that the next time the handler is invoked, the previous search can be cancelled. Here is an example console app that you should be able to run, but the important piece is in the handler.
private CancellationTokenSource _cts;
private async void TextChangedHandler(string text) // async void only for event handlers
{
try
{
_cts?.Cancel(); // cancel previous search
}
catch (ObjectDisposedException) // in case previous search completed
{
}
using (_cts = new CancellationTokenSource())
{
try
{
await Task.Delay(TimeSpan.FromSeconds(1), _cts.Token); // buffer
var users = await _userService.SearchUsersAsync(text, _cts.Token);
Console.WriteLine($"Got users with IDs: {string.Join(", ", users)}");
}
catch (TaskCanceledException) // if the operation is cancelled, do nothing
{
}
}
}
Be sure to pass the CancellationToken into all of the async methods, including those that perform the web request, this way you signal the cancellation right down to the lowest level.
Try to use timer. First time then you change text - you create it. Then you change text after that - you restart timer. If you don't change text for 700 milliseconds - timer will fire PerformeSearch method. Use Timeout.Infinite for timer period parameter to prevent it from restarting.
textview.TextChange += (sender,e) =>
{
if (_fieldChangeTimer == null)
_fieldChangeTimer = new Timer(delegate
{
PerformeSearch();
}, null, 700, Timeout.Infinite);
else
{
_fieldChangeTimer.Change(700, Timeout.Infinite);
}
};
Instantiate the CancellationTokenSource.
cts = new CancellationTokenSource(); Example method
private void cancelButton_Click(object sender, RoutedEventArgs e)
{
if (cts != null)
{
cts.Cancel();
}
}

c# TimeOut all httpwebrequests

this is not a question on how to abort thread pointhunters.
i am making a multi-threaded program which has a httpwebrequest in each one of the running threads and I figured that if I want to stop all of them what they are doing midway thru I must time them out.
is there a way to do that on a multi-threaded basis?
each thread looks like this:
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
webRequest.Method = "GET";
webRequest.Accept = "text/html";
webRequest.AllowAutoRedirect = false;
webRequest.Timeout = 1000 * 10;
webRequest.ServicePoint.Expect100Continue = false;
webRequest.ServicePoint.ConnectionLimit = 100;
webRequest.UserAgent = "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.152 Safari/537.36";
webRequest.Proxy = null;
WebResponse resp;
string htmlCode = null;
try
{
resp = webRequest.GetResponse();
StreamReader sr = new StreamReader(resp.GetResponseStream(), System.Text.Encoding.UTF8);
htmlCode = sr.ReadToEnd();
sr.Close();
resp.Close();
}
catch (Exception)
Timing out events explicitly is not a good method. You may want to look into
Cancel Async Tasks after a Period of Time.
You can cancel an asynchronous operation after a period of time by
using the CancellationTokenSource.CancelAfter method if you don't want
to wait for the operation to finish. This method schedules the
cancellation of any associated tasks that aren’t complete within the
period of time that’s designated by the CancelAfter expression.
Sample code from MSDN :
// Declare a System.Threading.CancellationTokenSource.
CancellationTokenSource cts;
private async void startButton_Click(object sender, RoutedEventArgs e)
{
// Instantiate the CancellationTokenSource.
cts = new CancellationTokenSource();
resultsTextBox.Clear();
try
{
// ***Set up the CancellationTokenSource to cancel after 2.5 seconds. (You
// can adjust the time.)
cts.CancelAfter(2500);
await AccessTheWebAsync(cts.Token);
resultsTextBox.Text += "\r\nDownloads succeeded.\r\n";
}
catch (OperationCanceledException)
{
resultsTextBox.Text += "\r\nDownloads canceled.\r\n";
}
catch (Exception)
{
resultsTextBox.Text += "\r\nDownloads failed.\r\n";
}
cts = null;
}
// You can still include a Cancel button if you want to.
private void cancelButton_Click(object sender, RoutedEventArgs e)
{
if (cts != null)
{
cts.Cancel();
}
}
async Task AccessTheWebAsync(CancellationToken ct)
{
// Declare an HttpClient object.
HttpClient client = new HttpClient();
// Make a list of web addresses.
List<string> urlList = SetUpURLList();
foreach (var url in urlList)
{
// GetAsync returns a Task<HttpResponseMessage>.
// Argument ct carries the message if the Cancel button is chosen.
// Note that the Cancel button cancels all remaining downloads.
HttpResponseMessage response = await client.GetAsync(url, ct);
// Retrieve the website contents from the HttpResponseMessage.
byte[] urlContents = await response.Content.ReadAsByteArrayAsync();
resultsTextBox.Text +=
String.Format("\r\nLength of the downloaded string: {0}.\r\n"
, urlContents.Length);
}
}
There is also Thread.Abort Method which terminates the thread.
EDIT : Canceling the Task - A better Explanation (source)
The Task class provides a way to cancel the started task based on the CancellationTokenSource class.
Steps to cancel a task:
The asynchronous method should except a parameter of type CancellationToken
Create an instance of CancellationTokenSource class like: var cts = new CancellationTokenSource();
Pass the CancellationToken from the instace to the asynchronous method, like: Task<string> t1 = GreetingAsync("Bulbul", cts.Token);
From the long running method, we have to call ThrowIfCancellationRequested() method of CancellationToken.
static string Greeting(string name, CancellationToken token)
{
Thread.Sleep(3000);
token. ThrowIfCancellationRequested();
return string.Format("Hello, {0}", name);
}
Catch the OperationCanceledException from where we are awiting for the Task.
We can cancel the operation by calling Cancel method of instance of CancellationTokenSource, OperationCanceledException will be thrown from the long running operation. We can set time to cancel the operation to the instanc also.
Further Details - MSDN Link.
static void Main(string[] args)
{
CallWithAsync();
Console.ReadKey();
}
async static void CallWithAsync()
{
try
{
CancellationTokenSource source = new CancellationTokenSource();
source.CancelAfter(TimeSpan.FromSeconds(1));
var t1 = await GreetingAsync("Bulbul", source.Token);
}
catch (OperationCanceledException ex)
{
Console.WriteLine(ex.Message);
}
}
static Task<string> GreetingAsync(string name, CancellationToken token)
{
return Task.Run<string>(() =>
{
return Greeting(name, token);
});
}
static string Greeting(string name, CancellationToken token)
{
Thread.Sleep(3000);
token.ThrowIfCancellationRequested();
return string.Format("Hello, {0}", name);
}

TcpClient.BeginConnect takes too much time to finish with wrong IPs [duplicate]

I have a TcpClient which I use to send data to a listener on a remote computer. The remote computer will sometimes be on and sometimes off. Because of this, the TcpClient will fail to connect often. I want the TcpClient to timeout after one second, so it doesn't take much time when it can't connect to the remote computer. Currently, I use this code for the TcpClient:
try
{
TcpClient client = new TcpClient("remotehost", this.Port);
client.SendTimeout = 1000;
Byte[] data = System.Text.Encoding.Unicode.GetBytes(this.Message);
NetworkStream stream = client.GetStream();
stream.Write(data, 0, data.Length);
data = new Byte[512];
Int32 bytes = stream.Read(data, 0, data.Length);
this.Response = System.Text.Encoding.Unicode.GetString(data, 0, bytes);
stream.Close();
client.Close();
FireSentEvent(); //Notifies of success
}
catch (Exception ex)
{
FireFailedEvent(ex); //Notifies of failure
}
This works well enough for handling the task. It sends it if it can, and catches the exception if it can't connect to the remote computer. However, when it can't connect, it takes ten to fifteen seconds to throw the exception. I need it to time out in around one second? How would I change the time out time?
Starting with .NET 4.5, TcpClient has a cool ConnectAsync method that we can use like this, so it's now pretty easy:
var client = new TcpClient();
if (!client.ConnectAsync("remotehost", remotePort).Wait(1000))
{
// connection failure
}
You would need to use the async BeginConnect method of TcpClient instead of attempting to connect synchronously, which is what the constructor does. Something like this:
var client = new TcpClient();
var result = client.BeginConnect("remotehost", this.Port, null, null);
var success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(1));
if (!success)
{
throw new Exception("Failed to connect.");
}
// we have connected
client.EndConnect(result);
Another alternative using https://stackoverflow.com/a/25684549/3975786:
var timeOut = TimeSpan.FromSeconds(5);
var cancellationCompletionSource = new TaskCompletionSource<bool>();
try
{
using (var cts = new CancellationTokenSource(timeOut))
{
using (var client = new TcpClient())
{
var task = client.ConnectAsync(hostUri, portNumber);
using (cts.Token.Register(() => cancellationCompletionSource.TrySetResult(true)))
{
if (task != await Task.WhenAny(task, cancellationCompletionSource.Task))
{
throw new OperationCanceledException(cts.Token);
}
}
...
}
}
}
catch(OperationCanceledException)
{
...
}
The answers above don't cover how to cleanly deal with a connection that has timed out. Calling TcpClient.EndConnect, closing a connection that succeeds but after the timeout, and disposing of the TcpClient.
It may be overkill but this works for me.
private class State
{
public TcpClient Client { get; set; }
public bool Success { get; set; }
}
public TcpClient Connect(string hostName, int port, int timeout)
{
var client = new TcpClient();
//when the connection completes before the timeout it will cause a race
//we want EndConnect to always treat the connection as successful if it wins
var state = new State { Client = client, Success = true };
IAsyncResult ar = client.BeginConnect(hostName, port, EndConnect, state);
state.Success = ar.AsyncWaitHandle.WaitOne(timeout, false);
if (!state.Success || !client.Connected)
throw new Exception("Failed to connect.");
return client;
}
void EndConnect(IAsyncResult ar)
{
var state = (State)ar.AsyncState;
TcpClient client = state.Client;
try
{
client.EndConnect(ar);
}
catch { }
if (client.Connected && state.Success)
return;
client.Close();
}
One thing to take note of is that it is possible for the BeginConnect call to fail before the timeout expires. This may happen if you are attempting a local connection. Here's a modified version of Jon's code...
var client = new TcpClient();
var result = client.BeginConnect("remotehost", Port, null, null);
result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(1));
if (!client.Connected)
{
throw new Exception("Failed to connect.");
}
// we have connected
client.EndConnect(result);
Here is a code improvement based on mcandal solution.
Added exception catching for any exception generated from the client.ConnectAsync task (e.g: SocketException when server is unreachable)
var timeOut = TimeSpan.FromSeconds(5);
var cancellationCompletionSource = new TaskCompletionSource<bool>();
try
{
using (var cts = new CancellationTokenSource(timeOut))
{
using (var client = new TcpClient())
{
var task = client.ConnectAsync(hostUri, portNumber);
using (cts.Token.Register(() => cancellationCompletionSource.TrySetResult(true)))
{
if (task != await Task.WhenAny(task, cancellationCompletionSource.Task))
{
throw new OperationCanceledException(cts.Token);
}
// throw exception inside 'task' (if any)
if (task.Exception?.InnerException != null)
{
throw task.Exception.InnerException;
}
}
...
}
}
}
catch (OperationCanceledException operationCanceledEx)
{
// connection timeout
...
}
catch (SocketException socketEx)
{
...
}
catch (Exception ex)
{
...
}
As Simon Mourier mentioned, it's possible to use ConnectAsync TcpClient's method with Task in addition and stop operation as soon as possible.
For example:
// ...
client = new TcpClient(); // Initialization of TcpClient
CancellationToken ct = new CancellationToken(); // Required for "*.Task()" method
if (client.ConnectAsync(this.ip, this.port).Wait(1000, ct)) // Connect with timeout of 1 second
{
// ... transfer
if (client != null) {
client.Close(); // Close the connection and dispose a TcpClient object
Console.WriteLine("Success");
ct.ThrowIfCancellationRequested(); // Stop asynchronous operation after successull connection(...and transfer(in needed))
}
}
else
{
Console.WriteLine("Connetion timed out");
}
// ...
Also, I would recommended checking out AsyncTcpClient C# library with some examples provided like Server <> Client.
If using async & await and desire to use a time out without blocking, then an alternative and simpler approach from the answer provide by mcandal is to execute the connect on a background thread and await the result. For example:
Task<bool> t = Task.Run(() => client.ConnectAsync(ipAddr, port).Wait(1000));
await t;
if (!t.Result)
{
Console.WriteLine("Connect timed out");
return; // Set/return an error code or throw here.
}
// Successful Connection - if we get to here.
See the Task.Wait MSDN article for more info and other examples.
I am using these generic methods; they can add timeout and cancellation tokens for any async task. Let me know if you see any problem so I can fix it accordingly.
public static async Task<T> RunTask<T>(Task<T> task, int timeout = 0, CancellationToken cancellationToken = default)
{
await RunTask((Task)task, timeout, cancellationToken);
return await task;
}
public static async Task RunTask(Task task, int timeout = 0, CancellationToken cancellationToken = default)
{
if (timeout == 0) timeout = -1;
var timeoutTask = Task.Delay(timeout, cancellationToken);
await Task.WhenAny(task, timeoutTask);
cancellationToken.ThrowIfCancellationRequested();
if (timeoutTask.IsCompleted)
throw new TimeoutException();
await task;
}
Usage
await RunTask(tcpClient.ConnectAsync("yourhost.com", 443), timeout: 1000);

How to await for multiple tasks when using lambda exp on the event handler

I have 2 classes Main.cs and Processing.cs (P and M for short) class M makes a call to P passing an html link, P in tern downloads, converts to Base64, renames and saves the file then returns a string back to M, now i need M to wait until all of this is complete to proceed but i have not been able to.
I used a lambda expression with the event handler to be able to do everything in that function as opposed to a separate function for the event trigger so i would be able to return the string with the Base64 converted file, but it just returns the empty string, not wait until it has been assigned.
I thought the taskA.Wait() call would make it wait until all processing was done, but it's not the case
If anyone has any ideas I would appreciate the help.
the call from Main.cs is like this:
Processing processing = new processing();
String _link = “http://www.something.com”;
var ResultBase64_Val = processing.FileToBase64(_link).Result;
In Processing.cs the function is:
public async Task<String> FileToBase64(String filePath)
{
String convertedFile = "";
WebClient client = new WebClient();
Task taskA = Task.Factory.StartNew(() => client.OpenReadCompleted += async (object sender, OpenReadCompletedEventArgs e) =>
{
byte[] buffer = new byte[e.Result.Length];
buffer = new byte[e.Result.Length];
await e.Result.ReadAsync(buffer, 0, buffer.Length);
convertedFile = Convert.ToBase64String(buffer);
});
client.OpenReadAsync(new Uri(filePath));
taskA.Wait();
return convertedFile;
}
Thanks,
Bob
The problem with your code is that the task started with Task.Factory.StartNew completes instantly, well before OpenReadCompleted is fired sometime in the future. That said, wrapping a naturally asynchronous API like OpenReadAsync with Task.Run or Task.Factory.StartNew is a bad idea anyway. Even if you waited for the event somehow, or used synchronous OpenRead, you'd be wasting a pool thread.
There's new WebClient.OpenReadTaskAsync method for that:
public async Task<String> FileToBase64(String filePath)
{
using (var client = new WebClient())
using (var stream = await client.OpenReadTaskAsync(new Uri(filePath)))
{
// use stream.ReadAsync
}
}
I also recommend HttpClient over WebClient, the former supports multiple HTTP requests in parallel:
using System.Net.Http;
// ...
public async Task<String> FileToBase64(String filePath)
{
using (var client = new HttpClient())
using (var response = await client.GetAsync(filePath))
using (var stream = await response.Content.ReadAsStreamAsync())
{
return string.Empty;
// use stream.ReadAsync
}
}
If you want to use the WebClient, and you want to return result from the method, you'll want to use the TaskCompletionSource and subscribe to the event normally
public Task<String> FileToBase64(String filePath)
{
TaskCompletionSource<string> completion = new TaskCompletionSource<string>();
String convertedFile = "";
WebClient client = new WebClient();
client.OpenReadCompleted += (s, e) =>
{
TextReader reader = new StreamReader(e.Result);
string result = reader.ReadToEnd();
completion.SetResult(result);
};
client.OpenReadAsync(new Uri(filePath));
return completion.Task;
}
Given this answer, I would recommend using the HttpClient instead of the WebClient
Both Noseratio answer and Shawn Kendrot answer should work. But I will try to use other approach - by WebRequest.
First to do this I will have to extend my WebRequest method by GetRequestStreamAsync() - WP lacks this method:
public static class Extensions
{
public static Task<Stream> GetRequestStreamAsync(this WebRequest webRequest)
{
TaskCompletionSource<Stream> taskComplete = new TaskCompletionSource<Stream>();
webRequest.BeginGetRequestStream(arg =>
{
try
{
Stream requestStream = webRequest.EndGetRequestStream(arg);
taskComplete.TrySetResult(requestStream);
}
catch (Exception ex) { taskComplete.SetException(ex); }
}, webRequest);
return taskComplete.Task;
}
}
Then I would convert your Task to something like this:
public async Task<string> FileToBase64(string filePath)
{
try
{
WebRequest request = WebRequest.Create(new Uri(filePath));
if (request != null)
{
using (Stream resopnse = await request.GetRequestStreamAsync())
using (MemoryStream temp = new MemoryStream())
{
const int BUFFER_SIZE = 1024;
byte[] buf = new byte[BUFFER_SIZE];
int bytesread = 0;
while ((bytesread = await resopnse.ReadAsync(buf, 0, BUFFER_SIZE)) > 0)
temp.Write(buf, 0, bytesread);
return Convert.ToBase64String(temp.ToArray());
}
}
return String.Empty;
}
catch { return String.Empty; }
}
Maybe this will help.
First of all, don't use Task.Factory.StartNew with async methods. Stephen Toub and Stephen Clearly have explained why.
Second, if you're using async-await, then you can use the ~TaskAsync methods of the WebClient class with the Microsoft Async NuGet package - given that you said it's for Windows Phone 8.
On a side note, you should always suffix your asynchronous methods with Async (or TaskAsync if not possible).
Given that, your code becomes:
public async Task<String> FileToBase64Async(String filePath)
{
String convertedFile = "";
var client = new WebClient();
Task taskA = Task.Factory.StartNew(() => client.OpenReadCompleted += async (object sender, OpenReadCompletedEventArgs e) =>
{
var buffer = await webclient.DownloadDataTaskAsync(filePath);
convertedFile = Convert.ToBase64String(buffer);
return convertedFile;
}
}
But you would be better served with the new HttpClient class that you can find on the Microsoft HTTP Client Libraries NuGet package.
And finally, you should not block on async code in the UI thread.

Windows process is unable to terminate when an application performs lots of async http requests

I have a question regarding strange behavior of a process that performs lots of async unsuccessful requests to a server.
The strange thing is that it's almost impossible to exit/stop/kill the process.
If you compile and run this program on a windows 8 machine the process hangs and I haven't found a solution how to kill it. Only reboot helps.
Could somebody explain the mentioned behavior please.
Thanks.
PS: This is what I get when use taskmanager to kill the process
internal class Program
{
private const int totalRequests = 2000;
private static void Main(string[] args)
{
var cancellationTockenSource = new CancellationTokenSource();
LoadTest(cancellationTockenSource);
Console.WriteLine("Press any key to break");
Console.ReadLine();
cancellationTockenSource.Cancel();
}
private static async Task LoadTest(CancellationTokenSource cancellationTockenSource)
{
Stopwatch stopWatch = Stopwatch.StartNew();
var requests = new List<Task>(totalRequests);
for (int i = 0; i < totalRequests; ++i)
{
requests.Add(Request(cancellationTockenSource.Token));
}
try
{
await Task.WhenAll(requests);
}
catch (Exception e)
{
Console.WriteLine(e);
}
stopWatch.Stop();
Console.WriteLine("{0} req/sec", stopWatch.Elapsed.TotalSeconds/totalRequests);
}
private static HttpRequestMessage CreateMessage()
{
var url = new Uri("http://ya.ru:8080/234234234234x");
var message = new HttpRequestMessage(HttpMethod.Get, url);
message.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json"));
return message;
}
protected static async Task<string> Request(CancellationToken token)
{
using (var client = new HttpClient())
{
HttpResponseMessage response = await client.SendAsync(CreateMessage(), token);
string content = await response.Content.ReadAsStringAsync();
return content;
}
}
}

Categories

Resources