views:

31

answers:

1

I have a Visual Basic .Net 2.0 program. I'm moving the settings from an older settings file, to an app.config program settings file. I'm trying to do this as nicely as possible.

So, I added my setting as shown in this image.

On load I do this:

If My.Settings.databaseConnectionSettings Is Nothing Then
            My.Settings.databaseConnectionSettings = New ArrayList()
End If

This is my custom class:

Imports System.Xml.Serialization

<Serializable()> Public Class DatabaseConnectionSettings
    Private _nickname As String = String.Empty
    Private _username As String = String.Empty
    Private _password As String = String.Empty
    Private _database As String = String.Empty
    Private _server As String = String.Empty
    Private _ssl As Boolean

    Public Sub New()
        _nickname = ""
        _username = ""
        _password = ""
        _database = ""
        _server = ""
        _ssl = False
    End Sub

    Public Sub New(ByVal nickname As String, ByVal username As String, _
                   ByVal password As String, ByVal database As String, _
                   ByVal server As String, ByVal ssl As Boolean)
        _nickname = nickname
        _username = username
        _password = password
        _database = database
        _server = server
        _ssl = ssl
    End Sub

    Public Property nickname() As String
        Get
            Return _nickname
        End Get
        Set(ByVal Value As String)
            _nickname = Value
        End Set
    End Property

    Public Property username() As String
        Get
            Return _username
        End Get
        Set(ByVal Value As String)
            _username = Value
        End Set
    End Property

    Public Property password() As String
        Get
            Return _password
        End Get
        Set(ByVal Value As String)
            _password = Value
        End Set
    End Property

    Public Property database() As String
        Get
            Return _database
        End Get
        Set(ByVal Value As String)
            _database = Value
        End Set
    End Property

    Public Property server() As String
        Get
            Return _server
        End Get
        Set(ByVal Value As String)
            _server = Value
        End Set
    End Property

    <XmlElementAttribute(ElementName:="ssl")> Public Property ssl() As Boolean
        Get
            Return _ssl
        End Get
        Set(ByVal Value As Boolean)
            _ssl = Value
        End Set
    End Property

End Class

And, this is how I use it:

Dim databaseSettings As New DatabaseConnectionSettings( _
                        Me.txtNickName.Text, Me.txtUser.Text, Me.txtPass.Text, Me.txtData.Text, _
                            Me.txtServer.Text, Me.chkSSL.Checked)
                        'This statement will increment the arraylist count'
                        My.Settings.databaseConnectionSettings.Add(databaseSettings)
                        'This statement will save everything but the array list'
                        My.Settings.Save()
                        'This statement reloads everything, but the array list.  The array list count after this goes to zero.'
                        My.Settings.Reload() 'If I remove this, program works fine until next run.'

So, the question is, how do I get that arraylist of my DatabaseConnectionSettings saved to persistent storage? I want to do this in the cleanest way possible. That is, I don't want to have to convert it to a string or save it to a separate file every-time I want to use it. I would like to be able to use the My.Settings accessor method.

Note, it's working perfectly, except it's not being saved to storage.

+1  A: 

Debug + Exceptions, tick the Thrown box for CLR exceptions. You'll now see what is going wrong. There are several exceptions but the deal breaker is the second one, "The type ... was not expected".

Attributes are required to tell the xml serializer what types are stored in an ArrayList. This is described in this MSDN Library page, "Serializing an ArrayList" section. Problem is, you cannot apply the required [XmlElement] attribute since the ArrayList instance is declared in auto-generated code. A generic List(Of T) doesn't have the same problem, but now you'll smack into a restriction in the setting designer, it doesn't support generic types.

Well, a rock and a hard place here, you can't make this work. StringCollection is the distasteful alternative. Or ditch the idea of using Settings for this and just do it yourself with xml serialization. Or whatever else you prefer.

Hans Passant
I figured this out. Basically, I created a wrapper for the ArrayList. I defined it using the "Serializing an ArrayList" section of that page. I then made it ISerializable, but I don't know if that's needed. Then, I put the wrapper class as the type of "setting," buy browsing, and then typing the full path to that class with the namespace. It's amazing that most programming problems boil down to adding an extra level of abstraction (the wrapper class) or bugs in the IDE (not being able to browse my own NAMESPACE). Peace!
Michael
Kudos for the quick hack but I think you're going 250 miles per hour into a brick wall. There's a good reason why classes in your own namespace are not browsable. Build + Clean, Build + Build and I suspect your headlights will crumble when the compiler cannot find a type in an assembly that it is trying to build. Workaround is to create a class library project with the type so it is built and available by the time the settings code is getting compiled.
Hans Passant
Well, it seems like the form where you add the My.Settings-settings edits the Settings.Designer.vb file. The Settings.Designer.vb file is the auto generated code. And, it already includes references to my projects namespace, so it should have access to it at compile time. The fix seems to work. That being said, your solution with the class library project would be much nicer.
Michael