ASP.NET WEB PROGRAMMING
How to optimally handle
Open
Close
Dispose
Exception
when retrieving data from a database.
LOOKING TO OPTIMISE
I have always used the following to make a connection, catch any errors, and then correctly dispose of the connection in either event.
VB.NET
Try
con.Open()
//...
con.Close()
Catch ex As Exception
lbl.Text = ex.Message
Finally
If con IsNot Nothing Then
con.Dispose()
End If
End Try
After reading many articles I find people practically throwing up at this code; however, I do not see any other way to accomodate the four steps required efficiently.
The alternative, and I believe more cpu friendly USING statement, seems to be the tool of choice for the correct disposal of a sql connection. But what happens when bad data is retrieved from the database and there is nothing in place to indicate to an end user what went wrong?
QUESTION
Between: Using, try catch, and other.
Which is faster, cleaner, and/or most efficient way to handle a data retrieval statement?
I am happy to hear people's opinions but I am looking for facts.
You can also use the following block of code as template. It combines the Using...End Using and Try...Catch blocks.
Using conn As New SqlConnection(My.Settings.SQLConn)
Try
Conn.open
Catch ex As SqlException
End Try
End Using
There is no need to call conn.Dispose() because using block does that automatically.
Use Entity Framework, it implements Unit Of Work Pattern for You efficiently, and perform your operations within transaction scope
Always use the "Using" process as it will automatically assign and then free up system resources. You are still able to perform the try-catch within this to present errors to the user.
Related
i'm trying to loop over a datatable with more then 100 000 row using the Parrallel For each. Everything work fine up to around 25 000 iterations. I dont get any error, and I see the apps still working, but it kind of block and nothing happen. I tried to encapsulate the loop in a factory.startnew and I get a random abort expection at around 5000 iterations for no reason.
Dim lstExceptions As New ConcurrentQueue(Of Exception)
Dim options As New ParallelOptions
options.MaxDegreeOfParallelism = 3
Parallel.ForEach(ReservationReportDS.Tables(0).AsEnumerable(), options,
Sub(row)
Try
Dim tmpRow As DataRow = CType(row, DataRow)
Dim ReservationID As Integer = tmpRow.Field(Of Integer?)("autNoReservation")
Dim customerID As Integer = tmpRow.Field(Of Integer?)("CustomerID")
Dim VehiculeID As Integer = tmpRow.Field(Of Integer?)("autNoVehicule")
Dim bill As New BillingPath()
bill.Calculate_Billing(ReservationID, customerID, VehiculeID)
Catch err As Exception
lstExceptions.Enqueue(err)
End Try
End Sub
)
If (lstExceptions.Count > 0) Then
Throw New AggregateException(lstExceptions)
End If
Catch errAgg As AggregateException
For Each ex As Exception In errAgg.InnerExceptions
Log(Log_Billing_UI, "", System.Reflection.MethodBase.GetCurrentMethod().Name & GetExceptionInfo(ex))
Next
Catch ex As Exception
Log(Log_Billing_UI, "", System.Reflection.MethodBase.GetCurrentMethod().Name & GetExceptionInfo(ex))
End Try
Since you have such amount of records, I would like to recommend you to think about following concept:
Read all records into ConcurrentQueue(Of SomeBillingInfoClass) collection first - it will allow you to not keep connection to DB opened, make thread-safe rest operations with data readed from DB.
Create list of Tasks with Billing calc code inside. This will allow you to run tasks in parallel and pass ConcurrentQueue variable from #1 easily.
Keep tasks running in loop while at least one element in ConcurrentQueue remains.
In case you can aggregate billing calculation result to some other class - you may do it using additional thread safe ConcurrentQueue(Of BillingCalcResultInfoClass) collection.
After all billings are calculated - write to DB in single thread and single long transaction - this may be faster then granular writing to db.
Some notes about your code - I think you may not need to throw AggregateException manually - .Net environment will do it for you automatically. You only will need to catch it in .ContinueWith() method of task (sorry, mostly I'm c# developer and use c# notation).
I used similar approach to process millions of records and it works fine. Typically I use 3-5 tasks. But you can always study how much tasks you may have.
Using ConcurrentQueue or similar thread safe collection will allow you to keep your code thread safe more easily.
Please let me know if you have any questions.
Thank you all for your answers and especially Anton Norko. I finally found the problem and it was on my side. Under certain condition, Calculate_Billing was stuck in an infinite loop. Since I used 3 threads at the same time, they were getting stuck one by one.
I am creating a program in which a user can search and add their desired order. The problem that I'm facing now is that when I throw the exception, the program does not read the exception so that the user will know if the id that is entered is on the database or not. I will provide the code snippet of the program that I'm working on.
Problems
Your code will not throw an error if the item_code does not exist in your database. It will simply not enter the while loop.
This is not the proper use of an exception. It is not an error if the record is not found. The proper way of checking if the item_code exists is a check if the datareader has results.
You must properly defend yourself again SQL injection. By concatenating the sql query you are opening yourself up to a whole host of problems. For example, if a user maliciously enters the following text, it will delete the entire Products table: ';DROP TABLE Products;-
You are not disposing of the OleDbConnection or the OleDbCommand objects correctly. If an exception occurs, your code will not run the Dispose() method. This can cause you to quickly run out of resources.
Solutions
You should check if the dataRead has any rows. If it does not, then you can alert the user via javascript. Like so:
If dataRead.HasRows Then
//READ DATA
Else
//ALERT USER
End If
Solution #1 address Problem #2 as well
Use a parameterized query. The .NET framework will prevent these kinds of attacks (SQL Injection).
selectProductQuery = "SELECT * FROM Products WHERE item_code = #item_code"
...
newCmd.Parameters.AddWithValue("item_code", txtItemCode.Text);
Wrap all objects that implement Dispose() in a using block. This will guarantee everything is properly disposed of, whether an error is thrown or not.
Using newCon As New OleDbConnection(....)
Using newCmd As New OleDb.OleDbCommand(...)
...
End Using
End Using
To be perfectly honest, there is quite a bit "wrong" with your code, but this should get you headed in the right direction.
The line:
Response.Write(<script>alert('The ...')</script>)
Needs to be (note the quotes):
Response.Write("<script type='text/javascript'>alert('The ...')</script>")
Same for the other one at the top, but I dont think that will fix your overall problem.
Instead, use javascript like this:
if(!alert('Whoops!')){window.location.reload();}
to pop up an alert box and then reload the page after they click on the button.
I am looking through someone elses code and there is plenty of code like this:
try
'Logic here
catch e as exception
throw
end try
I believe that the TRY and CATCH cause are pointless (they were probably used for debugging). Is there ever a scenario were coding like this is good practice?
There is a global even handler (global.asa).
I agree that these clauses are pointless and worse, add clutter to your code that adds nothing other than confusion.
Worse still: if they ever do Throw e instead of just Throw the stack on the original exception is lost.
No. There is no reason to have a try..catch that only throws. If you want to debug and catch exceptions at the moment they occur, you should halt on framework exceptions within Visual Studio (Debug menu -> Exceptions...).
I have the exact same thing in one of the programs I inherited and it's actually worse because catching is expensive in C# (only trying is free). I made it a point to remove a dozen of these every day, I should be done in a few more weeks.
Generally, you don't want to do this (and you don't want to catch System.Exception either).
That being said, there might be some cases where you want to Throw the exception further up the call stack, and Catch it elsewhere. Here is a trivial example:
Try
' Do some stuff here. For this example, let's assume
' it cannot cause any exceptions
Try
' Do some other stuff here that CAN cause an exception
Catch innerEx as Exception
' Rethrowing so that the outer block handles this
Throw
End Try
Catch ex as Exception
MessageBox.Show("I just caught an exception.")
End Try
IF you do something like this, common sense dictates that you should place a comment that states WHY you are doing this.
As I said, that is an overly trivial example, but a more common usage might be that you have a method that calls another method, and you want the first method to handle any exceptions that the 2nd method might throw. The behavior will be the same if you leave the Try/Catch block out of the 2nd method instead of rethrowing, but the Try/Catch and the comment make your intent a little more obvious.
EDIT: If you know which line of code is likely to throw the exception, then putting a comment above that line is probably preferable to adding the Try/Catch blocks.
Hello I am getting an error on the following line:
If Not System.Windows.Clipboard.GetDataObject Is Nothing Then
I believe it would look something like this in C#
if (System.Windows.Clipboard.GetDataObject!=null) {
The Error is:
"ThreadStateException: Current thread must be set to single thread apartment (STA) mode before OLE calls can be made."
Can anyone tell me how to fix this? A few suggestions online mentioned adding <STAThread()> _ over the 'main' method, however, this is an ASP.NET controller method, I tried adding this over it and it didn't help. Anyone have any suggestions?
ASP.NET doesn't really get along with STAThread.
You need an additional task scheduler to run a thread in STA mode to access what you want from the operating system
Take a look at this article it got me going with something like this.
Also, keep in mind that multiple request to your page might mess up things, since you're interacting with the clipboard of the operating system (which runs in another COM context) son concurrency might by risky.
What are you trying to acomplish, maybe there is a better way.
Don't forget to read the final notes.
http://www.telerik.com/community/forums/community-forums/interesting-resources/using-clipboard-class-in-asp-net.aspx
It seems that this can be caused by an out of date dll in your /bin directory. Have you tried clearing it?
http://social.msdn.microsoft.com/Forums/en-US/winforms/thread/2411f889-8e30-4a6d-9e28-8a46e66c0fdb/
http://www.devnewsgroups.net/windowsforms/t36723-current-thread-must-set-single-thread-apartment-sta.aspx
Also, you can explicitly start up a new thread in Single Apartment Mode
imports System.Threading
dim newThread As New Thread(new ThreadStart(AddressOf ThreadMethod))
newThread.SetApartmentState(ApartmentState.STA);
newThread.Start();
'and elsewhere
Public Sub ThreadMethod()
If Not System.Windows.Clipboard.GetDataObject Is Nothing Then
'stuff
End if
End Sub
I have an object, say Order where if an error occurs, it raises the ErrorOccurred event. If I'm running some code in say, the codebehind for a .aspx page with an public Order registered as WithEvents and I want to check to see if an error has occurred before I run more code, how do I do this? I can't simply check theOrder.ErrorOccurred. Do I have to create a local boolean flag that switches over in the event handler (OnErrorOccurred)? Or is there a better way to do this?
Thanks!
Example:
Public WithEvents theOrder As New Order
Public Sub DoStuff()
theOrder.DoSomething()
If theOrder.ErrorOccurred Then
do stuff
End If
End Sub
That seems like a reasonable approach. If there is lots of logic going on with an Order object that depends on knowing about errors, having a Status field would allow easy communication to any consumer what the status of the order was, rather than everyone having to subscribe to the event and track it themselves.
Alternately you could track it internally in the Order and just throw exceptions when critical methods were accessed if the Order was in an error state. This has the disadvantage of making you do more error handling, but would have the advantage of making sure that any Order consumer handled them explicitly.
Why not use structured error handling?
Try
'Code that may raise an error.
Catch
'Code to handle the error.
Finally
'Code to do any final clean up.
End Try
http://support.microsoft.com/kb/315965
This is what it is intended for.
Problems may arize if someone calls DoSomething but thay are unaware that they need to check theOrder.ErrorOccurred. based on what DoSomething is doing, allowing one to call a method and letting it fail quietly can be a problem.
If do something is doing logging sure, let it fail. If it is finalizing an order process..
Brian
Use the Try Catch Block
Try
'try your code here
Catch somevariablenamehere As Exception
'use methods from Exception class to get to know the error better and how to deal with it
Finally
'this is optional, If you want to do something finally, like cleaning up etc. You can do here
End Try
'to end the Try block