ADO.NET asynchronous methods not throwing exceptions - c#

I have a Web API 2 endpoint set up to test a 2+ second ADO.NET call. When attempting to "burst" this api, it fails horribly when using async methods. I'm getting connection timeouts and reader timeouts. This doesn't happen with the synchronous version of this method when "bursted". The real problem is as follows...
Async ADO.NET behaves strangely when exceptions are thrown. I can see the exceptions thrown in the Visual Studio output, but they are not caught by my code. As you'll see below, I've tried wrapping try/catches around just about everything and have had no results. I did this to be able to set break points. I understand that catching exceptions just to throw them is bad. Initially, I only wrapped the call in the API layer. The worst part is, this locks up the entire server.
Clearly, there's something I'm missing about async ADO.NET. Any ideas?
EDIT:
Just to clarify what I'm trying to do here. This is just some test code on my local computer that's talking to our developmental database. It was just to prove/disprove that we can handle more traffic with async methods against our longer running db calls. I think what's happening is that as the calls are stacking up. In doing so, the await'ed connections and readers are timing out because we're not getting back to them quickly enough. This is why it doesn't fail when it's ran synchronously. This is a completely different issue. My concern here is that the operations are not throwing exceptions in a way that can be caught. The below is not production code :)
Web API2 Controller:
[Route("api/async/books")]
[HttpGet]
public async Task<IHttpActionResult> GetBookAsync()
{
// database class instantiation removed
// search args instantiation removed
try
{
var books = await titleData.GetTitlesAsync(searchArgs);
return Ok(books);
}
catch (Exception ex)
{
return InternalServerError(ex);
}
}
Data Access:
public async Task<IEnumerable<Book>> GetTitlesAsync(SearchArgs args)
{
var procName = "myProc"
using(var connection = new SqlConnection(_myConnectionString))
using (var command = new SqlCommand(procName, connection) { CommandType = System.Data.CommandType.StoredProcedure, CommandTimeout = 90 })
{
// populating command parameters removed
var results = new List<Book>();
try
{
await connection.OpenAsync();
}
catch(Exception ex)
{
throw;
}
try
{
using (var reader = await command.ExecuteReaderAsync())
{
try
{
while (await reader.ReadAsync())
{
// FROM MSDN:
// http://blogs.msdn.com/b/adonet/archive/2012/07/15/using-sqldatareader-s-new-async-methods-in-net-4-5-beta-part-2-examples.aspx
// Since this is non-sequential mode,
// all columns should already be read in by ReadAsync
// Therefore we can access individual columns synchronously
var book = new Book
{
Id = (int)reader["ID"],
Title = reader.ValueOrDefault<string>("Title"),
Author = reader.ValueOrDefault<string>("Author"),
IsActive = (bool)reader["Item_Active"],
ImageUrl = GetBookImageUrl(reader.ValueOrDefault<string>("BookImage")),
ProductId = (int)reader["ProductID"],
IsExpired = (bool)reader["Expired_Item"]
};
results.Add(book);
}
}
catch(Exception ex)
{
throw;
}
}
}
catch(Exception ex)
{
throw;
}
return results;
}
}

Related

How to handle exceptions from API calls in Unity and pass them down to the UI?

I'm trying to figure out what to do with some errors in Unity when I call an API and how to propogate it up to the user interface - where and how to handle things. I've built aspnet APIs but there I'd normally use some error handling middleware to keep my controllers clean.
Let say we have some code like this (I'm using controller / repository language cos that's what I know).
A UI button fires an event like OnLoginButtonPressed.
An AuthController class reacts to the event by calling it's login method and then doing some logic when the response comes through, as follows:
public async void Login(LoginModel input)
{
var result = await AuthRepo.instance.Login(input);
app.token = result;
EventService.OnSuccessfulLogin();
}
The Auth.Repo calls the API and tries to return a Token class (just a wrapper around a JWT string)
public async Task<Token> Login(LoginModel input)
{
string json = JsonConvert.SerializeObject(input);
var request = UnityWebRequest.Post(app.baseURL + "authentication/login", json);
request.SetRequestHeader("Content-Type", "application/json");
request.SendWebRequest();
while (!request.isDone)
{
await Task.Yield();
}
if (request.result == UnityWebRequest.Result.Success)
{
Token token = JsonConvert.DeserializeObject<Token>(request.downloadHandler.text);
return token;
}
else
{
throw
}
}
So that's without exception handling. So I want to try to let the user know if there is a connection error, or they have put invalid details etc... I'm guessing I'm supposed add some logic into the AuthRepo such as:
if (request.result == UnityWebRequest.Result.Success)
{
Token token = JsonConvert.DeserializeObject<Token>(request.downloadHandler.text);
return token;
}
else if (request.result== UnityWebRequest.Result.ConnectionError)
{
throw new ConnectionException(request.error);
}
else if (request.result == UnityWebRequest.Result.DataProcessingError)
{
throw new BadRequestException(request.error);
}
else
{
throw new System.Exception(request.error);
}
This seems like a lot of code, and would end up in every method in every repo (unless I pull it out into some helper method?).... anyway, and then in the controller I would do something like:
try {
var result = await AuthRepo.instance.Login(input);
app.token = result;
EventService.OnSuccessfulLogin();
}
catch (ConnectionException ex)
{
EventService.OnConnectionError(ex.Message);
//some UI object would listen for this event and show the connection error message.
}
catch (BadRequestException ex)
{
EventService.LoginFailedError(ex.Message);
}
finally
{
EventService.UnknownError(ex.Message);
}
Is this completely down the wrong path? Seems like the code is just gonna get swamped with exception handling, or is this the correct way?
I've worked through a few YouTube videos that seem to suggest this is right, but they don't really show my use case (talking to APIs) so I'm just trying to be sure.
because UnityWebRequest.Result is an enum, you can start by using a switch statement here. Not only is this cleaner, it performs better too.
Another thing you can do is create an abstract class (e.g. APIException) and make that responsible for creating the correct exception instances, by giving it some static method like APIException FromUWRResult(UnityWebRequest.Result result).
Handling the exceptions can be done in APIException too. Give it an abstract method Handle() and implement accordingly in each of the deriving classes.
Now your code would look like this:
var ex = APIException.FromUWRResult(request.result);
if(ex != null) {
throw ex;
}
...
catch(APIException ex) {
ex.Handle();
}

