Pliki app.config / web.config specyficzne dla deweloperów w programie Visual Studio

93

Mamy kilka projektów .NET, w których przechowujemy określone ustawienia w plikach konfiguracyjnych.

Teraz każdy deweloper będzie miał własne pliki konfiguracyjne, które nieco się różnią (różne parametry połączenia do łączenia się z lokalnymi bazami danych, różne punkty końcowe WCF itp.)

W tej chwili mamy tendencję do sprawdzania plików app / web.config i modyfikowania ich zgodnie z naszymi potrzebami.

Prowadzi to do wielu problemów, ponieważ od czasu do czasu ktoś będzie sprawdzał własne ustawienia lub tracił konfigurację niestandardową podczas pobierania najnowszej wersji z TFS .

Jak radzisz sobie w takich sytuacjach? A może w ogóle nie masz tego problemu?

twarz01
źródło
10
Głosuję za ponownym otwarciem, ponieważ jest to częsty problem dla programistów Visual Studio i bezpośrednio dotyczy narzędzi, z których korzystają programiści. (stąd głosy)
Christian Gollhardt
Zgadzam się, jest to trwały problem, ponieważ wielkość naszego zespołu wzrosła, a różne próby rozwiązania były niezadowalające.
DiskJunky

Odpowiedzi:

66

Używamy systemu, który łączy kilka istniejących odpowiedzi na tej stronie, a także opiera się na sugestii Scotta Hanselmana .

Krótko mówiąc, mieliśmy wspólny plik app.config / web.config i większość określonych ustawień w poszczególnych plikach, zgodnie z sugestiami innych odpowiedzi tutaj. np. dla naszych ustawień SMTP plik app.config zawiera

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

Ten plik znajduje się w kontroli źródła. Jednak poszczególne pliki, takie jak ten, nie są:

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

Jednak to nie koniec historii. A co z nowymi programistami lub nową instalacją źródłową? Większość konfiguracji nie znajduje się już w kontroli źródła, a ręczne tworzenie wszystkich potrzebnych plików .config jest uciążliwe. Wolę mieć źródło, które przynajmniej będzie się kompilować zaraz po wyjęciu z pudełka.

Dlatego przechowujemy wersję plików .config w kontroli źródła o nazwie pliki .config.default . Dlatego świeże drzewo źródłowe wygląda następująco:

tekst alternatywny

Mimo to programista nie ma z tego żadnego pożytku, ponieważ dla programu Visual Studio są to tylko bezsensowne pliki tekstowe. Dlatego plik wsadowy copy_default_config.batdba o utworzenie początkowego zestawu plików .config z plików .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.

Skrypt można bezpiecznie ponownie uruchomić, ponieważ programiści, którzy mają już swoje pliki .config, nie będą ich nadpisywać. Dlatego można sobie wyobrazić uruchomienie tego pliku wsadowego jako zdarzenia przed kompilacją. Wartości w plikach .default mogą nie być dokładnie poprawne dla nowej instalacji, ale są rozsądnym punktem wyjścia.

Ostatecznie to, co kończy każdy programista, to folder plików konfiguracyjnych, który wygląda mniej więcej tak:

tekst alternatywny

Może się to wydawać trochę zawiłe, ale zdecydowanie lepiej niż kłopoty programistów nadeptywających sobie nawzajem.

Gavin
źródło
Dlaczego nie mieć bezpośrednio głównego pliku .config w repozytorium, ale nie indywidualnych?
graffic
6
Co za ból, potrzebujemy lepszego rozwiązania. Skonfigurowałem podobną metodę i zmęczyło mnie to, że jest tak delikatna i wciąż wymaga wyjaśnienia nowym programistom.
jpierson
@Gavin, pojawia się błąd, jeśli próbuję uruchomić opisany przez Ciebie plik bat: „∩╗┐ @ echo” nie jest rozpoznawane jako polecenie wewnętrzne lub zewnętrzne, program operacyjny lub plik wsadowy.
Austin
2
@Austin, wydaje się, że masz jakieś niedrukowalne śmieci przed „@echo”, którego częścią jest możliwy znak kolejności bajtów Unicode? Może coś poszło nie tak podczas kopiowania / wklejania lub plik wsadowy jest zapisany w kodowaniu, którego nie można poprawnie odczytać.
Gavin,
21

W swoim pliku Web.config użyj źródła z innych plików

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

Zachowaj plik web.config w kontroli wersji i nie rób tego dla ConnectionStrings.config. Teraz wszyscy programiści mają jeden plik dla parametrów połączenia.

Możesz to zrobić dla wszystkich ustawień zależnych od lokalnego.

