Arquivos app.config / web.config específicos do desenvolvedor no Visual Studio

93

Temos vários projetos .NET onde armazenamos certas configurações nos arquivos de configuração.

Agora, cada desenvolvedor terá seus próprios arquivos de configuração que diferem um pouco (strings de conexão diferentes para se conectar a bancos de dados locais, terminais WCF diferentes , etc.)

No momento, temos a tendência de verificar os arquivos app / web.config e modificá-los para atender às nossas necessidades.

Isso leva a muitos problemas, pois de vez em quando alguém verifica suas próprias configurações ou perde a configuração personalizada ao obter a versão mais recente do TFS .

Como você lida com situações como essa? Ou você não tem esse problema?

twarz01
fonte
10
Estou votando para reabrir, já que este é um problema comum para desenvolvedores de estúdio visual e envolve diretamente as ferramentas que os desenvolvedores estão usando. (daí os votos)
Christian Gollhardt
Concordo, esse é um problema persistente, pois o tamanho de nossa equipe cresceu e várias tentativas de solução foram insatisfatórias.
DiskJunky de

Respostas:

66

Usamos um sistema que combina várias das respostas existentes nesta página, além de recorrer a esta sugestão de Scott Hanselman .

Resumindo, o que fizemos foi ter um app.config / web.config comum e ter a maioria das configurações específicas em arquivos individuais, conforme sugerido por outras respostas aqui. por exemplo, para nossas configurações de SMTP, o app.config contém

<system.net>
  <mailSettings>
    <smtp configSource="config\smtp.config" />
  </mailSettings>
</system.net>

Este arquivo está no controle de origem. No entanto, os arquivos individuais, como este, não são:

<?xml version="1.0" encoding="utf-8" ?>
<smtp deliveryMethod="Network">
  <network host="127.0.0.1" port="25" defaultCredentials="false" password="" userName ="" />
</smtp>

Mas não é bem aí que a história termina. E quanto a novos desenvolvedores ou uma nova instalação de código-fonte? A maior parte da configuração não está mais no controle de origem, e é uma dor construir manualmente todos os arquivos .config de que precisam. Eu prefiro ter uma fonte que pelo menos compile direto da caixa.

Portanto, mantemos uma versão dos arquivos .config no controle de origem, denominados arquivos .config.default . Uma nova árvore de origem, portanto, tem a seguinte aparência:

texto alternativo

Ainda assim, não tem nenhuma utilidade para o desenvolvedor, já que para o Visual Studio eles são apenas arquivos de texto sem sentido. Portanto, o arquivo em lote copy_default_config.bat,, se encarrega de criar um conjunto inicial de arquivos .config a partir dos arquivos .config.default:

@echo off
@REM Makes copies of all .default files without the .default extension, only if it doesn't already exist. Does the same recursively through all child folders.
for /r %%f in (*.default) do (
    if not exist "%%~pnf" (echo Copying %%~pnf.default to %%~pnf & copy "%%f" "%%~pnf" /y)
)
echo Done.

O script pode ser reexecutado com segurança, pois os desenvolvedores que já possuem seus arquivos .config não os substituirão. Portanto, pode-se concebivelmente executar esse arquivo em lote como um evento de pré-construção. Os valores nos arquivos .default podem não ser exatamente corretos para uma nova instalação, mas são um ponto de partida razoável.

Em última análise, o que cada desenvolvedor acaba tendo é uma pasta de arquivos de configuração que se parece com isto:

texto alternativo

Pode parecer um pouco complicado, mas é definitivamente preferível ao incômodo de desenvolvedores pisando nos calos dos outros.

Gavin
fonte
Por que não ter diretamente o .config principal no repositório, mas não os individuais?
graffic de
6
Que dor, precisamos de uma solução melhor para isso. Eu tinha um método semelhante configurado e cansei dele ser tão frágil e ainda precisar de explicação para novos desenvolvedores.
jpierson de
@Gavin, recebo um erro se tento executar o arquivo bat que você descreveu: '∩╗┐ @ echo' não é reconhecido como um comando interno ou externo, programa operável ou arquivo em lote.
Austin
2
@Austin, você parece ter algum lixo não imprimível antes de '@echo', parte do qual é possível a marca de ordem de byte Unicode? Talvez algo tenha dado errado ao copiar / colar ou o arquivo em lote foi salvo em uma codificação que não pode ser lida corretamente.
Gavin
21

Em seu Web.config, use a fonte de outros arquivos

<configuration>
    <connectionStrings configSource="ConnectionStrings.config" />
...
</configuration>

Mantenha o web.config no controle de versão e não o faça para ConnectionStrings.config. Agora todos os desenvolvedores têm um arquivo para a string de conexão.

Você pode fazer isso para todas as configurações que dependem do local.

