Introduction
This is an Enterprise Library wrapper class to implement run-time dynamic connection strings without using config file.
Background
Enterprise Library out of the box recommends storing connection strings and provider information in a config file. Our applications generate connection strings dynamically during run-time. So I developed this enterprise library wrapper class to allow us to use the enterprise library with run-time dynamic connection strings.
Using the Code
Download the EntLibWrapper class and the Common functions.
The downloaded VB files can be included in a .NET project to use the EntLibWrapper
class. I am giving below details as to how we can use the Enterprise Library wrapper class with run-time dynamic connection strings:
I use the following Enterprise Library wrapper class to use the library with run-time generated connection strings:
Imports Microsoft.Practices.EnterpriseLibrary.Data
Imports system.Data.Common
Imports system.Data.Odbc
Imports System.Data.OleDb
Imports System.Data.OracleClient
Imports System.Data.SqlClient
Public Class EntLibWrapper
Private db As Database
Private dbCommand As DbCommand
Private dbConn As DbConnection
Private dbread As IDataReader
Private conString As String
Private dbProvider As enumProviderFactory
Private dbRowsAffected As Integer
Private dbIdentity As Integer
Public Enum enumProviderFactory
OleDb = 1
Sql = 2
Odbc = 3
Oracle = 4
End Enum
Public Sub New(ByVal connectionString As String, _
ByVal Provider As enumProviderFactory)
Select Case Provider
Case enumProviderFactory.OleDb
db = GetDatabase(connectionString, "System.Data.OleDb")
Case enumProviderFactory.Sql
db = GetDatabase(connectionString, "System.Data.SqlClient")
Case enumProviderFactory.Odbc
db = GetDatabase(connectionString, "System.Data.Odbc")
Case enumProviderFactory.Oracle
db = GetDatabase(connectionString, "System.Data.OracleClient")
End Select
conString = connectionString
dbProvider = Provider
End Sub
Public Sub Close()
db = Nothing
dbCommand = Nothing
If Not dbread Is Nothing Then
dbread.Close()
End If
If Not dbConn Is Nothing Then
dbConn.Close()
End If
End Sub
Public ReadOnly Property Database() As Database
Get
Return db
End Get
End Property
Public ReadOnly Property RowsAffected() As Integer
Get
Return dbRowsAffected
End Get
End Property
Public ReadOnly Property Identity() As Integer
Get
Return dbIdentity
End Get
End Property
Private Function GetDatabase(ByVal connectionString As String, _
ByVal dbProviderFactoryString As String) As Database
Return New GenericDatabase(connectionString, _
System.Data.Common.DbProviderFactories.GetFactory(dbProviderFactoryString))
End Function
Public Function GetDataReader(ByVal sql As String) As IDataReader
dbCommand = db.GetSqlStringCommand(sql)
Select Case dbProvider
Case enumProviderFactory.OleDb
dbread = CType(db.ExecuteReader(dbCommand), OleDbDataReader)
Case enumProviderFactory.Sql
dbread = CType(db.ExecuteReader(dbCommand), SqlDataReader)
Case enumProviderFactory.Odbc
dbread = CType(db.ExecuteReader(dbCommand), OdbcDataReader)
Case enumProviderFactory.Oracle
dbread = CType(db.ExecuteReader(dbCommand), OracleDataReader)
End Select
Return dbread
End Function
Public Function GetDataSet(ByVal sql As String, ByVal TableName As String) As DataSet
Dim ds As DataSet = New DataSet
ds = db.ExecuteDataSet(CommandType.Text, sql)
ds.Tables(0).TableName = TableName
Return ds
End Function
Public Sub LoadDataSet(ByVal sql As String, ByRef ds As DataSet, _
ByVal TableName As String)
db.LoadDataSet(CommandType.Text, sql, ds, New String() {TableName})
End Sub
Public Function GetDataTable(ByVal sql As String, _
ByVal TableName As String) As DataTable
Dim ds As DataSet = New DataSet
ds = db.ExecuteDataSet(CommandType.Text, sql)
ds.Tables(0).TableName = TableName
Return ds.Tables(TableName)
End Function
Public Function GetDataAdapter() As IDbDataAdapter
Return db.GetDataAdapter()
End Function
Public Function DoActionQuery(ByVal sql As String) As String
Dim retval As String
Dim cmdGetIdentity As DbCommand
Select Case dbProvider
Case enumProviderFactory.OleDb
dbConn = New OleDbConnection(conString)
dbConn.Open()
dbCommand = New OleDbCommand(sql, dbConn)
cmdGetIdentity = New OleDbCommand()
cmdGetIdentity.CommandText = "SELECT @@IDENTITY"
cmdGetIdentity.Connection = dbConn
Case enumProviderFactory.Sql
dbConn = New SqlConnection(conString)
dbConn.Open()
dbCommand = New SqlCommand(sql, dbConn)
cmdGetIdentity = New SqlCommand()
cmdGetIdentity.CommandText = _
"SELECT SCOPE_IDENTITY() AS [SCOPE_IDENTITY]"
cmdGetIdentity.Connection = dbConn
Case enumProviderFactory.Odbc
dbConn = New OdbcConnection(conString)
dbConn.Open()
dbCommand = New OdbcCommand(sql, dbConn)
Case enumProviderFactory.Oracle
dbConn = New OracleConnection(conString)
dbConn.Open()
dbCommand = New OracleCommand(sql, dbConn)
End Select
dbRowsAffected = 0
Try
dbRowsAffected = dbCommand.ExecuteNonQuery()
Select Case dbProvider
Case enumProviderFactory.OleDb, enumProviderFactory.Sql
dbIdentity = cmdGetIdentity.ExecuteScalar().ToString()
Case enumProviderFactory.Odbc, enumProviderFactory.Oracle
dbIdentity = 0
End Select
retval = "Success"
Catch exc As Exception
retval = "Error: " & exc.Message & "<br><br>" & _
exc.InnerException.Message & "."
Finally
dbCommand = Nothing
cmdGetIdentity = Nothing
dbConn.Close()
End Try
Return retval
End Function
Public Function GetTableWithZero(ByVal SQLString As String, _
ByVal ValueField As String, ByVal TextField As String) As DataTable
Dim dtTable As DataTable = New DataTable
Dim dr As DataRow
Dim dcDescription As New DataColumn("description")
Dim dcID As New DataColumn("id")
dtTable.Columns.Add(dcID)
dtTable.Columns.Add(dcDescription)
dr = dtTable.NewRow()
dr(0) = "FirstDummyRecord"
dr(1) = ""
dtTable.Rows.Add(dr)
dbread = db.ExecuteReader(CommandType.Text, SQLString)
While (dbread.Read())
dr = dtTable.NewRow()
dr(0) = dbread(ValueField)
dr(1) = dbread(TextField)
dtTable.Rows.Add(dr)
End While
dbread.Close()
Return dtTable
End Function
End Class
The following helper functions are used to encrypt / decrypt appSettings
in web.config as well as application variables which are used to assemble and store connection strings in memory during run-time dynamically:
Imports System.Configuration
Imports system.Web.Configuration
Imports Microsoft.Practices.EnterpriseLibrary.Security.Cryptography
Module Common
Private Const symmProvider As String = "SelfServiceCryptoProvider"
Public Sub ProtectSection(ByVal sectionName As String, _
ByVal provider As String, ByVal VirtualPath As String)
Dim config As Configuration = _
WebConfigurationManager.OpenWebConfiguration(VirtualPath)
Dim section As ConfigurationSection = config.GetSection(sectionName)
If ((section.SectionInformation.IsProtected = False) AndAlso _
(section.ElementInformation.IsLocked = False)) Then
section.SectionInformation.ProtectSection(provider)
section.SectionInformation.ForceSave = True
config.Save(ConfigurationSaveMode.Full)
End If
End Sub
Public Sub UnProtectSection(ByVal sectionName As String, _
ByVal VirtualPath As String)
Dim config As Configuration = _
WebConfigurationManager.OpenWebConfiguration(VirtualPath)
Dim section As ConfigurationSection = config.GetSection(sectionName)
section.SectionInformation.UnprotectSection()
section.SectionInformation.ForceSave = True
config.Save(ConfigurationSaveMode.Full)
End Sub
Public Function EncryptValue(ByVal UnEncryptedValue As String) As String
Dim RetVal As String
If (Not (UnEncryptedValue Is Nothing) AndAlso _
UnEncryptedValue.Trim().Length > 0) Then
RetVal = Cryptographer.EncryptSymmetric(symmProvider, UnEncryptedValue & "")
End If
Return RetVal
End Function
Public Function DecryptValue(ByVal EncryptedValue As String) As String
Dim RetVal As String
If (Not (EncryptedValue Is Nothing) _
AndAlso EncryptedValue.Trim().Length > 0) Then
RetVal = Cryptographer.DecryptSymmetric(symmProvider, EncryptedValue & "")
End If
Return RetVal
End Function
End Module
I generate my connection strings when the application starts in Global.asax as follows - the password is retrieved from web.config. Note that the connection string is stored in application variables in an encrypted form and decrypted when instantiating the EntLibWrapper
class. Also note that the appSettings
in web.config is encrypted or decrypted based on a parameter retrieved from a database - this enables the developer to add new appSettings
later after decrypting the section:
Const UserId As String = "YourUserNameGoesHere"
Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
Dim Password As String = ConfigurationManager.AppSettings("SYSPWD")
Application("News") = EncryptValue_
("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & _
Server.MapPath("../fpdb/News.mdb") & ";Jet OLEDB:System Database=" _
& Server.MapPath("../fpdb/SelfService.mdw") & ";User ID=" & _
UserId & ";Password=" & Password & ";")
Dim ELW As New EntLibWrapper(DecryptValue(Application("News")), _
EntLibWrapper.enumProviderFactory.OleDb)
Dim dbread As OleDbDataReader
Dim sql As String
Dim EncryptAppSettings As Boolean
sql = "SELECT tblParameters.*"
sql = sql & " FROM [tblParameters]"
sql = sql & " WHERE (((tblParameters.RecordId)='EncryptAppSettings'));"
dbread = ELW.GetDataReader(sql)
If dbread.HasRows Then
Do While dbread.Read()
EncryptAppSettings = dbread.Item("MyBoolean")
Loop
Else
EncryptAppSettings = True
End If
dbread.Close()
ELW.Close()
If EncryptAppSettings = True Then
"DataProtectionConfigurationProvider", "/timetable/Documentation")
"RSAProtectedConfigurationProvider", "/timetable/Documentation")
Call ProtectSection("appSettings", _
"SelfServiceConfigurationProvider", "/timetable/Documentation")
Else
Call UnProtectSection("appSettings", "/timetable/Documentation")
End If
End Sub
Then where I need to get the data, the code is as follows for getting a data reader and binding it to a dropdownlist
:
Dim ELW As New EntLibWrapper(DecryptValue(Application("News")), _
EntLibWrapper.enumProviderFactory.OleDb)
Dim dbread As OleDbDataReader
Dim sql As String
sql = "SELECT qryNewsCountry.*"
sql = sql & " FROM qryNewsCountry;"
dbread = ELW.GetDataReader(sql)
ddCountry.DataSource = dbread
ddCountry.DataTextField = "CountryName"
ddCountry.DataValueField = "Country"
If Session("SelectedCountryIndex") Is Nothing Then
ddCountry.SelectedIndex = 0
Else
ddCountry.SelectedIndex = Session("SelectedCountryIndex")
End If
ddCountry.DataBind()
dbread.Close()
ELW.Close()
For the encryption / decryption to work, we need web.config entries. The sample web.config you have downloaded contains entries which have been created using the Enterprise Library Configuration tool.
The following links are useful to fully understand issues regarding encryption / decryption. This will also help you to create your encryption keys:
Please note that the EntLibWrapper
class can be used even if you are not bothered about encryption / decryption. The class does not force you to encrypt appSettings
in web.config or the connection strings stored in application variables. You are also not forced to store the connections strings in application variables - you can also retrieve it from a database if that suits your requirement better.
The EntLibWrapper
class has the following methods / properties / enums / references:
Methods
Close
LoadDataSet
New
DoActionQuery
GetDataAdapter
GetDatabase
GetDataReader
GetDataSet
GetDataTable
GetTableWithZero
Properties
Database
- This enables the user to get access to the other methods and properties in the GenericDatabase
in Enterprise Library
Identity
- After calling the DoActionQuery
method to insert a record, the user can retrieve the id of the last record inserted using this property. RowsAffected
- After calling the DoActionQuery
method, the user can retrieve the number of rows affected from this property.
Enum
References
Microsoft.Practices.EnterpriseLibrary.Common
Microsoft.Practices.EnterpriseLibrary.Data
Microsoft.Practices.EnterpriseLibrary.Security.Cryptography
System.Configuration
System.Data.Common
System.Data.Odbc
System.Data.OleDb
System.Data.OracleClient
System.Data.SqlClient
System.Web.Configuration
The downloaded EntLibWrapper.CHM file should give you more details of the EntLibWrapper
class. When you use the class in your project, you will notice that it integrates well with Intellisense and the Object Explorer in Visual Studio. I was also able to generate the CHM file using nDocs easily. In case you are wondering how this was achieved, you can have a look at the following links:
Thanks to those who have given me feedback based on which I was able to improve the class further. Hope this enterprise library wrapper class is of use to others too.
Cheers
Raja Lakshman
History
- 11th June, 2009
- 16th June, 2009
RowsAffected
and Identity
properties added
- 26th June, 2009
- Added
LoadDataSet
method - Added
Encryption
/Decryption
functions - Compiled help file added using XML comments in code.