2015-09-01 15 views
5

Sto lavorando alla riduzione del tempo di compilazione per una soluzione C#/ASP.NET di grandi dimensioni. La nostra soluzione è tradotta in circa una dozzina di lingue straniere usando il solito metodo del file resx. L'analisi e la compilazione di questi file di risorse rallenta notevolmente il nostro tempo di compilazione ed è una frustrazione quotidiana.Come impedire la generazione di risorse in lingua straniera sostituendo gli obiettivi di MSBuild?

Sono consapevole del fatto che è possibile creare provider di risorse personalizzate e allontanarsi dai file .resx. Per ora, per favore supponiamo che dobbiamo rimanere con i file .resx.

Escludendo tutti i file .resx delle impostazioni internazionali predefinite dai file .csproj, sono in grado di dimezzare il tempo di compilazione. I nostri sviluppatori non hanno bisogno di compilare una dozzina di altre lingue durante lo sviluppo quotidiano.

Sto cercando modi per impedire la compilazione dei file .resx in lingua straniera. Ho messo a punto due metodi e sto cercando consigli su se uno è superiore o se ci sono altri metodi migliori.

I due mi è venuta in mente:

  • script scrivono che possono mettere a nudo fuori e aggiungere di nuovo nei file RESX non predefiniti nei vari file Csproj. Forse manterremo i file .csproj minimi nel controllo di versione e avremo un processo di compilazione separato per aggiungere nuovamente file .resx in modo ricorsivo, al fine di reintegrare nuove traduzioni, eseguire test e realizzare i build di implementazione.
  • Figura un modo per ignorare le destinazioni MSBuild incorporate che eseguono analisi e compilazione resx, disabilitandole in modo efficace per tutti tranne la lingua predefinita. Gli sviluppatori potrebbero abilitare/disabilitare questo comportamento con un semplice flag di compilazione o switch di compilazione. Non ho ancora approfondito i file .target forniti da Microsoft per vedere quanto questa soluzione sia ragionevole o gestibile.

Aggiornamento

ho scritto il seguente script PowerShell per spostare tutti i miei EmbeddedResources lingua straniera e compila gli elementi in un nuovo ItemGroup, che ha un attributo condizionale.

$root = "C:\Code\solution_root\" 

# Find all csproj files. 
$projects = Get-ChildItem -Path $root -Recurse -ErrorAction SilentlyContinue -Filter *.csproj | Where-Object { $_.Extension -eq '.csproj' } 

# Use a hashtable to gather a unique list of suffixes we moved for sanity checking - make sure we didn't 
# relocate anything we didn't intend to. This is how I caught I was moving javascript files I didn't intend to. 
$suffixes = @{} 

# Find foreign resources ending in .resx and .Designer.cs 
# Use a regex capture to so we can count uniques. 
$pattern = "\.(?<locale>\w{2}(-\w{2,3})?\.(Designer.cs|resx))$" 