Filipe Pinheiro
źródło
1
U mnie to zadziałało. Zobacz też: davidgiard.com/2012/05/25/… Plik ConnectionStrings.config musi znajdować się w tym samym folderze, co aplikacja lub konfiguracja sieciowa. Ponadto, aby wydrukować, należy zmienić jego właściwości na „kopiuj, jeśli nowszy”. A plik ConnectionStrings.config wymaga pełnej sekcji z elementami otwierającymi i zamykającymi. Musisz także ustawić kontrolę wersji, aby ignorować plik, aby każdy był specyficzny dla użytkownika.
Jeffrey Roughgarden
1
Użyłem opcji <appSettings file = "..">, ponieważ musiałem scalić ustawienia
Spikolynn
1
@JeffreyRoughgarden Jeśli dołączasz plik ConnectionStrings.config w Eksploratorze rozwiązań, czy plik ten nie musi istnieć w magazynie plików? A jeśli tak, oznacza to, że sprawdziłeś go w kontroli źródła. To jest pierwszy problem, od którego próbowaliśmy uciec.
Jez
20

Oto rozwiązanie dla plików web.config i programu Visual Studio 2010:

1) Edytuj ręcznie plik .csproj aplikacji internetowej, aby dodać obiekt AfterBuilddocelowy w następujący sposób:

  <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>

Ten cel przekształci plik Web.config odpowiadający aktualnie zalogowanemu deweloperowi - stąd $(USERNAME)zmienna - z odpowiednim plikiem utworzonym w 1). Zastąpi lokalny plik Web.config tylko wtedy, gdy zawartość ulegnie zmianie (aby uniknąć ponownego uruchomienia) przy każdej kompilacji, nawet jeśli lokalny plik Web.config jest kontrolowany pod kątem źródła, dlatego istnieje OverwriteReadOnlyFiles jest ustawiony na True. W rzeczywistości ten punkt jest dyskusyjny.

2) Utwórz plik nazwany Web.[developer windows login].configdla każdego programisty w projekcie. (na przykład na poniższych zrzutach ekranu mam dwóch programistów o nazwach smo i smo2):

wprowadź opis obrazu tutaj

Te pliki (1 na programistę) mogą / powinny być kontrolowane pod kątem źródła. Nie należy ich oznaczać jako zależnych od głównego pliku Web.config, ponieważ chcemy mieć możliwość sprawdzenia ich indywidualnie.

Każdy z tych plików reprezentuje transformację do zastosowania w głównym pliku Web.Config. Składnia transformacji została opisana tutaj: Składnia transformacji Web.config dla wdrażania projektu aplikacji sieci Web . Używamy ponownie tego fajnego zadania transformacji pliku Xml, które jest dostarczane z programem Visual Studio. Celem tego zadania jest scalanie elementów i atrybutów Xml zamiast nadpisywania całego pliku.

Na przykład, oto przykład, web.[dev login].configktóry zmienia ciąg połączenia o nazwie „MyDB”, niezależnie od pozostałej części pliku 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>

Teraz to rozwiązanie nie jest idealne, ponieważ:

  • po zbudowaniu programiści mogą mieć lokalnie inną Web.Config niż w systemie kontroli wersji
  • mogą być zmuszeni do wymuszenia lokalnego zapisu podczas pobierania nowego Web.Config z systemu kontroli źródła
  • programiści nie powinni sprawdzać / w głównym pliku web.config. Powinien być zarezerwowany dla kilku osób.

Ale przynajmniej musisz utrzymywać tylko unikalny główny plik web.config oraz jeden plik transformacji na programistę.

Podobne podejście można zastosować w przypadku plików App.config (nie internetowych), ale nie rozwiązywałem tego dalej.

Simon Mourier
źródło
Zmieniłem nazwę mojego Web.config na Web.base.config, utworzyłem nowy plik Web.config, a następnie w kroku 1 zmieniłem z <Copy SourceFiles = "web.config"> na <Copy SourceFiles = "web.base.config". Robiąc to, mogę mieć lokalny plik web.config, który można zignorować w kontroli źródła.
S. Baggy,
To nadal nie jest idealne, ale wolę to od innego rozwiązania
JMK
Czy myślisz, że można użyć web.default.configkiedy web.$(USERNAME).confignie istnieje? Dziękuję za tę wspaniałą odpowiedź.
Christian Gollhardt,
2

Używamy machine.config, aby uniknąć różnic w pliku web.config między środowiskami.

Darin Dimitrov
źródło
14
wolałabym uniknąć konieczności zmiany machine.config
twarz01
0

Co powiesz na zignorowanie pliku, aby nigdy nie został wpisany? Napotkałem podobny problem i dodałem plik web.config do listy ignorowanych w Subversion.

Jednak w TFS jest to trochę trudniejsze, zobacz ten post, jak to zrobić.

Marko
źródło
0

