.NET Framework Data Provider for Oracle multiple open connection - asp.net

I have the below mentioned code in a seperate class file for establishing connection and carry out DB transactions. I have an issue where multiple connections being opened which sometime exceed the connection pool. When I stepped through the code I found that there are codes which call ConnectDB() in a loop without calling DisconnectDB(). But I expected that the condition OraConn.State = ConnectionState.Closed should handle the situation. Somehow the condition is always satisfied hence openning another set of connection. Can you suggest where am I going wrong and also what best practice can be adopted here?
Public Class Connection
Dim Str_conn As String = "Data Source=...; User=...; password=...; Min Pool Size=10; Max Pool Size=500;"
Public OraConn As OracleConnection
Dim cmd As OracleCommand
Dim dr As OracleDataReader
Dim data_adapt As OracleDataAdapter
Dim dt As DataTable
Dim ds As DataSet
Public Sub ConnectDB()
OraConn = New OracleConnection(Str_conn)
If OraConn.State = ConnectionState.Closed Then
OraConn.Open()
End If
End Sub
Public Sub DisconnectDB()
If OraConn.State = ConnectionState.Open Then
OraConn.Close()
End If
End Sub
Public Function get_dataset(ByVal query As String, ByRef ds As DataSet) As DataSet
data_adapt = New OracleDataAdapter(query, OraConn)
data_adapt.Fill(ds)
Return ds
End Function
Public Function get_datareader(ByVal query As String) As OracleDataReader
cmd = New OracleCommand(query, OraConn)
dr = cmd.ExecuteReader()
Return dr
End Function
Public Sub UpdateDB(ByVal query As String)
cmd = New OracleCommand(query, OraConn)
cmd.ExecuteNonQuery()
cmd.Dispose()
End Sub
The class is refered in other classes or directly in the aspx.vb pages like this.
Public Function InsertData(ByVal var1 As String, ByVal var2 As String) As Integer
conn.ConnectDB()
Dim qryInsert As String
qryInsert = " INSERT INTO TABLE VALUES ('" & var1 & "', "
qryInsert = qryInsert & var2 & "')"
Try
conn.UpdateDB(qryInsert)
Catch ex As OracleException
If ex.Code = 1 Then
updData(var1, var2)
ElseIf ex.Code = 2091 Then
msgprompt("Duplicate Unique Key!", "Warning")
End If
Finally
conn.DisconnectDB()
End Try
Return count
End Function
The connection is again opened in function updData(). While I understand that it has to be closed correctly but keeping tab on every developer is not possible. Hence I want to control it directly from the connection class by using the same connection but the condition If OraConn.State = ConnectionState.Closed is not helping.
UPDATE
I have put the code in UpdateDB under a Using block and removed call to ConnectDB and DisconnectDB from function like InsertData(...). It seems that the issue has been resolved. But I would like to know in case of exception will the connection remain open? and also OraConn is a public variable defined outside Using block so will it be disposed of by the GC?
Public Sub UpdateDB(ByVal query As String)
Using OraConn = New OracleConnection(Str_conn)
cmd = New OracleCommand(query, OraConn)
Try
OraConn.Open()
cmd.ExecuteNonQuery()
Catch ex As Exception
Throw
Finally
cmd.Dispose()
End Try
End Using
End Sub

You must close all the connections as soon as you are done with it, no matter what.
Suggestion:
The best practice for closing the connection is to do it in finally block. So that even if there is any error, catch it (log it if required) in catch block, and then connection will get close in finally block.
UPDATE
You can put one private static counter in your Connection class. When ever ConnectDB() is called you increment this counter and decrement it in every DisconnectDB(). Now in ConnectDB() you check the value of counter, if it exceeds a minimum threshold you throw error, by doing this way; you can come to know idle connection present in your code and refactor it. On production keep this threshold value high or ignore it in code.

Related

How I do a WCF service with two methods: one that waits and insert data into the DB and another to poll the DB?

