Desenvolvimento - ASP. NET

Manipulando o Web.Config Sem Causar o Restart da Aplicação

Usualmente gravamos diversas configurações no web.config na tag appSettings que são utilizadas em nossas aplicações. É comum receber e-mail ou perguntas pelo MSN com a seguinte questão: Como se pode criar uma interface para alterar e manipular estes parâmetros do web.config em tempo de execução pela aplicação.

por Fernando Cerqueira



Usualmente gravamos diversas configurações no web.config na tag appSettings que são utilizadas em nossas aplicações. É comum receber e-mail ou perguntas pelo MSN com a seguinte questão:

“Como se pode criar uma interface para alterar e manipular estes parâmetros do web.config em tempo de execução pela aplicação”

Esta pergunta esbarra em dois cenários que devem ser resolvidos:

1) Qualquer alteração no web.config causa um "restart" da aplicação, o que inviabiliza este tipo de construção.

2) É comum é termos parâmetros distintos para o ambiente de produção e o ambiente de desenvolvimento, sendo necessário também modificar o web.config quando trocamos de ambiente.

Algumas novas características foram introduzidas no framework 2,0 que permitem resolver ambos os cenários de forma bastante eficiente.

Resolvendo o primeiro Cenário:

Alterar o web.config na tag appSettings sem causar o restart da aplicação

Temos agora no framework 2.0 um novo atributo para a tag appSettings :

configSource – Informar um caminho relativo de um arquivo para definição da uma sessão executando um include em tempo de execução.

Este atributo pode ser aplicado em qualquer sessão do web.config porem causa o restart da aplicação quando o arquivo externo é alterado, com exceção de uma única sessão :AppSetting!

Quando se define este atributo não pode existir mais nenhum outro atributo na sessão. Vejamos o exemplo abaixo:

Arquivo web.config:

<configuration>

<appSettings configSource="AppSettings.config"/>

<connectionStrings/>

. . .
Arquivo AppSettings.config:

<appSettings >

<add key="AppAmbiente" value="Desenvolvimento" />

</appSettings>

Para testar basta criar um formulário que recupere a key “AppAmbiente”. Depois que estiver executando altere o arquivo AppSettings.config e recupere novamente a key “AppAmbiente” . Vai perceber que o valor retornado será o valor alterado sem sua aplicação execute um restart!

Você deve estar se perguntando por que somente a sessão AppSettings não causa o restart da aplicação... Esta pergunta é respondida descrevendo outro atributo que foi introduzindo no framework 2.0: restartOnExternalChanges. Este atributo destina-se as definições de sessões informando se uma sessão (que aceita uma definição externa) executa um “restart” na aplicação quando ocorre uma alteração no arquivo externo que foi informado.

A definição as sessão AppSettings é feita no arquivo de configuração machine.config e tem a seguinte assinatura:


<section name="appSettings" type="System.Configuration.AppSettingsSection, System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" restartOnExternalChanges="false" requirePermission="false" />

Isso explica o motivo de não ocorrer o restart na aplicação quando é feito uma alteração no arquivo externo ao web.config.
:


File - Informar um caminho relativo de um arquivo para definição da sessão appsetting executando merge em tempo de execução. Caso o arquivo não exista não é executado o merge e ignorado a informação de arquivo.

Como é feito o Merge entre o que existe já definido com as key’s/valores do arquivo informado no atributo File (caso exista) resolvemos o segundo cenário:

- Na maquina de desenvolvimento Não deve existir. Assim a informação do atributo file é ignorado e mantido os valores.


-
Na máquina de produção o arquivo Deve existir. Assim a informação do atributo file é executado.

Resolvendo o Primeiro e Segundo Cenário juntos:

Conhecendo agora os dois novos atributos (file e configSource) fica fácil criar uma única abordagem para resolver os dois cenários:

Arquivo web.config:

<configuration>

<appSettings configSource="AppSettings.config"/>

<connectionStrings/>

. . .
Arquivo AppSettings.config:

<appSettings file="AppSettingsProducao.config">

<add key="AppAmbiente" value="Desenvolvimento" />

</appSettings>

Arquivo AppSettingsProducao.config:

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

<appSettings>

<clear/>

<add key="AppAmbiente" value="Produção" />

</appSettings>

Detalhes do funcionamento na máquina de Produção:

1) Quando a aplicação é inicializada a aplicação lê o arquivo web.config que informa que a leitura da sessão AppSettings devera ser feita no arquivo AppSettings.config e incluída no web.config.

2) Durante a leitura do arquivo AppSettings.config a aplicação é informada que existe outro arquivo externo (AppSettingsProducao.config) para ser feito um merge.

3) O arquivo é localizado e após a execução do merge a key AppAmbiente” recebe o valor "Produção"

Detalhes do funcionamento na máquina de Desenvolvimento:

1) Quando a aplicação é inicializada a aplicação lê o arquivo web.config que informa que a leitura da sessão AppSettings devera ser feita no arquivo AppSettings.config e incluída no web.config.

2) Durante a leitura do arquivo AppSettings.config a aplicação é informada que existe outro arquivo externo (AppSettingsDesenv.config) para ser feito um merge.

3) O arquivo NÃO É LOCALIZADO (não deve existir em desenvolvimento) e é ignorada a execução do merge e a key “AppAmbiente” mantem o valor "Desenvolvimento"

Aplicação de Exemplo:

Antes de terminar vamos mostrar um exemplo passo a passo de todo o conceito para ficar mais claro:

1) Crie uma aplicação web no Visual Studio Express

