KnowDotNet NetRefactor

AppConfig in VS2005

Use AppSetting Class in VS2003

by Les Smith
Print this Article Discuss in Forums

Let's say that you are still developing in VS2003 but you would like to utilize some of the neat things in VS2005.  Take the accessing of settings in the appConfig file.  In VS2005, you reference a setting of the app.config file using code shown below.  It is preceded by the VS2003 style.

VS2003

      Dim ftpPassWord As String = ConfigurationSettings.AppSettings("FTPPassword")

VS2005

      Dim ftpPW As String = My.Settings.FTPPassword

The advantage of the VS2005 style over the VS2003 style is fairly obvious.  First, the VS2005 style is the object oriented approach.  Secondly, this new style offers IntelliSense on the selection of settings, thus removing the inherent trap of misspelling the name of the setting and not finding out until run-time.

This article will descible a methodology for facilitating the new technology now while you are still in VS2003.  It will also show just a little Macro/Extensibility Wizardry.  First, I will show a simple appSettings section in an appConfig file.

   <appSettings>
     <add key="FTPOutputUrl" value="ftp.somesite.com" />
     <add key="FTPOutputUserid" value="someftp" />
     <add key="FTPOutputPWD" value="2ser&" />
     <add key="FTPOutputFolder" value="request" />
     <add key="Archive" value="\\server2\Prod\Data\KnowDotNet\Archive"/>
     <add key="ErrorLog" value="\\\\server2\Prod\Data\KnowDotNet\Errors\"/>
     <add key="EmailFrom" value="NoReply@KnowDotNet.com"/>
      <add key="EmailServer" value="mail.KnowDotNet.com"/>
   <appSetting/>

Next, I have built a macro to scan the appConfig file and create a MySettings Class automatically.  The entire code for the macro is shown below.  All you have to do to use it is to place the following Sub in a module in the Macro IDE.

   Public Sub AppSettingsClass()
      
Const prp As String = "Public ReadOnly Property propname() As String"
      
Const [get] As String = " Get"
      
Const endGet As String = " End Get"
      
Const ret As String = " Return "
      
Const gs As String = "GetSettings("
      
Const Imp1 As String = "Imports System.Configuration"
      
Const Imp2 As String = "Imports System.Web"
      
Const cl As String = "Public Class MySettings"
      
Const endCl As String = "End Class"
      
Const f1 As String = _
         "Public Shared Function GetSettings(ByVal key As String) As String"
      
Const f2 As String = _
         " Dim ret As String = System.Web.HttpUtility.HtmlDecode" & _
         (ConfigurationSettings.AppSettings(key))"
      
Const f3 As String = " If ret Is Nothing Then"
      
Const f4 As String = " Return String.Empty"
      
Const f5 As String = " Else"
      
Const f6 As String = " Return ret"
      
Const f7 As String = " End If"
      
Const f8 As String = "End Function"
      
Const endProp As String = "End Property"

      
Dim sb As New System.Text.StringBuilder(1000)
      
Dim patt As String = _
         "^\s*\<add\s+key\s*=\s*""(?<name>.*?)""\s+value\s*=\s*""(?<val>.*?)"""
      
Dim mc As MatchCollection
      
Dim ts As TextSelection = DTE.ActiveDocument.Selection
      ts.StartOfDocument()
      ts.EndOfDocument(
True)

      
Dim s As String = ts.Text
      mc = Regex.Matches(s, patt, RegexOptions.Multiline)

      
If mc.Count > 0 Then
         sb.Append(Imp1 & vbCrLf)
         sb.Append(Imp2 & vbCrLf)
         sb.Append(cl & vbCrLf)
        
For Each m As Match In mc
            sb.Append(prp.Replace("propname", _
               m.Groups("name").Value) & vbCrLf)
            sb.Append([get] & vbCrLf)
            sb.Append(ret & gs & Chr(34) & _
               m.Groups("name").Value & Chr(34) & ")" & vbCrLf)
            sb.Append(endGet & vbCrLf)
            sb.Append(endProp & vbCrLf)
        