Filipe pinheiro
fonte
1
Isso funcionou bem para mim. Veja também: davidgiard.com/2012/05/25/… O arquivo ConnectionStrings.config deve estar na mesma pasta que o aplicativo ou configuração da web. Além disso, você deve alterar suas propriedades para 'copiar se mais recente' para a saída. E o arquivo ConnectionStrings.config precisa da seção completa com elementos de abertura e fechamento. Você também deve definir o controle de versão para ignorar o arquivo, de forma que cada um seja específico do usuário.
Jeffrey Roughgarden de
1
Usei a opção <appSettings file = ".."> desde que tive que mesclar as configurações
Spikolynn
1
@JeffreyRoughgarden Se você incluir o arquivo ConnectionStrings.config no Solution Explorer, o arquivo não precisa existir no filesysterm? E se isso acontecer, isso significa que você verificou no controle de origem. Qual é o problema inicial do qual estávamos tentando fugir.
Jez
20

Aqui está uma solução para arquivos web.config e Visual Studio 2010:

1) Edite manualmente o arquivo .csproj do seu aplicativo da web para adicionar um AfterBuilddestino como este:

  <Project>
   ...
    <Target Name="AfterBuild">
      <Copy SourceFiles="web.config" DestinationFiles="obj\$(Configuration)\tempweb.config" />
      <TransformXml Source="obj\$(Configuration)\tempweb.config"
                  Transform="web.$(USERNAME).config"
                  Destination="obj\$(Configuration)\tempweb2.config" />
      <ReadLinesFromFile File="obj\$(Configuration)\tempweb2.config"><Output TaskParameter="Lines" ItemName="TransformedWebConfig"/></ReadLinesFromFile>
      <ReadLinesFromFile File="web.config"><Output TaskParameter="Lines" ItemName="UnTransformedWebConfig"/></ReadLinesFromFile>
      <Copy Condition=" @(UnTransformedWebConfig) != @(TransformedWebConfig) " SourceFiles="obj\$(Configuration)\tempweb2.config" DestinationFiles="web.config" OverwriteReadOnlyFiles="True" />
    </Target>
  </Project>

Esse destino transformará o arquivo Web.config correspondente ao desenvolvedor atual conectado - daí a $(USERNAME)variável -, com o arquivo correspondente criado em 1). Ele substituirá o Web.config local apenas se o conteúdo for alterado (para evitar a reinicialização) em cada compilação, mesmo se o Web.config local for controlado por origem, é por isso que OverwriteReadOnlyFilesestá definido como True. Este ponto é de fato discutível.

2) Crie um arquivo com o nome Web.[developer windows login].configde cada desenvolvedor do projeto. (por exemplo, nas capturas de tela a seguir, tenho dois desenvolvedores chamados smo e smo2):

insira a descrição da imagem aqui

Esses arquivos (1 por desenvolvedor) podem / devem ser controlados pela fonte. Eles não devem ser marcados como dependentes do Web.config principal porque queremos verificá-los individualmente.

Cada um desse arquivo representa uma transformação a ser aplicada ao arquivo Web.Config principal. A sintaxe de transformação é descrita aqui: Web.config Sintaxe de transformação para implantação de projeto de aplicativo da web . Reutilizamos esta tarefa de transformação de arquivo Xml que vem pronta para uso com o Visual Studio. O objetivo desta tarefa é mesclar elementos e atributos Xml em vez de sobrescrever todo o arquivo.

Por exemplo, aqui está um exemplo web.[dev login].configque altera uma string de conexão chamada 'MyDB', independentemente do resto do arquivo Web.config:

<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
    <connectionStrings>
      <add name="MyDB" 
        connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True" 
        xdt:Transform="SetAttributes" xdt:Locator="Match(name)" />
    </connectionStrings>
</configuration>

Agora, esta solução não é perfeita porque:

  • após a construção, os desenvolvedores podem ter um Web.Config diferente localmente do que no sistema de controle de origem
  • eles podem ter que forçar a gravação local ao obter um novo Web.Config do sistema de controle de origem
  • os desenvolvedores não devem fazer check-out / no web.config principal. Deve ser reservado para poucas pessoas.

Mas, pelo menos, você só precisa manter um web.config principal exclusivo, mais um arquivo de transformação por desenvolvedor.

Uma abordagem semelhante poderia ser adotada para arquivos App.config (não web), mas não entrei em detalhes.

Simon Mourier
fonte
Renomeei meu Web.config para Web.base.config, criei um novo arquivo Web.config e mudei de <Copy SourceFiles = "web.config"> para <Copy SourceFiles = "web.base.config" na etapa 1. Fazendo isso, posso ter um web.config local que pode ser ignorado no controle de origem.
S. Baggy
Isso ainda não é o ideal, mas eu prefiro a outra solução
JMK
Você acha que é possível usar um web.default.configquando web.$(USERNAME).confignão existe? A propósito, obrigado por esta ótima resposta.
Christian Gollhardt
2

