miércoles, 30 de noviembre de 2011

Filling app.config trough setup project

Hi,

After having the app.config & the Setup Project, to do this we need to:

1.- Rigth click in Setup Project -->Add-->Project Output-->Primary output
2.- Right click again & View User Interface
3.- In User Interface, at Start Node, Right Click & Add Dialog, Select the one fill your needs
4.- View the properties of Dialog Added and  make visible only the controls you need filling the Editlabels, the one important is the EditProperty's to access it from an Installer Class.
5.- Rigth click in Setup Project-->View-->Custom Actions
6.- Rigth click in Custom Actions --> Add Custom Action-->Application Folder
7.- Select the primary output of Install node and view their properties, at CustomActionData set the Dialog Added properties into Vars space separated like:
/TARGETDIR="[TARGETDIR]\" (ending with backslash in directories & between quotation marks).
/DBDIR=[DBDIR].
8.- Right click in the project where the app.config is and Add-->New Item->General (Installer Class).
9.- At the Installer class we need to override the Install method to do that we need (filling the app.config values from the installation parameters) like:

public override void Install(System.Collections.IDictionary stateSaver)
{base.Install(stateSaver);
string targetDirectory = Context.Parameters["targetdir"];
string param1 = Context.Parameters["DBDIR"];
string exePath = string.Format("{0}Myapp.exe", targetDirectory);
Configuration config = ConfigurationManager.OpenExeConfiguration(exePath);
config.AppSettings.Settings["DBDir"].Value = param1;
config.Save();
}
10.- Save & Rebuild
11.- Test it.

Greetings.

jueves, 30 de junio de 2011

Adding & using custom Config section elements to/from app.config

Hello,

I needed some custom configuration that can be readed at flat file level this taking care of resources, dependencies, etc.. so discarding to save the configuration in a DataBase.

I thought about the app.config and by default we can save som configs only with 2 values per register, one for the key and other for the value but my config requirement was of 1 key and 4 attributes or values.

Web Surfing I found some documentation in how to create a custom config that can be saved at app.config and then read it from code using the existent ConfigurationManager tool, the page: http://msdn.microsoft.com/en-us/library/2a1tyt9s.aspx

After a lot of reading and understanding I created a class  in my Win Services solution

Public Class PathSection
    Inherits ConfigurationSection

End Class

adding the properties or attributes that i want to use.

<ConfigurationProperty("name", _
            DefaultValue:="", _
            IsRequired:=True, _
            IsKey:=False)> _
    Public Property Name() As String
        Get
            Return CStr(Me("name"))
        End Get
        Set(ByVal value As String)
            Me("name") = value
        End Set
    End Property

Name() is like we are going to see the property in the code.
name is how we have to set the attribute in the app.config file.

Adding as many properties as we need.

the class must have other methods to serialize & deserialize:

Protected Overrides Sub DeserializeSection( _
        ByVal reader As System.Xml.XmlReader)
        MyBase.DeserializeSection(reader)
        ' Enter your custom processing code here.
    End Sub 'DeserializeSection
    Protected Overrides Function SerializeSection( _
        ByVal parentElement As ConfigurationElement, _
        ByVal name As String, _
        ByVal saveMode As ConfigurationSaveMode) As String
        Dim s As String = _
            MyBase.SerializeSection(parentElement, _
            name, saveMode)
        ' Enter your custom processing code here.
        Return s
    End Function 'SerializeSection

Other two are for simple or collection type of property(we need the collection one):

    ' Declare an element (not in a collection) of the type
    ' UrlConfigElement. In the configuration
    ' file it corresponds to <simple .... />.
    <ConfigurationProperty("simple")> _
    Public ReadOnly Property Simple() _
        As PathElement
        Get
            Dim url As PathElement = _
                CType(Me("simple"),  _
                PathElement)
            Return url
        End Get
    End Property

    ' Declare a collection element represented
    ' in the configuration file by the sub-section
    ' <urls> <add .../> </urls>
    ' Note: the "IsDefaultCollection = false"
    ' instructs the .NET Framework to build a nested
    ' section like <urls> ...</urls>.
    <ConfigurationProperty("paths", _
        IsDefaultCollection:=False)> _
    Public ReadOnly Property Paths() _
        As PathElementCollection
        Get
            Dim pathElementsCollection _
                As PathElementCollection = _
                CType(Me("paths"), PathElementCollection)
            Return pathElementsCollection
        End Get
    End Property

