I'm having a hard time tracing an exception within a Task. The message returned from the exception isn't helpful at all. Below is the method that appears to be throwing the exception:
public async Task<bool> TestProxy(IPEndPoint proxy)
{
Ping ping = new Ping();
PingReply reply = await ping.SendPingAsync(proxy.Address);
if (reply == null || reply.Status != IPStatus.Success) return false;
HttpClient client = new HttpClient();
HttpResponseMessage response;
try
{
response = await client.GetAsync("https://google.com");
} catch(Exception ex)
{
return false;
Console.WriteLine(ex.Message);
}
if(response.IsSuccessStatusCode)
{
return true;
}
else
{
return false;
}
And here is the calling code:
public async Task<List<IPEndPoint>> FetchWorkingProxiesAsync()
{
List<IPEndPoint> _proxies = await FetchRawProxiesAsync();
List<IPEndPoint> workingProxies = new List<IPEndPoint>();
Task[] tasks = new Task[_proxies.Count];
for(int i = 0; i < _proxies.Count; i++)
{
IPEndPoint _tmpProxy = _proxies[i];
tasks[i] = Task.Run(async () => {
try
{
if (await TestProxy(_tmpProxy))
{
workingProxies.Add(_tmpProxy);
}
}catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
});
}
await Task.WhenAll(tasks);
return workingProxies;
}
The exception that is being thrown is:
InnerException {"The request was aborted: The request was canceled."} System.Exception {System.Net.WebException}
When I set breakpoints no helpful information is available on the exception. I see that there's a System.Net.WebException but it doesn't say what or why.
I have CLR Throw and User Exceptions ticked in the Exceptions dialogue in VS.
Edit: I just realised I am not using the proxy to test the connection when attempting to connect to google.com. Even so, I'd still like to know how to find out more about the exception thrown.
Related
I ran into the following problem: I start a task to process responses from a bot in a telegram for a long execution
Task.Factory.StartNew(() => _.RunAsync(), TaskCreationOptions.LongRunning)
_ - is an instance of my service
method code below:
/// <inheritdoc />
public async Task RunAsync()
{
// запуск метода рассылки пользователям сообщений со стоимостями их портфелей
await _notifier.RunAsync(_cancellationTokenSource.Token);
var updateReceiver = _telegramClient.GetUpdateReceiver(
new[]
{
UpdateType.Message,
UpdateType.CallbackQuery,
});
try
{
Logger.Info("Revaluate portfolios service successfully launched!");
await foreach (var update in updateReceiver.WithCancellation(_cancellationTokenSource.Token))
{
var updateModel = new UpdateModel()
{
Text = update.Message?.Text ?? update.CallbackQuery?.Data,
ChatId = update.Message?.Chat.Id ?? update.CallbackQuery?.Message?.Chat.Id ?? 0,
Phone = update.Message?.Contact?.PhoneNumber ?? "",
From = update.Message?.From ?? update.CallbackQuery?.From
};
await HandleMessageAsync(updateModel);
}
}
catch (OperationCanceledException exception)
{
Logger.Error(exception, "The service was stopped by token cancellation. Reason: ");
throw;
}
catch (Exception ex)
{
Logger.Error(ex);
throw;
}
finally
{
Dispose();
}
}
I assume that the error is called from a method await HandleMessageAsync(updateModel);
where I used _cancellationTokenSource.Token.
I received next error on my server (Ubuntu 2G RAM, 2 Core, 40G SSD):
RevaluatePortfoliosService|The service was stopped by token cancellation. Reason: System.OperationCanceledException: The operation was canceled
But nothing could cause the cancellation. I don't understand why this is happening
I have Web Api which gets CancellationToken from users, the method inside it (DoWork) also get CancellationToken:
[HttpPost]
public async Task<long> GetInfo(CancellationToken cancellationToken)
{
long result = 0;
bool notDone = true;
Task<long> t = Task.Run(async () =>
{
if (cancellationToken.IsCancellationRequested)
cancellationToken.ThrowIfCancellationRequested();
while (notDone && !cancellationToken.IsCancellationRequested)
{
result = await DoWork(cancellationToken);
notDone = false;
}
return result;
}, cancellationToken);
try
{
return await t;
}
catch (AggregateException e)
{
Debug.WriteLine("Exception messages:");
foreach (var ie in e.InnerExceptions)
Debug.WriteLine(" {0}: {1}", ie.GetType().Name, ie.Message);
Debug.WriteLine("\nTask status: {0}", t.Status);
throw;
}
catch (Exception ex)
{
throw;
}
}
private Task<long> DoWork(CancellationToken token)
{
long result = 0;
bool notDone = true;
Task<long> task = Task.Run(() =>
{
if (token.IsCancellationRequested)
token.ThrowIfCancellationRequested();
while (notDone && !token.IsCancellationRequested)
{
Thread.Sleep(8000);
result = 2;
notDone = false;
}
return result;
}, token);
return task;
}
I expect when the user cancels the request it aborts the DoWork method and not continue the function, but after sending an Exception, when "Thread.Sleep" complete, the DoWork method continue.
the user can call the API service like this method "cc" as you can see it cancel after 5 seconds and in the DoWork method "Thread.Sleep" is 9 seconds. the user gets an Exception but the method still running.
private async Task<bool> cc()
{
UriBuilder builder = new UriBuilder("http://localhost:12458/api/Test/GetInfo");
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
HttpClient client = new HttpClient();
System.Threading.CancellationTokenSource s = new System.Threading.CancellationTokenSource();
s.CancelAfter(5000);
try
{
var result = client.PostAsJsonAsync<model1>(builder.ToString(), new model1 { }, s.Token).Result;
string tmp = result.Content.ReadAsStringAsync().Result;
long ApiResult = JsonConvert.DeserializeObject<long>(tmp);
}
catch (TaskCanceledException ex)
{
}
catch (OperationCanceledException ex)
{
}
catch (Exception ex)
{
}
finally
{
s.Dispose();
}
return false;
}
When use Thread.Sleep(8000) actually hold the main thread for 8 seconds and It can't check the cancellation token. you should use Task.Delay with cancellation token like this:
while (notDone && !token.IsCancellationRequested)
{
await Task.Delay(8000, token);
result = 2;
notDone = false;
}
Task.Delay check the cancellation token itself.
Ok, in your code you should process CancellationToken.IsCancellationRequested too. It's not kinda of magic, you should do this work.
public void DoWork(CancellationToken ctsToken)
{
ctsToken.ThrowIfCancellationRequested();
DoSomething();
ctsToken.ThrowIfCancellationRequested();
DoSomethingElse();
// end so on with checking CancellationToken before every part of work
}
And your Task should look like this
Task<long> t = Task.Run(async () =>
{
cancellationToken.ThrowIfCancellationRequested();
result = await DoWork(cancellationToken);
notDone = false;
cancellationToken.ThrowIfCancellationRequested();
return result;
}, cancellationToken);
In my case it was because of fiddler. When I closed the fiddler app, it started working like a charm.
I'm getting a System.Net.WebException saying:
The remote server returned an error: (403) Forbidden.
This is what I'm expecting since invalid headers are being passed in with the http request. However, my code does not seem to be catching the exception like I would expect.
Here is the code:
private void callback(IAsyncResult result)
{
Debug.WriteLine("Callback");
HttpWebResponse response = null;
try
{
response = (result.AsyncState as HttpWebRequest).EndGetResponse(result)
as HttpWebResponse;
}
catch (WebException e)
{
Debug.WriteLine("Exception: " + e);
}
catch (Exception e)
{
Debug.WriteLine("Unknown exception: " + e);
}
}
Why is the exception not caught?
Take a look here.
Probably you should do something like this:
Task<WebResponse> task = Task.Factory.FromAsync(
request.BeginGetResponse,
asyncResult => { callback(asyncResult); },
(object)null);
return task.ContinueWith(t =>
{
if (t.IsFaulted)
{
//handle error
Exception firstException = t.Exception.InnerExceptions.First();
}
else
{
return FinishWebRequest(t.Result);
}
});
I've got a Post method in my webapi 2 controller that does an insert into a database but often has to retry for many seconds before it succeeds. Basically, that causes a lot of sleeps between the retries. Effectively, it is running the code below. My question is, is this code correct so that I can have thousands of these running at the same time and not using up my iis page pool?
public async Task<HttpResponseMessage> Post()
{
try
{
HttpContent requestContent = Request.Content;
string json = await requestContent.ReadAsStringAsync();
Thread.Sleep(30000);
//InsertInTable(json);
}
catch (Exception ex)
{
throw ex;
}
return new HttpResponseMessage(HttpStatusCode.OK);
}
* Added By Peter As To Try Stephens's suggestion of Await.Delay. Shows error that can not put await in catch.
public async Task<HttpResponseMessage> PostXXX()
{
HttpContent requestContent = Request.Content;
string json = await requestContent.ReadAsStringAsync();
bool success = false;
int retriesMax = 30;
int retries = retriesMax;
while (retries > 0)
{
try
{
// DO ADO.NET EXECUTE THAT MAY FAIL AND NEED RETRY
retries = 0;
}
catch (SqlException exception)
{
// exception is a deadlock
if (exception.Number == 1205)
{
await Task.Delay(1000);
retries--;
}
// exception is not a deadlock
else
{
throw;
}
}
}
return new HttpResponseMessage(HttpStatusCode.OK);
}
* More Added By Peter, Trying Enterprise block, missing class (StorageTransientErrorDetectionStrategy class not found)
public async Task<HttpResponseMessage> Post()
{
HttpContent requestContent = Request.Content;
string json = await requestContent.ReadAsStringAsync();
var retryStrategy = new Incremental(5, TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(2));
var retryPolicy =
new RetryPolicy<StorageTransientErrorDetectionStrategy>(retryStrategy);
try
{
// Do some work that may result in a transient fault.
retryPolicy.ExecuteAction(
() =>
{
// Call a method that uses Windows Azure storage and which may
// throw a transient exception.
Thread.Sleep(10000);
});
}
catch (Exception)
{
// All the retries failed.
}
*****Code that causes SqlServer to spin out of control with open connections
try
{
await retryPolicy.ExecuteAsync(
async () =>
{
// this opens a SqlServer Connection and Transaction.
// if fails, rolls back and rethrows exception so
// if deadlock, this retry loop will handle correctly
// (caused sqlserver to spin out of control with open
// connections so replacing with simple call and
// letting sendgrid retry non 200 returns)
await InsertBatchWithTransaction(sendGridRecordList);
});
}
catch (Exception)
{
Utils.Log4NetSimple("SendGridController:POST Retries all failed");
}
and the async insert code (with some ...'s)
private static async Task
InsertBatchWithTransaction(List<SendGridRecord> sendGridRecordList)
{
using (
var sqlConnection =
new SqlConnection(...))
{
await sqlConnection.OpenAsync();
const string sqlInsert =
#"INSERT INTO SendGridEvent...
using (SqlTransaction transaction =
sqlConnection.BeginTransaction("SampleTransaction"))
{
using (var sqlCommand = new SqlCommand(sqlInsert, sqlConnection))
{
sqlCommand.Parameters.Add("EventName", SqlDbType.VarChar);
sqlCommand.Transaction = transaction;
try
{
foreach (var sendGridRecord in sendGridRecordList)
{
sqlCommand.Parameters["EventName"].Value =
GetWithMaxLen(sendGridRecord.EventName, 60);
await sqlCommand.ExecuteNonQueryAsync();
}
transaction.Commit();
}
catch (Exception)
{
transaction.Rollback();
throw;
}
}
}
}
}
No. At the very least, you want to replace Thread.Sleep with await Task.Delay. Thread.Sleep will block a thread pool thread in that request context, doing nothing. Using await allows that thread to return to the thread pool to be used for other requests.
You might also want to consider the Transient Fault Handling Application Block.
Update: You can't use await in a catch block; this is a limitation of the C# language in VS2013 (the next version will likely allow this, as I note on my blog). So for now, you have to do something like this:
private async Task RetryAsync(Func<Task> action, int retries = 30)
{
while (retries > 0)
{
try
{
await action();
return;
}
catch (SqlException exception)
{
// exception is not a deadlock
if (exception.Number != 1205)
throw;
}
await Task.Delay(1000);
retries--;
}
throw new Exception("Retry count exceeded");
}
To use the Transient Fault Handling Application Block, first you define what errors are "transient" (should be retried). According to your example code, you only want to retry when there's a SQL deadlock exception:
private sealed class DatabaseDeadlockTransientErrorDetectionStrategy : ITransientErrorDetectionStrategy
{
public bool IsTransient(Exception ex)
{
var sqlException = ex as SqlException;
if (sqlException == null)
return false;
return sqlException.Number == 1205;
}
public static readonly DatabaseDeadlockTransientErrorDetectionStrategy Instance = new DatabaseDeadlockTransientErrorDetectionStrategy();
}
Then you can use it as such:
private static async Task RetryAsync()
{
var retryStrategy = new Incremental(5, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(2));
var retryPolicy = new RetryPolicy(DatabaseDeadlockTransientErrorDetectionStrategy.Instance, retryStrategy);
try
{
// Do some work that may result in a transient fault.
await retryPolicy.ExecuteAsync(
async () =>
{
// TODO: replace with async ADO.NET calls.
await Task.Delay(1000);
});
}
catch (Exception)
{
// All the retries failed.
}
}
I have written a server side code using Sockets, Its working fine but have one problem I don't know how to handle this scenario: if client just closes application without sending Disconnect request, my server side program crashes. What do I need to do to avoid this? Please guide me I am new to Socket programming.
private void OnReceive(IAsyncResult result)
{
try
{
Socket clientSocket = (Socket)result.AsyncState;
clientSocket.EndReceive(result);
command = responseMessage = string.Empty;
command = ByteToString(receviedData);
receviedData = new byte[30];
if (command=="Connect")
{
ClientInfo clientInfo = new ClientInfo();
clientInfo.socket = clientSocket;
clientInfo.IP = clientSocket.RemoteEndPoint.ToString();
connectedClients.Add(clientInfo);
responseMessage = "Connection established...";
}
else if (command=="Disconnect")
{
for (int i = 0; i < connectedClients.Count; i++)
{
if (connectedClients[i].socket == clientSocket)
{
connectedClients.RemoveAt(i);
break;
}
}
clientSocket.Close();
}
else
{
responseMessage = "Error";
}
byte[] responseStatus = StringToByte(responseMessage);
for (int i = 0; i < connectedClients.Count; i++)
{
if (connectedClients[i].socket==clientSocket)
{
connectedClients[i].socket.BeginSend(responseStatus, 0, responseStatus.Length,SocketFlags.None, new AsyncCallback(OnSend), connectedClients[i].socket);
break;
}
}
}
catch(Exception ex)
{
throw new Exception(ex.Message);
}
}
Your application crashes, because you throw an exception in the catch block of your method.
If you don't want your application to crash, you need to remove the throw new Exception(ex.Message); line from the catch block.
Replace it with code that handles the error and gracefully restores your application to a safe state. From reading your code, this should be done by removing the clientSocket from connectedClients
Secondly, it is better to just use throw; instead of throw new Exception(ex.Message);. throw; will re-throw the original exception object and thus preserve the stack trace and other vital information that helps in debugging your software.
Using new Exception("Message") will create a completely new exception object with the current stack trace.
private void OnReceive(IAsyncResult result)
{
try
{
Socket clientSocket = (Socket)result.AsyncState;
clientSocket.EndReceive(result);
command = responseMessage = string.Empty;
command = ByteToString(receviedData);
receviedData = new byte[30];
if (command=="Connect")
{
ClientInfo clientInfo = new ClientInfo() {
socket = clientSocket,
IP = clientSocket.RemoteEndPoint.ToString(),
};
connectedClients.Add(clientInfo);
responseMessage = "Connection established...";
}
else if (command=="Disconnect")
{
removeClientInfo(clientSocket);
clientSocket.Close();
}
else
{
responseMessage = "Error";
}
byte[] responseStatus = StringToByte(responseMessage);
for (int i = 0; i < connectedClients.Count; i++)
{
if (connectedClients[i].socket==clientSocket)
{
connectedClients[i].socket.BeginSend(responseStatus, 0, responseStatus.Length,SocketFlags.None, new AsyncCallback(OnSend), connectedClients[i].socket);
break;
}
}
}
catch(Exception ex)
{
// add error handling and gracefully recover
// caution: The way done here, might work, but it smells :-/
removeClientInfo((Socket)result.AsyncState);
((Socket)result.AsyncState).Close();
}
}
/// removes the client info from the connectedClients enumerable
private void removeClientInfo(Socket socket)
{
for (int i = 0; i < connectedClients.Count; i++)
{
if (connectedClients[i].socket == socket)
{
connectedClients.RemoveAt(i);
break;
}
}
}
You are throwing a new exception inside the catch block, which doesn't make much sense unless you're doing some logging or similar. Change the catch block like:
catch(SocketException)
{
}
Also, you should check the number of bytes read returned from EndReceive. If you receive zero bytes, that means the client has shutdown the connection:
int numReceived = clientSocket.EndReceive(result);
if(numReceived == 0)
{
//client has shutdown the connection
}