Jednym ze sposobów, w jaki możesz sobie poradzić, jest posiadanie systemu tokenizowanego i użycie skryptu rake do zmiany wartości.

Bardziej podstawową metodą może być utworzenie łącza do pliku AppSettings.config dla wszystkich ustawień AppSettings w pliku web.config (podobnie jak w przypadku połączeń), tj.

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

Następnie niech folder, w którym każdy z twoich programistów będzie miał wersję w podfolderze (np. / _Configs / dave /). Następnie, gdy programista pracuje nad własnym kodem, kopiuje go z podkatalogu do katalogu głównego połączonego folderu.

Musisz upewnić się, że przekazujesz zmiany w tych plikach (chyba że tokenizujesz). Jeśli utrzymasz plik AppSettings.config poza kontrolą źródła i sprawdzisz tylko poszczególne foldery programistów (wszystkie), będą zmuszeni skopiować poprawny.

Wolę tokenizację, ale może być trudniej zacząć działać, jeśli ma to być tylko szybka naprawa.

ArtificialGold
źródło
0

Zignoruj ​​pliki i miej Commom_Web.Config i Common_App.Config. Używanie serwera budowania z ciągłą integracją z zadaniami budowania, które zmieniają nazwy tych dwóch na zwykłe, tak aby serwer budowania mógł wykonać swoje zadanie.

Arthis
źródło
należy to zrobić na maszynach dev, zanim przejdzie do budowy serwera
twarz01
Nie, zmiana nazwy powinna nastąpić na serwerze kompilacji. Typowe pliki konfiguracyjne przechowywane w subversion są niezależne od konkretnego programisty. Podczas gdy każdy programista uruchamia swoje osobiste pliki konfiguracyjne, aby rozwijać się na swoim komputerze i nie dba o to, aby je przesłać, ponieważ nie jest to część subversion.
Arthis,
To, czego nie obsługuje, to debugowanie aplikacji przez programistów. web.configPodczas debugowania używany jest katalog główny w folderze źródłowym. Jeśli, na przykład, dodane web.configdo .gitignorei albo wymagane użytkownikom kopiowanie Commom_Web.Configdo web.configi edytować go do swojej fantazji, jesteś częścią drogi tam. Ale kiedy musisz edytować coś, co jest takie samo na wszystkich komputerach programistów, na przykład system.web/compilationsekcję lub szczegół, appSettingsktóry powinien być taki sam wszędzie, ten schemat się rozpada.
binki
0

Mamy ten sam problem i to, co robimy

  • Sprawdź w pliku web.config z wartościami testerów / produkcji
  • Programista przechodzi do eksploratora Windows i zmienia tryb tylko do odczytu pliku
  • Edytuj konfigurację, aby dopasować ją do ich środowiska.
  • Zaewidencjonowanie pliku web.config ma miejsce tylko wtedy, gdy wartości wdrożenia ulegną zmianie lub jakikolwiek wpis konfiguracji zostanie dodany lub usunięty.
  • Wymaga to dużej ilości komentarzy dla każdego wpisu konfiguracji, ponieważ musi być zmieniany przez każdego programistę
Joy George Kunjikkuru
źródło
1
Może to działać lepiej w sklepach, w których kontrola źródła, której używasz, ustawia pola jako domyślne tylko do odczytu, ale dla innych używających Subversion może to nie działać tak dobrze. Moglibyśmy ustawić uprawnienia tylko do odczytu w repozytorium, aby zapobiec jego zatwierdzeniu, jednak musiałoby to być ustawione w każdym pliku konfiguracyjnym dla każdej gałęzi.
jpierson
Dla tych z nas, którzy nie używają czegoś takiego jak TFS, nie jest oczywiste, jak to rozwiązanie może działać. Czy mógłbyś podać trochę więcej informacji? Ponadto, czy nie wymaga od programistów ostrożności i przypadkowego pobrania pliku?
binki
-1

Zakładając, że korzystasz z programu Visual Studio, dlaczego nie używasz różnych konfiguracji rozwiązań? Na przykład: możesz mieć konfigurację debugowania, która używa Web.config.debug i konfigurację wydania, która używa Web.config.release. Web.config.debug powinien mieć coś takiego jak

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

z plikiem Standard_Name_For_Config.config, który zawiera wszystkie osobiste ustawienia programisty, podczas gdy plik Web.config.release zawsze ma ustawienia produkcyjne. Możesz przechowywać domyślne konfiguracje w jakimś folderze kontrolowanym przez źródła i sprawić, by nowy użytkownik je stamtąd wziął.


źródło
Wtedy każdy pojedynczy użytkownik, który kiedykolwiek wniósłby wkład w projekt, musiałby mieć własną konfigurację kompilacji. To nie wydaje się mieć skali i nie wspiera projektów, które przyjmują wkłady.
binki