Web service calling another webservice

So I have a database that fills up when a value is not found inside of it already, basically is a web API written in C# that checks if there is a value inside of it, if its null then calls another web service that will retrieve the data and insert a new record into the database and return the newly created record to the user. The code is like this:
[HttpGet ("{idDocument}")]
public async Task<IActionResult> GetPerson (string idDocument)
{
// Get the person record from the database
var person = await repository.GetPersonAsync (idDocument);
// if the record does not exist, return not found
if (person == null)
{
Person newPerson = await GetNewPersonFromRemoteServer(idDocument);
var result = mapper.Map<Person, PersonResource>(newPerson);
return Ok(result);
}
// Map the record to a resource to return to user
var resource = mapper.Map<Person, PersonResource> (person);
// return record resource to user
return Ok (resource);
}
private async Task<Person> GetNewPersonFromRemoteServer(string id)
{
Person newPerson = new Person();
string address = "http://remoteservice.serv/?id=";
string fullAddress = address + id;
try
{
using (HttpClient client = new HttpClient())
{
HttpResponseMessage response = await client.GetAsync(new Uri(fullAddress));
string responseMessage = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
Person newPerson = JsonConvert.Deserialize<Person>(responseMessage);
repository.AddPersonAsync(newPerson);
await uow.CompleteAsync();
return newPerson;
}
return newPerson;
}
}
catch (Exception ex)
{
return newPerson;
}
}
But the service is working sometimes and sometimes its returning null even tho if I execute the remote service I get a response with the correct data. I believe it has something to do with the nested async/await methods/functions but I cant seem to figure it out a better solution to my problem. Any help would be greatly appreciated!
You have extremely faulty exception handling. Right now you swallow Exceptions. Moreover, you do it with Fatal Exceptions. That is a deadly sin of exception handling and can easily explain any odd behavior.
After a fatal exception your programm should always close. Ignoring them only leads to more followup errors that are impossible to debug or even predict.
You should read up on proper exception handling. Here are two articles I linked often:
http://blogs.msdn.com/b/ericlippert/archive/2008/09/10/vexing-exceptions.aspx
http://www.codeproject.com/Articles/9538/Exception-Handling-Best-Practices-in-NET

How to handle database exceptions in .NET?

I'm using Oracle through their official managed drivers for .NET (a Nuget package).
My application uses the same connection to the DB from the beginning and it's used from several locations to perform queries.
In some cases, there may be connection "hiccups" that cause exceptions. The problem is that I don't know what's the best strategy to retry to perform a query when this happens.
Is there a common way to solve this situation?
Thank you.
I agree with the comment from Habib.
The oracle .NET Package uses connection pooling. Even if you open up multiple connections, it will manage them accordingly so that you don't have to keep it open.
That means that your code can be simplified, into something like this pseudo-code:
using(OracleConnection conn = MakeConnection())
{
//do stuff with connection
//not necessary, but I always manually close connection. Doesn't hurt.
conn.Close();
}
If you're uncertain of connection issues even in that small of an execution, you can wrap it in a try-catch block like so:
try
{
using(OracleConnection conn = MakeConnection())
{
//do stuff with connection
//not necessary, but I always manually close connection. Doesn't hurt.
conn.Close();
}
}
catch(OracleException ex)
{
//handle exception.
}
OracleException looks to be the main exception with the .NET oracle package. Please note that there may be others you want to catch more specifically.
It would be easier to instantiate the connection on the fly when the query is being made. I don't think a simple try/catch would help you here because even if you reinitialized the connection in the catch block, you would have to somehow re-execute your query.
I don't recommend this but you could use a Retry class that reinitializes the connection if an exception is caught....
public class Retry
{
public static void Do(Action action, TimeSpan retryInterval, int retryCount = 3)
{
Do<object>(() =>
{
action();
return null;
},
retryInterval, retryCount);
}
public static T Do<T>(Func<T> action, TimeSpan retryInterval, int retryCount = 3)
{
var exceptions = new List<Exception>();
for (int retry = 0; retry < retryCount; retry++)
{
try
{
if (retry > 0)
Thread.Sleep(retryInterval);
return action();
}
catch (ConnectionException ex)
{
// ***Handle the reconnection in here***
exceptions.Add(ex);
}
}
throw new AggregateException(exceptions);
}
}
Then you can call your query like
Retry.Do(() => MyQueryMethod, TimeSpan.FromSeconds(5));
I got the basis for this Retry code from SO a long time ago, don't recall the thread but it isn't my original code. I have used it quite a bit for some things though.

