Ссылки на проект VS нарушены по чувствительности к регистру GUID
Начиная с обновления до VS 2015, моя команда испытала случайные причудливые вещи, которые, я уверен, сейчас разрабатываются в Microsoft. Один довольно раздражает то, что мы, похоже, теряем ссылки на проекты, особенно после ветвления. Вчера я начал работать над новой ветвью нашего решения, только чтобы выяснить, что типы были не распознаны, а использование пространства имен цитировалось как ненужное (потому что они были для типов, которые внезапно стали нераспознанными).
Ссылки в проекте не показывали никаких значков, указывающих на проблему со ссылкой, но просто чтобы посмотреть, сработает ли она, я удалил и повторно добавил ссылку на проект, что привело к тому, что его типы были снова распознаны.
Это, конечно, обновило файл проекта, поэтому я посмотрел, какие изменения были внесены. Единственная разница между проектом, который не смог обнаружить ссылку, и тем, который теперь может, состоит в том, что буквенные символы в GUID были изменены с нижнего регистра на верхний. Например:
Старая, неработающая ссылка:
<ProjectReference Include="path/redacted">
<Project>{95d34b2e-2ceb-499e-ab9e-b644b0af710d}</Project>
<Name>Project.Name.Redacted</Name>
</ProjectReference>
Новая фиксированная ссылка:
<ProjectReference Include="path/redacted">
<Project>{95D34B2E-2CEB-499E-AB9E-B644B0AF710D}</Project>
<Name>Project.Name.Redacted</Name>
</ProjectReference>
Я ищу причину, по которой это происходит, и то, как я мог бы это исправить, без необходимости вручную удалять и повторно добавлять ссылки повсеместно (и без необходимости преобразовывать все GUID файла проекта в верхний регистр).
Я должен отметить, что эти "неработающие" ссылки не нарушают сборку и что они отображаются только в списке ошибок как ошибка IntelliSense, а не как ошибки сборки. Таким образом, ссылки на самом деле не сломаны, они просто сломали IntelliSense (что, возможно, еще хуже?!).
3 ответа
TL; DR
Visual Studio не совсем согласна с тем, как она назначает идентификаторы GUID для проектов или как она определяет эти идентификаторы GUID в ссылках на проекты. Я смог решить проблему, используя прописные буквы GUID с фигурными скобками для ProjectGuid
элементы и нижний регистр с фигурными скобками для Project
элементы (в ссылках).
Фон
У нас есть большое решение (более 60 проектов на C#), и у нас были постоянные проблемы с решением Перестроить, так как неправильный порядок сборки может привести к невозможности разрешения ссылочных проектов, которые еще не были собраны (но должны были быть). Зависимости сборки и порядок сборки оказались правильными. Пакетная сборка MSBuild работала нормально, это была проблема только при восстановлении из Visual Studio.
Преобразование всех GUID проекта в верхний регистр с фигурными скобками и все ссылки на GUID проекта в нижний регистр с фигурными скобками решило проблему. Обычно Visual Studio генерирует эти GUID, но не всегда.
Проводя некоторые исследования в новом тестовом решении, выясняется, что:
- Сгенерированные GUID для проектов консольных приложений пишутся в верхнем регистре с фигурными скобками.
- Сгенерированные идентификаторы GUID для проектов библиотек классов изначально строчные, без скобок.
- Если добавлена новая ссылка на проект проекта библиотеки классов с GUID в нижнем регистре, то не только добавляется GUID ссылки, но GUID проекта преобразуется в верхний регистр с фигурными скобками.
- Если создается копия проекта библиотеки классов, а затем добавляется в решение, ее GUID заменяется новым, в котором используются верхний регистр и фигурные скобки. (Но если копия сделана и ее GUID удален вручную, Visual Studio не вставит заменяющий GUID в файл.csproj.)
- Ссылки на проекты GUID обычно используют строчные и фигурные скобки, но каким-то образом наш проект накопил кучу ссылок на GUID в верхнем регистре.
- GUID в.sln всегда используют верхний регистр и фигурные скобки.
Я смог исправить нашу неработающую перестройку, заменив эталонные GUID либо прописными буквами, либо прописными буквами - это что-то вроде сочетания прописных и строчных букв, которые вызывали проблемы в Visual Studio (возможно, чувствительные к регистру строковые ключи в словаре где-то?) Поскольку Visual Studio обычно добавляет ссылки с прописными буквами GUID, я выбрал именно эту опцию.
Поиск и замена регулярных выражений
Чтобы исправить это, я использовал поиск и замену в файлах на основе регулярных выражений в Notepad++, чтобы все ProjectGuids в файлах.csproj были в верхнем регистре с фигурными скобками (по умолчанию для консольных приложений, и стиль Visual Studio будет применяться после добавления любой ссылки на проект к проект):
Find what: (<ProjectGuid>)\{?([0-9a-f-]+)\}?(</ProjectGuid>)
Replace with: \1{\U\2}\E\3
Search in: *.csproj
Обязательно включите поиск по регулярному выражению и отключите регистр совпадений. И не ищите все файлы, или вы можете вносить изменения, которые вам не нужны, например, в файлы *.xproj, как отмечает @AspNyc. (См. Этот ответ для дополнительной информации об использовании регулярных выражений для изменения регистра.)
Затем я заменил все ссылки на проекты, чтобы использовать строчные буквы с фигурными скобками (что обычно делает Visual Studio):
Find what: (<Project>)\{?([0-9a-f-]+)\}?(</Project>)
Replace with: \1{\L\2}\E\3
Search in: *.csproj
После внесения этих изменений перестройка решения Visual Studio теперь работает надежно. (По крайней мере, до следующего раза, когда в наш проект проникнут мошеннические ссылки на GUID в верхнем регистре.)
Я столкнулся с аналогичной проблемой при обновлении VS2017 v15.7 до v15.9.
Ответ для меня был закрыть VS, очистить скрытое .vs
папку в корневом каталоге моего решения и перезапустите VS.
Кажется, есть ошибка в системе проектов. Этот powershell будет перебирать проекты и делать все ссылки прописными:
#FixGuids
get-childitem -recurse | ?{ @('.sln', '.csproj', '.vbproj') -contains $_.Extension } | %{
[regex]::Replace((gc $_.FullName), '[{(]?[0-9A-Fa-f]{8}[-]?([0-9A-Fa-f]{4}[-]?){3}[0-9A-Fa-f]{12}[)}]?', { return ([string]$args[0]).ToUpperInvariant() }) |
Out-File $_.FullName
}
Это довольно упрощенно. Если вы полагаетесь на руководства в своих проектах для чего-то иного, чем ссылки, вы можете захотеть превратить это в нечто более умное.
Чтобы использовать ответ в git hook, мне пришлось преобразовать его в синтаксис регулярного выражения sed:
sed -r "s/(<Project>\{?)([0-9A-F-]+)(\}?<\/Project>)/\1\L\2\E\3/g" sample.csproj
Может быть, кто-то найдет это полезным.
Сегодня в Visual Studio 2019 (16.2.2) я столкнулся с проблемами системы сборки, когда проекты без необходимости (и неоднократно) перестраивались всякий раз, когда я инициировал сборку своего решения.
(Ни один из обычных шагов не решил проблемы сборки, например, удаление папки ".vs" или удаление каталогов "bin" и "obj" и т. Д.).
Сначала казалось, что это связано с оболочкой символов руководств, потому что я смог решить проблему, отредактировав направляющие и сохранив проект. Однако это был отвлекающий маневр... Я невольно решил проблему, изменив временные метки всех моих файлов csproj. Система сборки казалась намного более счастливой после того, как эти временные метки были обновлены, и она остановила раздражающее поведение (постоянные попытки пересобрать проекты, которые уже были построены).
Оболочка персонажей в руководствах вообще не была проблемой. Насколько я могу судить, VS 2019 подходит как для заглавных, так и для строчных букв. Они могут даже не соответствовать исходному проекту, основываясь на моих экспериментах (например, исходный исходный проект может использовать верхний регистр, а ссылающиеся проекты могут использовать нижний регистр).
Если это кому-то будет полезно, ниже представлена оболочка PowerShell, которая позволит вам настроить время записи всех файлов csproj по пути. Это будет еще один трюк, который я использую всякий раз, когда система msbuild работает некорректно в Visual Studio.
$datenow = get-date
$files = Get-ChildItem -path "C:\Data\Workspaces\LumberTrack\" -recurse | where { $_.PSIsContainer -eq $false}
foreach ($file in $files)
{
if ($file.Extension -eq ".csproj")
{
Set-ItemProperty $file.FullName LastWriteTime $datenow
Write-Output $file.FullName
}
}
}