Next

         sb.Append(f1 & vbCrLf)
         sb.Append(f2 & vbCrLf)
         sb.Append(f3 & vbCrLf)
         sb.Append(f4 & vbCrLf)
         sb.Append(f5 & vbCrLf)
         sb.Append(f6 & vbCrLf)
         sb.Append(f7 & vbCrLf)
         sb.Append(f8 & vbCrLf)
         sb.Append(endCl & vbCrLf)

         Debug.WriteLine(sb.ToString)
         DTE.ItemOperations.NewFile("General\Text File")
         ActiveDocument.Object("TextDocument").Selection.Insert(sb.ToString)
      
End If
      ts.StartOfDocument()
  
End Sub

After you have created your macro, you should then open the appConfig file in the IDE.  Make it the active code window.  In the Macro Explorer, double click on your new macro.  It will create a new text window in the IDE and insert the code shown below into it.  I could have made the macro create a new class and add it to the current project with just a couple more lines of automation (extensibility) code.  However, since I normally add new settings to the appConfig file throughout the development of an application, I chose to create a text window from which I can copy the new contents into a class each time I need to regenerate the settings properties.

The following code is the result from the macro code generation.  It is a complete class, ready for pasting over an empty class named MySettings.  After generating the code, I added the Class named MySettings.vb to my project and copied the entire text from the macro generation text window and pasted it over the empty class.  The new MySettings Class is shown below.

Imports System.Configuration
Imports System.Web
Public Class MySettings
  
Public ReadOnly Property FTPOutputUrl() As String
      Get
         Return GetSettings("FTPOutputUrl")
      
End Get
   End Property
   Public ReadOnly Property FTPOutputUserid() As String
      Get
         Return GetSettings("FTPOutputUserid")
      
End Get
   End Property
   Public ReadOnly Property FTPOutputPWD() As String
      Get
         Return GetSettings("FTPOutputPWD")
      
End Get
   End Property
   Public ReadOnly Property FTPOutputFolder() As String
      Get
         Return GetSettings("FTPOutputFolder")
      
End Get
   End Property
   Public ReadOnly Property Archive() As String
      Get
         Return GetSettings("Archive")
      
End Get
   End Property
   Public ReadOnly Property ErrorLog() As String
      Get
         Return GetSettings("ErrorLog")
      
End Get
   End Property
   Public ReadOnly Property EmailFrom() As String
      Get
         Return GetSettings("EmailFrom")
      
End Get
   End Property
   Public ReadOnly Property EmailServer() As String
      Get
         Return GetSettings("EmailServer")
      
End Get
   End Property
   Public Shared Function GetSettings(ByVal key As String) As String
      Dim ret As String = System.Web.HttpUtility.HtmlDecode(ConfigurationSettings.AppSettings(key))
      
If ret Is Nothing Then
         Return String.Empty
      
Else
         Return ret
      
End If
   End Function

End
Class

Note that every element of the appSettings section of the appConfig file has generated a ReadOnly Property in the MySettings class.  Now, I can access settings in my appConfig file just like I would in VS2005.  The only difference is that I don't have a period between My and Settings in the code shown below.  Obviously, I will have IntelliSense on the MySettings properties!

         Dim MySettings As New Settings
        
Dim ftpURL As String = MySettings.FTPOutputUrl

You will see that the generated method, GetSettings, in the Class uses the HtmlDecode method to access the settings of the appConfig file.  I have done this because passwords can have any character in them, including such HTML sensitive characters as "&<>".  These characters can't be coded explicitly in an appConfig file without causing an exception to be raised when you try to access them.  If you look back at the FTPPWD in the appConfig file above, you will see that I encoded it as "2ser&".  
That allows me to have an "&" in the password, but it has to be decoded in order to be returned as "2ser&", which is the real password.

Ask a Question, or give your feedback on my articles or products by going to the KnowDotNet Forum or by clicking on My Blog.
  

Writing Add-Ins for Visual Studio .NET
Writing Add-ins for Visual Studio .NET
by Les Smith
Apress Publishing