foreach ($project in $projects) 
{ 
    "Processing {0}" -f $project.FullName 

    # Load the csproj file as XML 
    $xmlDoc = new-object XML 
    $xmlDoc.Load($project.FullName) 

    # Set namespace for XPath queries 
    $ns = New-Object System.Xml.XmlNamespaceManager($xmlDoc.NameTable) 
    $ns.AddNamespace("ns", $xmlDoc.DocumentElement.NamespaceURI) 

    $count = 0 

    $embeds = $xmlDoc.SelectNodes("//ns:EmbeddedResource",$ns) 
    $compiles = $xmlDoc.SelectNodes("//ns:Compile",$ns) 

    # Create new conditional ItemGroup node if it does not exist. 
    # Side-effect - every csproj will get this new element regardless of whether it 
    # contains foreign resources. That works for us, might not for you. 
    $moveToNode = $xmlDoc.SelectSingleNode("//ns:ItemGroup[@Condition=`" '`$(Configuration)'=='Release' `"]", $ns) 
    if ($moveToNode -eq $null) { 
     # When creating new elements, pass in the NamespaceURI from the parent node. 
     # If we don't do this, elements will get a blank namespace like xmlns="", and this will break compilation. 
     # Hat tip to https://stackoverflow.com/questions/135000/how-to-prevent-blank-xmlns-attributes-in-output-from-nets-xmldocument 

     $conditionAtt = $xmlDoc.CreateAttribute("Condition") 
     $conditionAtt.Value = " '`$(Configuration)'=='Release' " 
     $moveToNode = $xmlDoc.CreateElement("ItemGroup", $xmlDoc.Project.NamespaceURI) 
     $ignore = $moveToNode.Attributes.Append($conditionAtt) 
     $ignore = $xmlDoc.LastChild.AppendChild($moveToNode) 
    } 

    # Loop over the EmbeddedResource and Compile elements. 
    foreach ($resource in ($embeds += $compiles)) { 

     # Exclude javascript files which I found in our Web project. 
     # These look like *.js.resx or *.js.Designer.cs and were getting picked up by my regex. 
     # Yeah, I could make a better regex, but I'd like to see my kids today. 
     if ($resource.Include -notmatch "js\.(Designer.cs|resx)$" -and $resource.Include -match $pattern) { 

      # We have a foreign-language resource. 

      # Track unique suffixes for reporting later. 
      $suffix = $matches['locale'] 
      if (!$suffixes.ContainsKey($suffix)) { 
       $ignore = $suffixes.Add($suffix,"") 
      } 

      $ignore = $moveToNode.InsertBefore($resource, $null) 

      # Count how many we moved per project. 
      $count += 1 
     } 
    } 
    "Moved {0} resources in {1}.`n" -f $count, $project.Name 
    $xmlDoc.Save($project.FullName) 
} 
echo "The following unique suffixes were processed." 
$suffixes.Keys | sort 

risposta

2

Si potrebbe fare uso dei meccanismi esistenti in MSBuild che permettono di gestire questo scenario, come il <Choose> elemento documentated here e la possibilità di introdurre le proprie configurazioni di compilazione. Se i tuoi sviluppatori costruiscono configurazioni di debug solo durante il loro lavoro quotidiano, potresti non aver nemmeno bisogno della tua configurazione di build: puoi impostare il tuo progetto in modo che tutte le risorse di lingua straniera siano incluse solo nelle build di Release.

Questo progetto sezione del file potrebbe fare in modo che le risorse polacchi sono costruite solo nella configurazione di rilascio (i codici di lingua sono probabilmente sbagliato, ma si ottiene l'idea):

<Choose> 
    <When Condition=" '$(Configuration)'=='Release' "> 
    <ItemGroup> 
    <EmbeddedResource Include="Properties\Resources.pl.resx"> 
     <Generator>ResXFileCodeGenerator</Generator> 
     <LastGenOutput>Resources.pl.Designer.cs</LastGenOutput> 
     <SubType>Designer</SubType> 
    </EmbeddedResource> 
    <Compile Include="Properties\Resources.pl.Designer.cs"> 
     <DependentUpon>Resources.pl.resx</DependentUpon> 
     <AutoGen>True</AutoGen> 
    </Compile> 

    <!-- TODO: add other language resources as necessary--> 

    </ItemGroup> 
    </When> 
</Choose> 

Nel caso in cui gli sviluppatori hanno bisogno di costruire Rilasciare le configurazioni è possibile creare la propria configurazione ReleaseResx e includere i file .resx in lingua straniera solo in quella configurazione.

Entrambi i suggerimenti potrebbero funzionare, anche io penso che questo approccio sia più pulito.

+0

L'attributo condizione su ItemGroup sembra più pulito.Ma in generale sono d'accordo: preferirei hackerare all'interno di msbuild piuttosto che includere, escludendo i file dallo script esterno –

+0

Great! Mi sto chiedendo l'installazione e il mantenimento di questa tecnica. Durante l'installazione, immagino che avrò bisogno di modificare manualmente i file csproj e spingere tutte le risorse locali non predefinite nella struttura Scegli, giusto? Probabilmente lo script abbastanza facilmente. Man mano che nuove pagine e controlli vengono aggiunti alla soluzione, Visual Studio creerà le sue solite risorse locali predefinite all'esterno di questa nuova struttura Scegli dove risiedono il resto delle risorse locali predefinite. Quindi suppongo sia tutta una questione di come andiamo a integrare nuove traduzioni nei file csproj. Questo è promettente. –

+0

L'installazione è molto probabilmente un passaggio manuale, temo. Ottenere nuove risorse nelle traduzioni non è un problema se le agenzie di traduzione utilizzano strumenti come SDL Passolo o Alchemy Catalyst. – Jenszcz