O tym, że od dawna można w VS używać transformacji web|app.config pewnie każdy już wie (jeżeli nie do zapraszam do przeczytania podstaw w poście Web Deployment: Web.Config Transformation). Jak i każdy wie, że łatwo jest zmienić wartość jednej wartości z appSettings czy też ją kompletnie usunąć. Tak jak łatwo jest usunąć lub zamienić inne elementy które już istnieją.

Czy jednak kiedykolwiek, próbowaliście coś dodać? Dla przykładu, jeżeli będziecie chcieli dodać tag <section> do <configSections> ale <configSections> nie istnieje w żródłowym configu, to dostaniecie coś takiego:

No element in the source document matches '/configuration/configSections/section'

By to rozwiązać należy dodać element configSections, ale jak to zrobić?

Poniższy kod nie zadziała:

<configSections xdt:Transform="Insert">

<section …/>

</configSections>

Wciąż będziemy dostawać powyższy błąd, ba, nawet jakby się udało, to configSections wylądowało by na końcu dokumentu a nie na początku. Do tego, jeżeli już istnieje configSections to został by dodany drugi. Co też spowoduje iż nasz kod nie zadziała.

Ale najpierw uprośćmy sprawę, chcemy tylko i wyłącznie dodać ten element (najlepiej na samym początku) i sekcje w nim. By tego dokonać należy wykonać 2 kroki – tak, dwa:

<!-- 1: Insert element before anything else in configuration -->
<configSections xdt:Transform="InsertBefore(/configuration/*)" />
<!-- 2: Insert section elements to configSections -->
<configSections>
  <section name="system.identityModel"
           type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"
           xdt:Transform="Insert" />
  <section name="system.identityModel.services"
           type="System.IdentityModel.Services.Configuration.SystemIdentityModelServicesSection, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"
           xdt:Transform="Insert" />
</configSections>

Muszę stwierdzić, że dojście do tego, iż to należy rozbić na dwa kroki zajęło mi około 2h.

No dobrze, ale teraz możemy mieć problem z dwoma sekcjami configSections, tego niestety dla przykładu configSections bez dodatkowego kodu nie da się rozwiązać. W sensie, prostym rozwiązaniem jest wywołanie remove jako dodatkowej linijki:

<!-- 0: Remove configSections if element exists -->  
<configSections xdt:Transform="Remove" />

Jednak spowoduje to usunięcie już istniejących sekcji jeżeli jakieś zostały dodane.

Dla innych przypadków kiedy nie zależy nam na tym by coś było na samej górze, lub dole, możemy wykorzystać ukrytą transformację (mówię ukrytą, bo nie opisaną w dokumentacji jak to ma MS w zwyczaju) InsertIfMissing.

Dla przykładu, poniższy kod, doda element modules jeżeli on już nie istnieje, ustawi atrybut runAllManagedModulesForAllRequests na true i wstawi do niego trzy elementy:

<system.webServer>

  <modules xdt:Transform="InsertIfMissing" />
  <modules runAllManagedModulesForAllRequests="true" xdt:Transform="SetAttributes"/>
  <modules>

    <remove name="FormsAuthentication"
            xdt:Transform="Insert" />

    <add name="WSFederationAuthenticationModule"
          type="System.IdentityModel.Services.WSFederationAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
          preCondition="managedHandler" xdt:Transform="Insert" />
    <add name="SessionAuthenticationModule"
          type="System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
          preCondition="managedHandler" xdt:Transform="Insert" />

  </modules>
</system.webServer>

Transformacja configów do prostych nie należy i można łatwo się w niej pogubić, jeżeli do tego dodamy jeszcze czyszczenie wykonanej transformacji, to już chyba lepiej część rzeczy z kodu zrobić (a chyba istnieje taka możliwość). Tak czy siak, jeżeli chcecie dodać nowy elementy lub dodać jeżeli nie istnieje to już wiecie jak :) a przy małych modyfikacjach, warto jednak wykorzystać możliwość transforamcji z poziomu VS niż męczyć się z osobnymi skrytpami które to za nas zrobią.

A jak ktoś z was ma pomysł jak rozwiązać problem z <configSections> to pls dajcie znać! :)