Estamos usando machine.config para evitar diferenças no web.config entre os ambientes.

Darin Dimitrov
fonte
14
preferiria evitar ter que alterar o machine.config
twarz01
0

Que tal ignorar o arquivo, para que nunca seja verificado? Eu encontrei um problema semelhante e adicionei web.config à lista de ignorados no Subversion.

No entanto, no TFS é um pouco mais difícil, veja este post sobre como fazer isso.

Marko
fonte
0

Uma maneira de lidar com isso é ter um sistema tokenizado e usar um script rake para alterar os valores.

Um método mais rudimentar poderia ser ter um link para um arquivo AppSettings.config para todos os AppSettings em seu web.config (semelhante com conexões), ou seja,

<appSettings configSource="_configs/AppSettings.config" />

Em seguida, tenha uma pasta com cada um de seus desenvolvedores tem uma versão em uma subpasta (ou seja, / _configs / dave /). Então, quando um desenvolvedor está trabalhando em seu próprio código, ele copia da subpasta para a raiz da pasta vinculada.

Você precisará comunicar as alterações a esses arquivos (a menos que você faça token). Se você mantiver o arquivo AppSettings.config fora do controle de origem e apenas verificar as pastas individuais do desenvolvedor (todas elas), eles serão forçados a copiar a correta.

Eu prefiro a tokenização, mas pode ser mais difícil de colocar em funcionamento se isso for apenas uma solução rápida.

ArtificialGold
fonte
0

Ignore os arquivos e tenha um Commom_Web.Config e Common_App.Config. Usando um servidor de construção de integração contínua com tarefas de construção que renomeiam esses dois para nomes normais para que o servidor de construção possa fazer seu trabalho.

Arthis
fonte
isso precisa ser feito em máquinas de desenvolvimento, antes de ir para a construção do servidor
twarz01
Não, essa renomeação deve acontecer no servidor de compilação. Arquivos de configuração comuns sendo armazenados no subversion, eles são independentes de um desenvolvedor específico. Considerando que todo desenvolvedor executa seus arquivos de configuração pessoais para desenvolver em sua máquina, e não se preocupa em enviá-los porque não faz parte da subversão.
Artigo
O que isso não suporta são os desenvolvedores que estão depurando o aplicativo. A raiz web.configna pasta de origem é usada durante a depuração. Se você, por exemplo, adicionado web.configao .gitignoree quer exigido aos usuários copiar Commom_Web.Configpara web.confige editá-lo para sua fantasia, você faz parte do caminho até lá. Mas então, quando você precisa editar algo que é o mesmo em todas as máquinas do desenvolvedor, como a system.web/compilationseção ou particular appSettingsque deve ser o mesmo em todos os lugares, esse esquema falha.
binki,
0

Temos o mesmo problema e o que estamos fazendo é

  • Verifique o web.config com os valores de testserver / production
  • O desenvolvedor vai para o Windows Explorer e altera o modo somente leitura do arquivo
  • Edite a configuração para se adequar ao seu ambiente.
  • O check-in no web.config ocorre apenas quando os valores de implantação são alterados ou qualquer entrada de configuração é adicionada ou excluída.
  • Isso precisa de uma boa quantidade de comentários para cada entrada de configuração, pois precisa ser alterado por cada dev
Joy George Kunjikkuru
fonte
1
Isso pode funcionar melhor em lojas onde o controle de origem que você usa define os campos como Somente Leitura por padrão, mas para outros que usam Subversion pode não funcionar tão bem. Poderíamos definir permissões somente leitura no repositório para evitar que ele seja confirmado, no entanto, isso precisaria ser definido em cada arquivo de configuração de cada branch.
jpierson de
Para aqueles de nós que não usam algo como o TFS, não é óbvio como essa solução poderia funcionar. Você poderia dar um pouco mais de fundo? Além disso, não exige que os desenvolvedores sejam cuidadosos e não retirem o arquivo acidentalmente?
binki,
-1

Supondo que você esteja usando o Visual Studio, por que não usa configurações de solução diferentes? Por exemplo: você pode ter uma configuração de depuração que usa Web.config.debug e uma configuração de versão que usa Web.config.release. Web.config.debug deve ter algo como

<appSettings file="C:/Standard_Path_To_Configs/Standard_Name_For_Config.config"> 

com o arquivo Standard_Name_For_Config.config que obtém todas as configurações pessoais do desenvolvedor, enquanto o Web.config.release sempre tem as configurações de produção. Você pode armazenar configurações padrão em alguma pasta de origem controlada e fazer com que um novo usuário as tire de lá.


fonte
Então, cada usuário individual que contribuiria com o projeto precisaria ter sua própria configuração de construção. Isso não parece escalar e não apóia projetos que aceitam contribuições.
binki,