This is the scenario:
I'm doing a web service in WCF and a client application in ASP.NET. The language is VB.NET.
I want a method than send "jobs" to the server. I'm trying to simulate this kind of jobs as long running processes that wait up to 20-30 seconds with thread sleeping and inserting a row into a JOBS table in the DB.
I want another method that polls the database every 5 seconds with client postbacks to get the jobs lists from the JOBS table (finished and currently running)
This is what i've got so far, both methods are working, except when a long running job is sleeping, then the client can't retrieve the list of jobs with another call. I've tried "PerCall" in the but it didn't work out. I suspect the thread is somewhat locking the service or maybe I have to use async calls. I'm using HttpBasicBinding at web.config ... I'm a little lost and I have not found any code doing something similar.
Here is the code in the service side:
iServiceJobs.vb
<ServiceContract()>
Public Interface IServiceJobs
<OperationContract(IsOneWay:=True)>
Sub SendJob(ByVal runTime As Integer, ByVal id As String)
<OperationContract>
Function GetJobsList() As List(Of ClassJob)
ServiceJobs.vb
Public Class ServiceJobs Implements IServiceJobs
Public SendJob(ByVal runTime As Integer, ByVal id As String) Implements IServiceJobs.SendJob
Dim connStr As String = "..."
Dim conn As New OracleConnection(connStr)
conn.Open()
Dim query As String = "INSERT INTO JOBS(...)"
Dim cmd As New OracleCommand(query, conn)
cmd.ExecuteNonQuery()
Threading.Thread.Sleep(runTime* 1000)
cmd = New OracleCommand(query, conn)
cmd.ExecuteNonQuery()
End Sub
Public Function GetJobList() As List(Of ClassJob) Implements IServiceJobs.GetJobsList
Try
Dim jobList As New List(Of ClassJobs)
Dim connStr As String = "..."
Dim conn As New OracleConnection(connStr)
conn.Open()
Dim query As String = "SELECT * FROM JOBS"
Dim cmd As New OracleCommand(query, conn)
Dim dr As OracleDataReader
Dim job As ClassJob
dr = cmd.ExecuteReader
While dr.Read
job = New ClassJob
job.id = dr(0)
job.lock = dr(3)
...
jobList.Add(job)
job = Nothing
End While
Return jobList
Catch ex As Exception
Return Nothing
End Try
End Function
End Class
The code in the client is very simple, just two buttons, one with a ws call for insert jobs and another to get the job list.
I'm open to any suggestion on how to do a better implementation of this scenario.
EDIT:
I've tried
<ServiceBehavior(ConcurrencyMode:=ConcurrencyMode.Multiple, InstanceContextMode:=InstanceContextMode.PerCall)>
But it doesn't work, GetJobList() returns Nothing while SendJob() is working on this thread.
SOLVED: Apparently, I was using an outdated version of Oracle libraries. When I used Oracle.ManagedDataAccess from NuGet everything went OK.
SOLVED: Apparently, I was using an outdated version of Oracle libraries. When I used Oracle.ManagedDataAccess from NuGet everything went OK.

How to select GUID column by another GUID column in VB.net?My Select query does not work

I am new to programming and get the chance to work and maintain in another developers project.
The project is built with ASP.Net Vb.Net and SQl Server.
I am trying to select the primary key ID (which is actually a GUID) from a table.
SQID = Core.DB.GetString("SELECT id FROM SQC WHERE sid = " & sid)
In the Table SQC the primary key is id which is guid and the sid is also guid which is primary key to another table.
my previous developer developed the code to select string variable GetString function where GetString is
Shared Function GetString(ByVal selectQueryText As String, ByVal ParamArray params As SqlParameter()) As String
Dim dt As DataTable = Nothing
Try
dt = GetData(selectQueryText, CommandType.Text, params)
If dt.Rows.Count = 0 Then
Return ""
Else
If TypeOf dt.Rows(0)(0) Is DBNull Then
Return ""
Else
Return CStr(dt.Rows(0)(0))
End If
End If
Finally
If dt IsNot Nothing Then dt.Dispose()
End Try
End Function
When I debug the code my process enters into GetString Function and from Get String it goes to GetData function
Shared Function GetData(ByVal selectCommandText As String, ByVal selectCommandType As CommandType, ByVal ParamArray params As SqlParameter()) As DataTable
Dim conn As SqlConnection = Nothing
Try
conn = GetOpenSqlConnection()
Return GetData(conn, selectCommandText, selectCommandType, params)
Finally
If conn IsNot Nothing Then conn.Dispose()
End Try
End Function
Shared Function GetData(ByVal conn As SqlConnection, ByVal selectCommandText As String, ByVal selectCommandType As CommandType, ByVal ParamArray params As SqlParameter()) As DataTable
If conn Is Nothing Then Return GetData(selectCommandText, selectCommandType, params)
Dim sa As SqlDataAdapter = Nothing
Try
sa = New SqlDataAdapter(selectCommandText, conn)
sa.SelectCommand.CommandType = selectCommandType
Dim dt As New DataTable
Try
For Each param As SqlParameter In params
sa.SelectCommand.Parameters.Add(param)
Next
sa.Fill(dt)
Return dt
Catch ex As Exception
dt.Dispose()
Throw ex
End Try
Finally
If sa IsNot Nothing Then sa.Dispose()
End Try
End Function
In the Try Catch area of exeption handling the code breaks and throws the exception error. It saying Incorrect syntax near 'a379'. which is first the part of sid (GUID). I mean the sid value is 9417A379-6371-432F-9DA5-BCFC46DD95A1
I am not sure how to handle this. I want to select the id from from SQC table and store it in a variable.
I am looking for your advice and suggestion. As I am new in the programming world please also point me my mistakes.
Thanks
It looks like your issue could be fixed like so:
SQID = Core.DB.GetString("SELECT id FROM SQC WHERE sid = '" & sid & "'")
But you should be aware that this style of code is open to SQL injection and you may want to look at ways of parameterising your queries (i.e. don't take what's in this project as good practice).