2) Altere o web.config na tag : <appSettings configSource="AppSettings.config"/>

3) Adicione a solução um arquivo XML com o nome: AppSettings.config

4) Inclua as linhas abaixo no arquivo AppSettings.config

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

<appSettings file="AppSettingsProducao.config.off">

<add key="AppAmbiente" value="Desenvolvimento" />

</appSettings>

5) Adicione a solução um arquivo XML com o nome: AppSettingsProducao.config

6) Inclua as linhas abaixo no arquivo AppSettingsProducao.config

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

<appSettings>

<clear/>

<add key="AppAmbiente" value="Produção" />

</appSettings>

7) Adicione a solução um arquivo global.asax

8) Inclua o código abaixo no arquivo global.asax

Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)

Application("Status") = " Aplicação foi feita restart"

End Sub

9) Inclua o código dentro da <DIV> abaixo dentro do arquivo default.aspx

<form id="form1" runat="server">

<div>

Application Evento Start :

<asp:Label ID="Label3" runat="server" Text=""></asp:Label><br />

Sessão :

<asp:Label ID="Label2" runat="server" Text=""></asp:Label><br />

Ambiente :

<asp:Label ID="Label1" runat="server" Text=""></asp:Label>&nbsp;<br />

<br />

<asp:Button ID="Button1" runat="server" Text="Atualizar" />

</div>

</form>

10)Inclua na classe do formulário o código abaixo:

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

If Not Page.IsPostBack Then

Session("VarSession") = Session.SessionID

VerTeste()

End If

End Sub

Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click

VerTeste()

End Sub

Private Sub VerTeste()

Me.Label1.Text = ConfigurationManager.AppSettings("AppAmbiente").ToString

Me.Label2.Text = Session("VarSession")

Me.Label3.Text = Application("Status")

Application("Status") = "Aplicação Sem Restart"

End Sub

11)Compile a aplicação e execute

12)Altere o conteúdo key="AppAmbiente" no arquivo AppSettings.config e salve

13)Clique no botão de Atualizar

14)Altere o conteúdo file="AppSettingsProducao.config.off" para file="AppSettingsProducao.config" e salve

15)Clique no botão de Atualizar

Indo um pouco além:


Se observar com atenção já percebeu que com esta estrutura proposta podemos ter múltiplos arquivos de configuração na produção podendo escolher entre eles apenas alterado o atributo FILE. Este recurso expande as possibilidades de configuração da aplicação, mas podemos ir alem.


No inicio do artigo falamos de dois atributos (
configSource e restartOnExternalChanges). O primeiro atributo (configSource) pode ser definido no arquivo web.config para algumas tag’s : AppSettings , connectionStrings , siteMap , membership , smtpMail etc. Uma lista completa pode ser encontrada no SDK do produto.


O segundo atributo restartOnExternalChanges pode ser definido no web.config para sessões customizada. As sessões default / padrão do framework definidas pelo arquivo machine.config não podem ser alteradas no web.config , porem podemos alterar estas definições no próprio arquivo machine.config permitindo alterar os arquivos externos sem causar o restart da aplicação.

Deve ficar claro para o desenvolvedor que estas alterações no arquivo machine.config terá efeito para todas as aplicações que rodam sobre o IIS onde esta instalado o framework. Outro ponto importante é saber exatamente o efeito que uma alteração dinâmica pode causar. Um exemplo é a connectionStrings : Para deixar ela com o mesmo comportamento do AppSettings basta alterar a linha para :

<section name="connectionStrings" type="System.Configuration.ConnectionStringsSection, System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" requirePermission="false" restartOnExternalChanges="false" />

A principal pergunta quando alterar neste exemplo o comportamento é: Se houve uma alteração da string de conexão provavelmente você estará acessando outro banco... O que acontece se isso ocorrer no meio de um processo onde já possui dado e executado a lógica baseado em resultados provenientes do banco anterior?

A idéia aqui é demonstrar que podemos com pouco esforço deixar o framework e a configuração bem mais flexível, porem as implicações de mudanças dinâmicas deve ser pensado de forma criteriosa para garantir a consistência dos dados, interfaces e processos da aplicação.

Conclusão:

Devido às novas características introduzidas no framework 2.0 o desenvolvedor passou a contar com recursos de configurações mais poderosos e dinâmicos, sendo possível criar as interfaces para leitura dos arquivos XML de configuração e executar alterações em tempo de execução. Alem desta facilidade tornou-se possível manter ambientes distintos sem a necessidade de se alterar valores de chaves em arquivos de configuração evitando-se assim erros comuns causados pelo “esquecimento” ou alteração indevida destas chaves.

Fernando Cerqueira

Fernando Cerqueira - Microsoft Most Valuable Professional em ASP.NET 2004 – 2005 – 2006 . Possui formação Acadêmica em Administração de empresas, especialista em Call Center , BI e CRM. Atuou em diversas empresas de grande porte, sempre utilizando a plataforma Microsoft. Desde 2002 vem trabalhando com o Visual Studio .NET prestando consultoria e treinamento focando os resultados em ASP.NET. Em 2003, criou o GURJ.NET - Grupo de usuários .NET do Rio de Janeiro sendo reconhecido pelo INETA. Hoje voluntariamente dedica parte de seu tempo no comitê de Web e Infra da INETA Brasil. Atualmente, como profissional, presta serviços exclusivamente na plataforma Microsoft.NET atuando como arquiteto de sistemas em diversos projetos de porte nos estados do RJ, SP e MG.