terça-feira, 13 de maio de 2008

Criando configurações utilizando configSections customizados

Olá! Neste post pretendo apresentar uma forma mais elegante do que o AppSettings para amazenar as configurações de aplicativos.

De cada 10 aplicações que desenvolvemos, 9 precisam de parâmetros de configuração. Normalmente utiliza-se o web.config (para aplicações ASP.Net) ou o app.config (para aplicações Console ou Windows) para armazenar as configurações. Normalmente vemos o seguinte:


<appsettings>
<add key="Parametro1" value="ValorDoParam1">
<add key="Parametro2" value="ValorDoParam2">
</appsettings>


Esta abordagem é simples e normalmente atende nossas necessidades. Porém ao utilizar esta abordagem temos os seguintes problemas:

  • Este espaço é compartilhado, o que torna mais difícil e suscetível a erros a configuração e manutenção

  • Todos os dados são armazenados como String e não possuem nenhum tipo de validação para o tipo que eles realmente representam

  • Não é possível armazenar estruturas complexas, como objetos por exemplo

Recentemente me deparei com uma alternativa muito interessante para melhorar a forma de armazenar configurações utilizando o Namespace System.Configuration do .Net Framework.
Esta alternativa nos permite criar seções dentro dos arquivos de configuração customizadas. Estas seções terão classes de fachada para recuperar (de uma forma simples) as configurações armazenadas de forma estruturada.

Para criar a classe de fachada, basta herdar da classe System.Configuration.ConfigurationSection e definir propriedades que devolvem as configurações que virão do arquivo de configuração, exemplo:

<!-- O trecho a seguir configura as secões customizadas do arquivo de configurações -->
<configSections>
<section name="ExemploConfig" type="ExemploConfiguracao.Configuration, ExemploConfiguracao"/>
</configSections>

<!-- A Seguir estão as configurações armazenadas no trecho configurado anteriormente -->
<ExemploConfig SaveLog="True" />

Para a configuração acima teríamos a classe abaixo:

Public Class Configuration
Inherits System.Configuration.ConfigurationSection

<System.Configuration.ConfigurationProperty("SaveLog", IsRequired:=True)> _
Public ReadOnly Property SaveLog() As Boolean
Get
Return Convert.ToBoolean(MyBase.Item("SaveLog"))
End Get
End Property
End Class


Neste exemplo, a classe Configuration serve de fachada para a recuperação das configurações. Para acessar essas configurações é só fazer o seguinte:


Dim _Config As Configuration = System.Configuration.ConfigurationManager.GetSection("ExemploConfig")

Dim _SaveLog As Boolean = _Config.SaveLog


É possível também criar coleções de configurações: para isto, é necessário criar uma classe para lidar com a coleção e uma outra classe que definirá os itens dessa coleção, por exemplo, para adicionarmos uma coleção de módulos dentro do nosso exemplo anterior, ficaria assim:

Arquivo XML:


<!-- O trecho a seguir configura as secões customizadas do arquivo de configurações -->
<configSections>
<section name="ExemploConfig" type="ExemploConfiguracao.Configuration, ExemploConfiguracao"/>
</configSections>

<!-- A Seguir estão as configurações armazenadas no trecho configurado anteriormente -->
<ExemploConfig SaveLog="True">
<Modules>
<add ModuleName="Teste1" ExtractQuery="Select * From Tabela" />
<add ModuleName="Teste2" />
</Modules>
</ExemploConfig>


Classe Configuration:


Public Class Configuration
Inherits System.Configuration.ConfigurationSection

<System.Configuration.ConfigurationProperty("SaveLog", IsRequired:=True)> _
Public ReadOnly Property SaveLog() As Boolean
Get
Return Convert.ToBoolean(MyBase.Item("SaveLog"))
End Get
End Property

<System.Configuration.ConfigurationProperty("Modules", IsRequired:=False)> _
Public ReadOnly Property Modules() As ModuleConfigurationCollection
Get
Return MyBase.Item("Modules")
End Get
End Property
End Class


Classe que controlará a coleção:

<System.Configuration.ConfigurationCollection(GetType(ModuleConfiguration), AddItemName:="add", ClearItemsName:="clear")> _
Public Class ModuleConfigurationCollection
Inherits System.Configuration.ConfigurationElementCollection

Protected Overloads Overrides Function CreateNewElement() As System.Configuration.ConfigurationElement
Return New ModuleConfiguration()
End Function

Protected Overrides Function GetElementKey(ByVal element As System.Configuration.ConfigurationElement) As Object
Return DirectCast(element, ModuleConfiguration).ModuleName
End Function

Default Public Overloads ReadOnly Property Item(ByVal Index As Int32) As ModuleConfiguration
Get
Return BaseGet(Index)
End Get
End Property
End Class


Classe que representa os itens da coleção:


Public Class ModuleConfiguration
Inherits System.Configuration.ConfigurationElement

<System.Configuration.ConfigurationProperty("ModuleName", IsRequired:=True, IsKey:=True)> _
Public ReadOnly Property ModuleName() As String
Get
Return Me.Item("ModuleName")
End Get
End Property

<System.Configuration.ConfigurationProperty("ExtractQuery")> _
Public ReadOnly Property ExtractQuery() As String
Get
Return Me.Item("ExtractQuery")
End Get
End Property
End Class


Pesquisando mais afundo você encontrará parâmetros que podem ser configurados nas propriedades da classe de fachada que implementam validação sobre os dados inseridos, além da validação básica que há no exemplo (IsRequired:=True).

Acredito que esta abordagem para configuracões de aplicativos pode trazer benefícios na fase de implantação, pois é possível criar um ConfigSection mais intuitivo para quem irá realizar a configuração do aplicativo (na maioria das vezes quem realiza esta configuração não é o desenvolvedor). Esta abordagem também torna mais simples a tarefa de mover as configurações para um arquivo XML diferente do web.config ou do app.config.

Baixe o exemplo acima completo para o Visual Studio 2008: Download

2 comentários:

Gabriel Guedes disse...

Bela iniciativa!

Henrique Avila disse...

Valeu!!!

Com esse espaço pretendo trocar idéias com o pessoal interessado nestes assuntos e expor minha opinião!

Abrassss!