Multithreading and connection pool

I have problems with asp.net web service that randomly getting errors like "sql transaction completed no longer usable", "transaction is already commited..."
After read lot of posts I think its problem of shared connection problem bet I was unable to find where the problem is.
Starting from 0 I want to create a "class for 2 porpuoses
- Ensure Connections are closed
- Coding less
The simply class have 2 methods GDT (Give DataTable) and Ejecutar (execute in spanish)
¿Can anybody tell me if this class is well designed for non having problems of sharing connections?
Public Class clsAccesoBD2
Public Function GDT(ByVal strSql As String) As DataTable
Try
Using Cnn As New SqlConnection(ConfigurationManager.ConnectionStrings("CadenaPEA").ConnectionString)
Using da As New SqlDataAdapter(strSql, Cnn)
Using dt As New DataTable
da.Fill(dt)
Return dt
End Using
End Using
End Using
Catch ex As Exception
'Log code here
Throw
End Try
End Function
Public Function Ejecutar(ByVal strSql As String) As Integer
Try
Using Cnn As New SqlConnection(ConfigurationManager.ConnectionStrings("CadenaPEA").ConnectionString)
Using Cb As New SqlCommand(strSql, Cnn)
Dim RegistrosAfectados As Integer
Cnn.Open()
RegistrosAfectados = Cb.ExecuteNonQuery()
Cnn.Close()
Return RegistrosAfectados
End Using
End Using
Catch ex As Exception
'Log code here
Throw
End Try
End Function
End Class
este
close db connection (i.e. Cnn.Close()) in finally block of try-catch-finally construct

InvalidOperationException: Timeout - recursive DB access

