I'm using HttpWebRequest to call a web service. If the AsyncCallback from BeginGetResponse throws an error, I want to propagate it up to my main program flow. I'm having trouble doing this because the error doesn't get propagated beyond the AsyncCallback. I've tried putting try/catch blocks at each step of the HttpWebRequest chain, but it never propagates beyond the "ResponseCallBack" method. Is it possible to get it back to the main thread?
private void StartRequest()
{
// Code to create request object is here
// ...
httpRequest.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), httpRequest);
}
private void GetRequestStreamCallback(IAsyncResult result)
{
HttpWebRequest request = (HttpWebRequest)result.AsyncState;
// End the operation
var postStream = request.EndGetRequestStream(result);
string body = GenerateRequestBody();
// Convert the string into a byte array
byte[] postBytes = Encoding.UTF8.GetBytes(body);
// Write to request stream
postStream.Write(postBytes, 0, postBytes.Length);
postStream.Close();
// Start the asynchronous operation to get the resonse
try
{
request.BeginGetResponse(new AsyncCallback(ResponseCallback), request);
}
catch (Exception)
{
throw;
}
}
private void ResponseCallback(IAsyncResult result)
{
string contents = String.Empty;
HttpWebRequest request = (HttpWebRequest)result.AsyncState;
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(result);
using (Stream stream = response.GetResponseStream())
using (StreamReader reader = new StreamReader(stream))
{
contents = reader.ReadToEnd();
}
// Check the status
if (response.StatusCode == HttpStatusCode.OK)
{
//EXCEPTION NEVER MAKES IT PASSED HERE, EVEN IF I HAVE IT IN A TRY/CATCH BLOCK AND RE-THROW IT.
_object = ProcessResponseEntity(contents);
}
}
I think you're getting confused about the way asynchronous code exectution works and how the callback execution fits in with the calling code.
Within GetRequestStreamCallback, after the call to request.BeginGetResponse the method will continue to execute and in your example just end.
It is not known when (or even if) ResponseCallback will execute or what will be happening on the UI thread when it does. Because of this, ResponseCallback will execute on a different thread.
It's possible to have code within the callback run on the UI thread (which you'll need to do you want to interact with the UI) by using Dispatcher.BeginInvoke. However you can't have this execute within the context of another method.
While I wouldn't recommend it, you may want to have a look at this discussion on making the callback appear to execute synchronously. This will block your UI thread though and so is NOT recommended.
Related
In my WCF service, I have to make a call to an API, where I wanted to do a Fire and Forget implementation. And If possible just capture the errors if any.(That's fine too , if not an option)
I am planning to do the following implementation, what are the issues it could lead to? By doing the following implementation is going to leave a huge number of open connections. Or what could be the issue? Please help in understanding how in a better way this can be implemented.
void SendRequest(inputs)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);
request.Method = "POST";
request.ContentType = "application/xml";
byte[] requestBytes = Encoding.UTF8.GetBytes(inputXML);
using (Stream requestStream = request.GetRequestStream())
{
requestStream.Write(requestBytes, 0, requestBytes.Length);
}
request.GetResponseAsync();
}
Main()
{
try
SendRequest(inputs);
catch ex
log ex;
}
First, make fully async version of your code
using System.Threading;
public async Task<System.Net.WebResponse> SendRequestAsync(
string inputXML, string url, CancellationToken cancellationToken)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST";
request.ContentType = "application/xml";
byte[] requestBytes = Encoding.UTF8.GetBytes(inputXML);
// GetRequestStreamAsync is a lightweight operation I assume
// so we don't really need any cancellation
using (Stream requestStream = await request.GetRequestStreamAsync())
{
// Idk if we really need cancellation here, but just in case of big request we might need to
await requestStream.WriteAsync(
requestBytes, 0, requestBytes.Length, cancellationToken);
}
// Close any long-running request
using (cancellationToken.Register(() => request.Abort(), useSynchronizationContext: false))
{
var response = await request.GetResponseAsync();
cancellationToken.ThrowIfCancellationRequested();
return response;
}
}
Let's create an async void method, but make it safe. It will basically execute in "fire-and-forget" manner.
public async void DoWork(string inputXML, string url, CancellationToken ct)
{
try
{
using(var response = await SendRequestAsync(inputXML, url, ct))
{
var httpResponse = (HttpWebResponse) response;
// Use 201 Created or whatever you need
if (httpResponse.StatusCode != HttpStatusCode.Created)
{
// TODO: handle wrong status code
}
}
}
catch (Exception e)
{
if (ct.IsCancellationRequested)
{
Console.WriteLine("Cancelled");
}
else
{
// TODO: handle exception
}
}
}
private static CancellationTokenSource _cts = new CancellationTokenSource();
public static void Main (string[] args)
{
DoWork("xml string", "example.com", cts.Token);
Console.WriteLine("Boom!");
if (Console.ReadLine() == "exit")
{
// Cancel the damn job
cts.Cancel();
}
}
It's important to handle all errors from inside a DoWork, because following will not work
// Warning, will NOT catch an exception
public static void Main (string[] args)
{
try
{
DoWork("xml string", "example.com");
}
catch (Exception e)
{
}
}
EDIT: OP requested cancellation so I added cancellation
Please note that it's not best practice not to use fire and forget, especially if this a core layer of the application and you might miss important exceptions. When you use this technique you have to remember that the following happens:
Exception will be fail silently without any chance of catching them. normally you will want to log them or get a notification.
You have no idea when the code completes,
Since You don't need the code to complete and it might may not run to you would have no notification that it failed to complete.
A good case scenario for using this technique could be for updating a cache for an example.
Having said that, you could use the following techniques:
NET 4.5 allows us to use it via Task.Run
Task.Run(() => FireAndForget());
You could also start a thread with parameterless lambda:
(new Thread(() => {
FireAndForget();
}) {
Name = "Running Work Thread (FireAndForget)",
Priority = ThreadPriority.BelowNormal
}).Start();
I've been reading Essential C# 6.0 recently. In the chapter of the book where author explains multi threading he shows this method and I don't understand two things about it which don't seem to be explained anywhere.
private static Task WriteWebRequestSizeAsync(string url)
{
StreamReader reader = null;
WebRequest webRequest = WebRequest.Create(url);
Task task = webRequest.GetResponseAsync()
.ContinueWith(antecedent =>
{
WebResponse response = antecedent.Result;
reader = new StreamReader(response.GetResponseStream());
return reader.ReadToEndAsync();
})
.Unwrap()
.ContinueWith(antecedent =>
{
if(reader != null) reader.Dispose();
string text = antecedent.Result;
Console.WriteLine(text.Length);
});
return task;
}
1. Why does the author use ContinueWith() methods and calls them essential? How is his way of doing it better than my approach, which does not utilize these methods?
private static Task WriteWebRequestSizeAsync(string url)
{
return Task.Run(() =>
{
WebRequest webRequest = WebRequest.Create(url);
WebResponse response = webRequest.GetResponseAsync().Result;
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
string text = reader.ReadToEndAsync().Result;
Console.WriteLine(text.Length);
}
});
}
2. Why does the author use async variants of the methods and then access their result via .Result property, instead of using not async variants as it appears to have the same result at the end. Please, notice that I haven't changed it in my approach above
Although you are calling GetResponseAsync() in your method, however, trying to use .Result makes it a blocking call.As a result of this your task continues to wait for the result to be available wasting cpu cycles.
WebResponse response = webRequest.GetResponseAsync().Result; //blocking call
However, in the example by author, GetResponseAsync() is followed by a ContinueWith(). This means that Task on which GetResponseAsync() is called won't be blocked and can be utilized to do something else. When the result of GetResponseAsync() is available the continuation will run.
webRequest.GetResponseAsync()
.ContinueWith(antecedent =>
{
WebResponse response = antecedent.Result;
reader = new StreamReader(response.GetResponseStream());
return reader.ReadToEndAsync();
})
Same example can also be written using async and await instead of continuation...This will have a similar effect of continuations . However, this will be more natural to read.
var result = await webRequest.GetResponseAsync();
//do something with result now.
It seems as if the author uses stacked continuation in order to split the operations according to the seperation of concerns principle.
Main difference between yours and authors way is that author runs code in the same thread from what method WriteWebRequestSizeAsync while your code will run in some thread from ThreadPull.
I don't know context so may be it's essential.
About second question. If author calls not async methods he could not get tasks and attach to them ContinueWith.
I'm trying to learn the async and await mechanisms in C#.
The simplest example is clear to me.
The line
Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");
triggers an asynchronous web call. The control returns to AccessTheWebAsync(). It is free to perform DoIndependentWork(). After doing this it waits for the completion of the task getStringTask and when this result is available the function executes the next line
return urlContents.Length;
So, as far as I understand the purpose of the async call is to let the caller execute other operations when the operation tagged with async is in progress.
However, I'm bit confused with the example, in this function.
private async Task<byte[]> GetURLContentsAsync(string url)
{
// The downloaded resource ends up in the variable named content.
var content = new MemoryStream();
// Initialize an HttpWebRequest for the current URL.
var webReq = (HttpWebRequest)WebRequest.Create(url);
// Send the request to the Internet resource and wait for
// the response.
using (WebResponse response = await webReq.GetResponseAsync())
// The previous statement abbreviates the following two statements.
//Task<WebResponse> responseTask = webReq.GetResponseAsync();
//using (WebResponse response = await responseTask)
{
// Get the data stream that is associated with the specified url.
using (Stream responseStream = response.GetResponseStream())
{
// Read the bytes in responseStream and copy them to content.
await responseStream.CopyToAsync(content);
// The previous statement abbreviates the following two statements.
// CopyToAsync returns a Task, not a Task<T>.
//Task copyTask = responseStream.CopyToAsync(content);
// When copyTask is completed, content contains a copy of
// responseStream.
//await copyTask;
}
}
// Return the result as a byte array.
return content.ToArray();
}
Inside the method GetURLContentsAsync(), there are two async invocations. However, the API waits with an await call on both. The caller is not doing anything between the trigger of the async operation and the receipt of the data. So, as far as I understand, the async/await mechanism brings no benefit here. Am I missing something obvious here?
Your code doesn't need to explicitly be doing anything between await'd async calls to gain benefit. It means that the thread isn't sitting waiting for each call to complete, it is available to do other work.
If this is a web application it can result in more requests being processed. If it is a Windows application it means the UI thread isn't blocked and the user has a better experience.
However, the API waits with an await call on both.
You will have to await for the both because your method code should get executed sequentially, if you don't await the first call, your next lines of code will also get executed which is something you might not expect or need to happen.
The following two reasons that come in my mind for awaiting both methods are:
it is possible that your first async method result is used as
parameter in your second async method call
it is also possible that we decide on the result of first async
method call that the second async method to be called or not
So if that's the case then it is quite clear why you would not need to add await to every async method call inside your async method.
EDIT:
From the example which you are pointing to clearly you can see that the output of first async method is being used in the second async method call here:
using (WebResponse response = await webReq.GetResponseAsync())
// The previous statement abbreviates the following two statements.
//using (WebResponse response = await responseTask)
{
// Get the data stream that is associated with the specified url.
using (Stream responseStream = response.GetResponseStream())
{
// Read the bytes in responseStream and copy them to content.
await responseStream.CopyToAsync(content);
// The previous statement abbreviates the following two statements.
// CopyToAsync returns a Task, not a Task<T>.
//Task copyTask = responseStream.CopyToAsync(content);
// When copyTask is completed, content contains a copy of
// responseStream.
//await copyTask;
}
}
GetResponseAsync returns when the web server starts its response (by sending the headers), while CopyToAsync returns once all the data has been sent from the server and copied to the other stream.
If you add code to record how much time elapses between the start of the asynchronous call and the return to your function, you'll see that both methods take some time to complete (on a large file, at least.)
private static async Task<byte[]> GetURLContentsAsync(string url) {
var content = new MemoryStream();
var webReq = (HttpWebRequest)WebRequest.Create(url);
DateTime responseStart = DateTime.Now;
using (WebResponse response = await webReq.GetResponseAsync()) {
Console.WriteLine($"GetResponseAsync time: {(DateTime.Now - responseStart).TotalSeconds}");
using (Stream responseStream = response.GetResponseStream()) {
DateTime copyStart = DateTime.Now;
await responseStream.CopyToAsync(content);
Console.WriteLine($"CopyToAsync time: {(DateTime.Now - copyStart).TotalSeconds}");
}
}
return content.ToArray();
}
For a ~40 MB file on a fast server, the first await is quick while the second await takes longer.
https://ftp.mozilla.org/pub/thunderbird/releases/52.2.1/win32/en-US/Thunderbird%20Setup%2052.2.1.exe
GetResponseAsync time: 0.3422409
CopyToAsync time: 5.3175731
But for a server that takes a while to respond, the first await can take a while too.
http://www.fakeresponse.com/api/?sleep=3
GetResponseAsync time: 3.3125195
CopyToAsync time: 0
I have the following extension methods for using asynchronous calls on WebRequest objects.
public static Task<WebResponse> GetReponseAsync(this WebRequest request)
{
return Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null);
}
public static Task<Stream> GetRequestStreamAsync(this WebRequest request)
{
return Task.Factory.FromAsync<Stream>(request.BeginGetRequestStream, request.EndGetRequestStream, null);
}
I would like to convert the following code to an asynchronous equivalent using these extension methods.
using (Stream rs = request.GetRequestStream())
{
var postData = Encoding.ASCII.GetBytes(PostData);
rs.Write(postData, 0, postData.Length);
using (WebResponse response = request.GetResponse())
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
str = reader.ReadToEnd();
rs.Close();
reader.Close();
response.Close();
}
}
I did this easily using another piece of code making usage of WebRequest, however that did not require the first call to GetRequestStream().
request.GetReponseAsync().ContinueWith(t =>
{
if (t.Exception == null)
{
using (var sr = new StreamReader(t.Result.GetResponseStream()))
{
str = sr.ReadToEnd();
}
}
});
How do I convert the first code block to use my extension methods and be equivalent?
EDIT I am using .NET 4.0, so async/await is not currently an option.
You just need to chain the ContinueWith calls. As a rule of thumb, you will have one ContinueWith per async operation in the sequence. Each ContinueWith will generally end with return <some async call> and the next will start process its result.
request.GetRequestStreamAsync()
.ContinueWith((trs) =>
{
var postData = System.Text.Encoding.ASCII.GetBytes("dummy");
trs.Result.Write(postData, 0, postData.Length);
return request.GetResponseAsync();
}).Unwrap()
.ContinueWith((resp) =>
{
using (var sr = new StreamReader(resp.Result.GetResponseStream()))
{
var str = sr.ReadToEnd();
}
});
Note that in my code (and your asynchronous version), not all of the objects are getting disposed as they were in the original.
At each step, you probably want to either check the Status or IsFaulted/IsCanceled properties or use the overload of ContinueWith that takes a TaskContinuationOptions parameter. For the latter option, beware that the previous task not completing in a way that matches the options results in a cancelled task. If you need to pass the errors through, that approach will not. Personally, I wrap all the checking into a method that either passes through errors and cancellation or runs a delegate on successful completion. Otherwise, you get a lot of boilerplate checking code very quickly.
I have C# code and have a problem with webRequest.begingetresponse.
When I try to used it for asynchronous call, the working thread is blocked and waits for the callback to be called. But, as I read in documentation, the current thread should continue to run and the callback method should be invoked by a different thread once the response is back from the server.
[UPDATE] Actually getting the response back from the server is where the current thread is blocked, and when I check the thread IDs, the thread which calls the callback is the same thread who sent the request.
Any idea what I might be missing?
Here's a snippet of the code:
public class MyRequestState
{
public WebRequest Request;
public WebResponse Response;
public ManualResetEvent allDone = new ManualResetEvent(false);
public MyRequestState()
{
Request = null;
Response = null;
}
}
public class SendRequest
{
private void ResponseCallback(IAsyncResult result)
{
//do sth ...
state.Response = (HttpWebResponse)request.EndGetResponse(result);
//do sth ...
state.allDone.Set();
}
public void MakeWebRequestAsync(string url)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "GET";
request.Proxy = null;
state state = new MyRequestState();
state.Request = request;
IAsyncResult result = request.BeginGetResponse(new System.AsyncCallback(ResponseCallback), state);
state.allDone.WaitOne();
}
}
WebRequest.BeginGetResponse wait for connection synchronously and then receive data asynchronously. If the connection takes some times, it will freeze the calling thread for a while.
You are waiting on your ManualResetEvent right after starting the request. That's why your thread blocks. The thread isn't being signaled to continue until your completed callback is called.