我正在減少大型C#/ ASP.NET解決方案的編譯時間。我們的解決方案使用通常的resx文件方法被翻譯成十幾種外語。這些資源文件的解析和編譯大大減慢了我們的編譯時間,並且每天都受挫。如何通過覆蓋MSBuild目標來防止外語資源的生成?
我知道有可能創建自定義資源提供程序並遠離.resx文件。現在,請假設我們必須堅持使用.resx文件。
通過從我們的.csproj文件中排除除默認語言環境.resx文件以外的所有文件,我可以將編譯時間減半。我們的開發人員在日常開發過程中不需要編譯其他十幾種語言。
我正在尋找方法來防止編譯外語.resx文件。我提出了兩種方法,並且正在尋求一種優越性的建議,還是有其他更好的方法。
兩個我已經想出了:
- 寫腳本,可以去掉,並在各種.csproj的文件添加回在非缺省的.resx文件。也許我們會將最小化的.csproj文件保存在版本控制中,並且有一個單獨的構建過程用於遞歸重新添加.resx文件,以便重新整合新的翻譯,執行測試並執行我們的部署構建。
- 想象一種方法來覆蓋執行resx解析和編譯的內置MSBuild目標,除了缺省語言之外,它們都可以有效地禁用它們。開發人員可以使用簡單的編譯標誌或編譯開關啓用/禁用此行爲。我還沒有深入研究微軟提供的.target文件,看看這個解決方案實際上有多合理或可維護。
更新
我寫了下面PowerShell腳本將我的所有外國語言EmbeddedResources和編譯元素融入其中有一個條件屬性的新的ItemGroup。
$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
ItemGroup上的條件屬性看起來更乾淨。但總的來說,我同意 - 我寧願在msbuild內部進行黑客攻擊,而不是包括 - 通過外部腳本排除文件 –
太棒了!我想知道這種技術的設置和維護。在設置上,我想我需要手動編輯csproj文件並將所有非默認區域設置資源推送到Choose結構中,對嗎?可以很容易地編寫腳本。當新的頁面和控件被添加到解決方案時,Visual Studio將在這個新的Choose結構之外創建其通常的默認語言環境資源,其餘的默認語言環境資源駐留在該結構中。那麼我想這就是我們如何將新翻譯整合回csproj文件的問題。這是有希望的。 –
恐怕,安裝很可能是手動步驟。如果您的翻譯公司使用SDL Passolo或Alchemy Catalyst等工具,獲取新資源並不會造成問題。 – Jenszcz