Ok, we have the tools to do the job, so now, how to use it?

Well, first adding the app.config file using Add-->New File, in Common Items-->General, Selecting Application Configuration File, and the app.config is added, Open it, and we must see something like this:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.diagnostics>
        <sources>
            <!-- This section defines the logging configuration for My.Application.Log -->
            <source name="DefaultSource" switchName="DefaultSwitch">
                <listeners>
                    <add name="FileLog"/>
                    <!-- Uncomment the below section to write to the Application Event Log -->
                    <!--<add name="EventLog"/>-->
                </listeners>
            </source>
        </sources>
        <switches>
            <add name="DefaultSwitch" value="Information" />
        </switches>
        <sharedListeners>
            <add name="FileLog"
                 type="Microsoft.VisualBasic.Logging.FileLogTraceListener, Microsoft.VisualBasic, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"
                 initializeData="FileLogWriter"/>
            <!-- Uncomment the below section and replace APPLICATION_NAME with the name of your application to write to the Application Event Log -->
            <!--<add name="EventLog" type="System.Diagnostics.EventLogTraceListener" initializeData="APPLICATION_NAME"/> -->
        </sharedListeners>
    </system.diagnostics>
</configuration>

There's no <configSections> element so we are going to add it, at the begining just after:

<?xml version="1.0" encoding="utf-8"?><configuration>
The <configSections> element is to declare the section that we just created before,so must looks like this:

<?xml version="1.0" encoding="utf-8"?><configuration>
  <configSections>


  </configSections>

 Between <configSections></configSections> we are going to declare our section created before inserting this: <section name="ConfPaths" type="CFD.PathSection, EDIOrganizer" requirePermission="false" />, I will explain each part:

<section name="ConfPaths" //This is the name that we want to name or declare our section.
type="CFD.PathSection, EDIOrganizer" //This type is constructed by 2 parts comma separated, the first one is the Root namespace dot our class name for the section, the second one is the Assembly name. (This info is at the Solution properties).

requirePermission="false" //documented at: http://msdn.microsoft.com/en-us/library/system.configuration.sectioninformation.requirepermission.aspx

Once declared our section we can use it, our section is named section name="ConfPaths" so we add it:

<ConfPaths name="OrganizePaths"></ConfPaths>

Inside declare the collection name that we set at our Section Class <ConfigurationProperty("paths", _
 <ConfPaths name="OrganizePaths">
    <Paths>

    </Paths>
</ConfPaths>

Now our objective declare all the elements with the attributes that we configured in the Section Class.


<ConfPaths name="OrganizePaths">
    <Paths>
        <add name="0" source="E:\Root" xmltarget="E:\XML" pdftarget="E:\PDF" />
        ...
        ...
    </Paths>
</ConfPaths>


To get access to this config section at code we can use:

' Get the current configuration file.
Dim config As System.Configuration.Configuration = ConfigurationManager.OpenExeConfiguration( _
                ConfigurationUserLevel.None)
' Get the MyUrls section.
Dim SConf As PathSection = config.GetSection("ConfPaths")

At this point we finished adding & using custom config elements.

VB. NET Windows Service with Timer

Hi,

I was wondering in how to do a Win Service that will execute at certain periods of time, and the way I achieved it was doing this.

Using VS selecting a project of type Windows Service a class is created with OnStart and OnStop Routines, so at this point the service only execute a bunch of code in the OnStart Routine when is started .

What we are going to do is declare some var of type Timers.Timer

Public T As New Timers.Timer(60000)

60000 is the time in milliseconds that the service is going to execute some code.
Now we must associate an event Handler to the OnStart Sub with the elapsed event

Protected Overrides Sub OnStart(ByVal args() As String)
        AddHandler T.Elapsed, AddressOf T_Tick
End Sub

We must create the Method T_Tick wich has the code to be executed each 60 seconds.

Private Sub T_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs)
'...
'...
'...
End Sub