Как заставить InternalsVisibleTo работать, когда процесс сборки подписывает сборку строгими именами?

В нашем магазине мы используем Cruise Control и MSBuild для автоматизации сборок продукта в рамках непрерывной интеграции.

Часть сборки должна подписывать сборки, чтобы они имели строгие имена.

В наших файлах проекта, когда мы разрабатываем локально, в нем не указывается подпись, так как это отменяется сценарием MSBuild.

Это все хорошо, пока я не решил ввести модульные тесты, которые требуют от меня использования InternalsVisibleTo приписывать. Я также начал использовать хорошую библиотеку с открытым исходным кодом, в которой есть модульные тесты, которые также используют эту технику.

Это означает, что на моей машине я могу обновить AssemblyInfo.cs использовать следующее утверждение:

[assembly: InternalsVisibleTo("MyProject.Tests.UnitTests")]

и все хорошо.

Однако проверка этого прерывает сборку, так как сборочный компьютер подписывает сборки, поэтому необходимо обновить эту строку, чтобы она выглядела следующим образом:

[assembly: InternalsVisibleTo("MyProject.Tests.UnitTests, 
             PublicKey="magic key here..)"]

У меня есть полумрака, чтобы не подписывать собрания и называть это днем. Тем не менее, "подписание сборок - это лучшая практика"(повторите эту мантру 3 раза), и если мы получим какую-либо выгоду от этого, я не хочу ее удалять.

Мы не устанавливаем в GAC, нас не особо беспокоит фальсификация, нам не нужно беспокоиться о третьих сторонах, которые используют наши библиотеки, мы обновляем все наши файлы сразу, когда обновляем приложение. Наиболее заметным преимуществом является то, что кто-то из техподдержки не может скопировать случайную версию сборки в папку времени выполнения, и некоторые вещи могут работать некоторое время.

Я не хочу открывать банку с работами, изменяя около 100 файлов проекта вручную, чтобы включить подпись. Я также не хочу взламывать вещи, помечая вещи, которые должны быть внутренними, как публичные, я не хочу связываться с перенаправлениями и не хочу удалять модульные тесты.

Мне бы очень хотелось, чтобы у меня не было сильных имен со всеми преимуществами наличия сильных имен (если они есть), и я не хочу создавать для этого много дополнительной работы. Неужели я прошу так много?

Этот пост хорошо описывает проблему и ее решение, но я не очень разбираюсь в сценарии MSBuild, чтобы воспользоваться этим:

http://social.msdn.microsoft.com/forums/en-US/msbuild/thread/02df643c-956a-48bd-ac01-4a1016d91032/

Как правильно решить эту проблему?

Любые вклады и вопросы для обсуждения приветствуются.

2 ответа

Решение

Вы можете добавить информацию о ключе в исходные файлы перед компиляцией.

В следующем примере используется FileUpdate из задач сообщества MSBuild и (очень грубого) регулярного выражения для вставки ключевой информации в файлы C# AssemblyInfo.cs.

<ItemGroup>
    <AssemblyInfoFiles Include="$(MSBuildProjectDirectory)**/AssemblyInfo.cs"/>
</ItemGroup>
<FileUpdate
  Files="@(AssemblyInfoFiles)"
  Regex='(\[assembly:\s*InternalsVisibleTo\(\"[\w.]*\")(\)\])'
  ReplacementText='$1, PublicKey="$(StrongNamingPublicKey)"$2' />

Тем не менее, я думаю, что изменение проектов под всегда строгим именем было бы более чистым решением для устранения еще одного различия между средой разработки и развернутыми средами, и его можно было бы легко написать в сценарии.

Используйте ту же конструкцию, которую вы используете, чтобы отключить подпись сборки разработчика для определения символа компилятора, например. DO_NOT_SIGN, то в вашем AssemblyInfo.cs, использовать этот:

#if DO_NOT_SIGN
[assembly: InternalsVisibleTo("MyProject.Tests.UnitTests")]
#else
[assembly: InternalsVisibleTo("MyProject.Tests.UnitTests, PublicKey="magic key here..)"]
#endif

По моему личному мнению, это более элегантно, чем изменение исходного кода из скрипта сборки.