currently I have a serious problem with one of my web applications which runs into a Timeout Exception around half a dozen times a day.
Error: "The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached".
After a lot of googling I found out that the problem has something to do with unclosed connections. So I checked all functions that access the database in any way until I stumbled upon this one:
Private Sub getOrgas(ByVal orgID As String)
Dim Id = orgID
orgColl.Add(Id)
While (Not IsNothing(Id))
Dim conn = Database.DbWrapper.GetConnection(1, Integration.Mandanten.DatabaseType.AddonSQL)
Dim paras As New HashSet(Of System.Data.Common.DbParameter)
Dim orgatmp As String
paras.Add(New SqlClient.SqlParameter("#Id", orgID))
Dim dr = Database.DbWrapper.GetDataReaderFromStoredProcedure("stp_Orgas_Get", paras, conn)
While dr.Read
If Not valueInColl(CStr(dr(0))) Then
orgatmp = dr(0).ToString
orgColl.Add(orgatmp)
getOrgas(orgatmp)
End If
End While
dr.Close()
conn.Close()
Id = Nothing
End While
End Sub
As you can see this function executes a stored procedure and runs the results through a while loop where it calls the function again if a specific condition -valueInColl-. Now in that way it is possible that there are 20 or more open connections. It has nothing to do with the timeout-value which is set via the GetDataReaderFromStoredProcedure to 600 which actually should be enough. To be sure I doubled the value and will roll it out this evening. I'll see whether that helped within the next day then.
I believe the problem is that there are too many open connections at the same time, because of the recursive function, but I have no clue how to solve this.
I couldn't find anything as to how to edit the max connections. I'm not even entirely sure where have to set it. Is it the IIS, the DB itself or is it a programming-parameter (VB.net/ASP.NET).
Would be nice if you guys could help me out here.
[EDIT]
Ok, somebody had the idea to reuse the connection variable, but this won't work as the datareader is still running. As long as it is not closed I can't reuse the connection in any way and I can't close the datareader, because I might lose data if I do so. The while-loop for dr.read hasn't ended, yet ..
On the other hand I deleted the (pretty much useless) outer while and used an If-clause in exchange:
Private Sub getOrgas(ByVal orgID As String, ByVal con As DbConnection)
Dim Id = orgID
Dim conn As DbConnection
Dim tmpOrga As String
orgColl.Add(Id)
If Not IsNothing(Id) Then
If IsNothing(con) Then
conn = Database.DbWrapper.GetConnection(1, Integration.Mandanten.DatabaseType.AddonSQL)
Else
conn = con
End If
Dim paras As New HashSet(Of System.Data.Common.DbParameter)
paras.Add(New SqlClient.SqlParameter("#Id", orgID))
Dim dr = Database.DbWrapper.GetDataReaderFromStoredProcedure("stp_Orgas_Get", paras, conn)
While dr.Read
If Not valueInColl(CStr(dr(0))) Then
tmpOrga = dr(0).ToString
orgColl.Add(tmpOrga)
getOrgas(tmpOrga, conn)
End If
End While
dr.close()
conn.Close()
Id = Nothing
End If
End Sub
Is there any reason you cannot refactor things so that each recursion uses the same db connection?
I am not a VB coder but I would tackle it as follows
Change getOrgas() to take a connection parameter defaulting to 'nothing'.
Change the Dim conn line to if IsNothing(connParameter) conn = GetConnection() else conn := connParameter;
Change your recursion line to getOrgas(orgatmp, conn);
Test the F%%%% out of it.
I have just noticed the outer While Loop. Is it there just to confuse you ? How many times will it execute ? ...
I did wonder about the datareader -
try this - I see that your datareader needs to close before you recurse, so close it.
in pseudocode -
dim locallist = new list();
while dr.read
{
LocalList.Add dr.thing;
}
dr.close;
foreach(thing in locallist)
{
if Not ValueInColl(thing) Then
CallYourFunctionTRecursively()
end if;
}
Are you with me ?
If you are trying to put together all the members of a family then it depends which database system you are using how it is done, but look up 'Heirarchical queries' in your documentation.

Query about Oracle Connections

I seem to be getting intermittent problems with my Oracle connection indicating something about a problem with semaphores which suggest that Oracle is somehow holding onto the connections instead of removing them after they have been used.
Here's the code and connection string I use:
Connection string: user id=user;password=password;data source=dataSource; Validate Connection=true;Min Pool Size=10;Connection Lifetime=5;Connection Timeout=60;Incr Pool Size=5;
And the code I use is this:
Dim OracleConn As New OracleConnection()
Dim DataTable As DataTable
Dim queryOracle As OracleCommand
Dim OracleDataAdapter As OracleDataAdapter
Dim connStr As String = "user id=user;password=password;data source=dataSource; Validate Connection=true;Min Pool Size=10;Connection Lifetime=5;Connection Timeout=60;Incr Pool Size=5;"
OracleConn.ConnectionString = connStr
Try
OracleConn.Open()
queryOracle = OracleConn.CreateCommand()
queryOracle.CommandText = "select * from table1"
DataTable = New DataTable()
OracleDataAdapter = New OracleDataAdapter(queryOracle)
OracleDataAdapter.Fill(DataTable)
table1.DataSource = DataTable.DefaultView
table1.DataBind()
Catch OracleEx As OracleException
Throw
Catch ex As Exception
Throw
Finally
If Not OracleConn Is Nothing And OracleConn.State = ConnectionState.Open Then
OracleConn.Close()
End If
End Try
Now my questions are:
Is this the best way of doing this?
I only "Close" my connection do I need to "Dispose" of it also?
I'm using Oracle.DataAccess.Client by the way.
Any help will be much appreciated
Try to put everything between Using.
Using oracleConn as OracleConnection = new OracleConnection()
'Your stuff goes here
End Using
the same goes for Commands.
P.S. There's is no need to catch Exception if they are just thrown again.
I suggest you to use using block (Execute Dispose in the end)
Using connection As New OracleConnection()
....
End Using
2 An application can call Close more than one time. No exception is generated.
If you called Dispose method SqlConnection object state will be reset. If you try to call any method on disposed SqlConnection object, you will receive exception.

Resources