Dispose not working, many dead connections

I'm getting strange things since updated to EF6,no sure this is related or not, but used to be good
I'm doing a set of work, then save it to DB , then do another , save another.
after a while,i check SQL server by sp_who2 , i found many dead connections from my computer.
Job is huge then there goes to 700 connections,
I have to kill them all manually in cycle.
program like:
while (jobDone == false)
{
var returnData=doOneSetJob();
myEntity dbconn= new myEntity;
foreach( var one in retrunData)
{
dbconn.targetTable.add(one );
try
{
dbconn.savechange();
/// even i put a dispose() here , still lots of dead connections
}
catch
{
console.writeline("DB Insertion Fail.");
dbconn.dispose();
dbconn= new myEntity();
}
}
dbconn.dispose()
}
You should consider refactoring your code so that your connection is cleaned up after your job is complete. For example:
using (var context = new DbContext())
{
while (!jobDone)
{
// Execute job and get data
var returnData = doOneSetJob();
// Process job results
foreach (var one in returnData)
{
try
{
context.TargetTable.Add(one);
context.SaveChanges();
}
catch (Exception ex)
{
// Log the error
}
}
}
}
The using statement will guarantee that your context is cleaned up properly, even if an error occurs while you are looping through the results.
In this case you should use a using statement. Taken from MSDN:
The using statement ensures that Dispose is called even if an exception occurs while you are calling methods on the object. You can achieve the same result by putting the object inside a try block and then calling Dispose in a finally block; in fact, this is how the using statement is translated by the compiler.
So, your code would look better like this:
using(var dbconn = new DbContext())
{
while (!jobDone)
{
foreach(var one in retrunData)
{
try
{
targetTable row = new TargetTable();
dbconn.TargetTable.add(row);
dbconn.SaveChanges();
}
catch (Exception ex)
{
Console.WriteLine("DB Insertion Fail.");
}
}
}
}
This way, even if your code fails at some point, the Context, resources and connections will be properly disposed.

rewriting recursive form to iterative. exception handling

Consider such a function:
void RequestThings(List<Things> container, Connection connection, Int32 lastVersion) {
var version = lastVersion;
try {
foreach(var thing in connection.RequestThings(version)) {
container.Add(thing);
version = thing.lastVersion;
}
}
catch(Exception ex) {
RequestThings(container, connection, version + 1);
}
}
But this choice is far not perfect: it involves adding to a recursion depth (up to a stack overflow) in case if there are (many) exceptions.
How do I rewrite this the iterative way?
I've tried to do this like:
var container = new List<Things>();
var version = getLastVersionFromDB();
foreach(var thing in connection.RequestThings(version)) {
try {
container.Add(thing);
}
catch(Exception ex) {
continue;
}
}
But it appears that exception doesn't get handled. How do I do this?
edit. the details
Connection.RequestThings(Int32 startVersion) requests data from a remote server. Accepts a seed version as its only parameter. There might be blocked/damaged documents which you cannot request though they appear on the results returned by calls to Connection.RequestThings(Int32 startVersion). This piece throws the exception
Don't know why but the inner try/catch in my iterative example doesn't catch the exception.
Generally, it's a bad idea to have a catch clause for all exceptions. Consider catching only a specific exception type to be sure that you're not swallowing unexpected errors.
Additionally, if you got a stack overflow in the first place, it indicates that you might be doing something wrong. For example, what happens if you pass an invalid version number to this method, and there are no documents with a larger version number available? This method will keep running forever, with no chance to gracefully cancel it. Especially since it seems that you are getting the "last version" from a database somehow; if this fails, you can be pretty certain that no higher version exists.
Having said that, you can simplify the method by creating an "infinite" loop and then using return to exit the method on success:
void RequestThings(List<Things> container, Connection conn, int version)
{
while (true)
{
try
{
foreach (var thing in connection.RequestThings(version))
{
container.Add(thing);
version = thing.lastVersion;
}
return;
}
catch (Exception ex)
{
Log.Error(ex);
version++;
}
}
}
A slightly better approach might be to make sure that you really get the entire list on success, or nothing. The way your code is written right now leaves the possibility of container being filled multiple times if an exception happens while iterating.
List<Things> RequestThings(Connection conn, int version)
{
while (true)
{
try
{
// this will either create an entire list,
// or fail completely
return connection.RequestThings(version).ToList();
}
catch (Exception ex)
{
Log.Error(ex);
version++;
}
}
}

Categories