Лучший способ передать объект подключения среди форм? - PullRequest
0 голосов
/ 17 февраля 2009

Предыстория: я переписываю приложение VB6, которое использовало MS Access для хранения данных, в то, которое использует VB.NET и MS SQL Server.

Мне интересно, как лучше передать соединение между различными формами в моем приложении, которым требуется соединение с базой данных. Прямо сейчас я создал класс для управления строкой соединения для безопасной передачи между формами:

Public Class LoginCredientials
    Private uname As String
    Private password_hash() As Byte = {0}
    Private server_name As String  'not used in access style databases
    Private dbname As String
    Private st As ServerType  'enum that would allow for different connections
    Private tdes As TripleDES 'encryption class to encrypt password in memory

    Public Sub New()
        uname = ""
        server_name = ""
        dbname = ""
        st = ServerType.stNotDefined
    End Sub
    Public Sub New(ByVal Username As String, _
                   ByVal Password As String, _
                   ByVal ServerName As String, _
                   ByVal DatabaseName As String, _
                   ByVal ServType As ServerType)
        tdes = New TripleDES
        uname = Username
        password_hash = tdes.Encrypt(Password)
        server_name = ServerName
        dbname = DatabaseName
        st = ServType
       tdes = Nothing
    End Sub

    Public ReadOnly Property Server_Type() As ServerType
        Get
            Return st
        End Get
    End Property
    Public ReadOnly Property CompanyName() As String
        Get
            Return dbname.Remove(0, 4)
        End Get
    End Property
    Public Property UserName() As String
        Get
            Return uname
        End Get
        Set(ByVal value As String)
            uname = value
        End Set
    End Property
    Public Property Password() As String
        Get
            tdes = New TripleDES
            Return tdes.Decrypt(password_hash)
            tdes = Nothing
        End Get
        Set(ByVal value As String)
            tdes = New TripleDES
            password_hash = tdes.Encrypt(value)
            tdes = Nothing
        End Set
    End Property
    Public Property ServerName() As String
        Get
            Return server_name
        End Get
        Set(ByVal value As String)
            server_name = value
        End Set
    End Property
    Public Property DatabaseName() As String
        Get
            Return dbname
        End Get
        Set(ByVal value As String)
            dbname = value
        End Set
    End Property

    Public Function GetConnectionString() As String
        Dim cstring As String = ""
        tdes = New TripleDES
        Select Case st
            Case ServerType.stSQLServer
                cstring = "User ID=" & uname & ";" & _
                        "Password=" & tdes.Decrypt(password_hash) & ";" & _
                        "Initial Catalog=" & dbname & ";" & _
                        "Data Source=" & server_name
        End Select
        tdes = Nothing
        Return cstring
    End Function
End Class

Я передавал ссылку на свой объект в любую из моих форм, для которой требовалось подключение к базе данных, например:

'in the form declaration
Private myLC As LoginCredientials
Public Sub New(ByRef lc As LoginCredientials)
    InitializeComponent()
    myLC = lc
End Sub

И тогда я бы создал новый объект соединения, сделал то, что мне нужно было сделать, а затем закрыл соединение и уничтожил объект соединения. Когда я делал это раньше в ADO с VB6, процесс, созданный соединением, был уничтожен, когда объект соединения был уничтожен, но это больше не так. Теперь каждый раз, когда я создаю новый объект подключения и подключаюсь к своему серверу, создается новый процесс, а затем закрывается, когда я закрываю подключение. Через некоторое время сервер начнет отказывать в соединениях, пока я не войду в систему и не завершу все процессы, созданные моим приложением. Очевидно, что это не делается правильно, и я хотел бы узнать правильный путь.

Было бы лучше просто передать один и тот же объект подключения по ссылке (или внутри класса-оболочки) среди моих форм, оставив объект подключения открытым?

Как правильно закрыть соединение, чтобы в конечном итоге я не получил несколько спящих процессов на моем SQL-сервере? Есть ли на сервере SQL параметр, который я могу настроить для автоматического отключения процессов после определенного периода бездействия?

Рассматриваете ли вы шифрование пароля при переполнении памяти во время выполнения?

Спасибо за любую помощь. :)

Ответы [ 4 ]

8 голосов
/ 17 февраля 2009

Вы НЕ должны передавать объект подключения между формами. По сути, при использовании соединения с SQL Server шаблон заключается в создании соединения, его открытии, выполнении операции, а затем закрытии соединения.

Для этого у вас должен быть где-то открытый статический метод, который сгенерирует ваше SqlConnection, которое вы бы использовали в выражении Using, например:

Using connection As SqlConnection = GetConnection
    ' Use connection here.

End Using

Это должно препятствовать тому, чтобы процессы складывались на сервере.

1 голос
/ 18 февраля 2009

Поскольку вы используете VB.NET, попробуйте следующее (код из памяти, не скопирован из приложения):

Namespace Helpers

Public NotInheritable Class Connections

    Private Sub New()

    End Sub

    Public Shared Function GetConnection(ByVal connString As String) As SqlConnection
        Dim c as New SqlConnection(connString)
        c.Open
        Return c
    End Sub

    Public Shared Sub AdoCleanup(cn As SqlConnection, cmd As SqlCommand)
        cmd.Dispose
        cn.Close
    End Sub

End Class

End Namespace

А затем используйте его так:

Private Sub LoadMyData()

    Dim connString As String = <your conn string>
    Dim cn As SqlConnection = Helpers.Connections.GetConnection(connString)
    Dim cmd As New SqlCommand

    Try
        ' data access code
    Catch ex As Exception
        ' handle exception
    Finally
        Helpers.Connections.AdoCleanup(cn, cmd)
    End Try

End Sub

Вы даже можете поместить код для получения строки подключения в GetConnection, если только вам не требуется гибкость открытия нескольких соединений с разными строками подключения.

1 голос
/ 17 февраля 2009

Я согласен с Каспером. Если вам нужно разделить объект между страницами, чтобы уменьшить нагрузку, например, тогда вы можете использовать статическую переменную-член для этого. Просто убедитесь, что соединение закрыто после выполнения последнего оператора. Вы также можете создать область подключения, которая может быть удалена после завершения последней транзакции. Если у вас нет опыта, чтобы сделать это, просто откройте и закройте соединение при первой же возможности и не передавайте его.

У меня есть веб-приложение, и для уменьшения некоторых задержек существуют случаи, когда я использую область, созданную для своего DAL, чтобы при вызовах в дочерних функциях они могли использовать то же соединение и не повышаться в MSDTC. Однако это действительно необходимо только в транзакционной системе.

1 голос
/ 17 февраля 2009

Вы можете использовать оператор Using, он закроет и удалит соединение, когда это будет сделано.

Using _conn as New SqlConnection(<connstring>)
  _conn.Open()
  'get your data'

End Using

Если вы не звоните .Close (), это может быть проблемой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...