Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting InternalsVisibleTo to work when the build process signs the assembly with strong names?

In our shop, we are using Cruise Control & MSBuild to automate the builds of the product as part of continuous integration.

Part of the build is to sign the assemblies so they have strong names.

In our project files when we develop locally, it does not specify signing, as this is overridden by the MSBuild script.

This is all well and good until I decided I would like introduce unit tests that require me to use the InternalsVisibleTo attribute. I also began using a nice open source library which has unit tests that also use this technique.

This means that, on my machine, I can update AssemblyInfo.cs to use the following statement:

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

and all is well.

However, checking this in breaks the build since the build machine signs the assemblies, that line would need to be updated to look like this instead:

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

I have half a mind to not sign the assemblies and call it a day. However, "signing assemblies is a best practice"(repeat this mantra 3 times), and if we are getting any benefit from doing this, I don't want to remote it.

We don't install to the GAC, we're not particularly concerned about tampering, don't have to worry about 3rd parties who use our libraries, we update all our files at once when we update the app. The most identifiable benefit is someone in support can't copy some random version of an assembly into the run-time folder and have things appear to work for a little while.

I don't want to open the can of works involved w/ changing around 100 project files manually to enable signing. I also don't want to hack things up by marking things which should be internal as public, I don't want to get into binding redirects & I don't want to remove the unit tests.

I'd like all of the ease of not having strong names with all of the benefits of having strong names(if there are any), and I don't want to create a lot of extra work to do it. Is that too much to ask?

This post describes the problem and a solution well, but I'm not much of a MSBuild script guy to take advantage of it:

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

What is the proper solution to this problem?

Any inputs and points of discussion are welcome.

like image 427
Wes Avatar asked Jun 25 '11 00:06

Wes


2 Answers

Use the same construct that you employ to disable signing a developer build to define a compiler symbol, eg. DO_NOT_SIGN, then, in your AssemblyInfo.cs, use this:

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

In my personal opinion it's more elegant than modifying the source code from the build script.

like image 190
skolima Avatar answered Nov 11 '22 15:11

skolima


You could patch the key information into the source files before compiling.

The following example uses the FileUpdate from the MSBuild Community Tasks and a (very crude) regex to patch key information into C# AssemblyInfo.cs files.

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

However, I think modifying the projects to always strong-name sign would be the cleaner solution for eliminating one more difference between development and deployed environments, and could be easily scripted.

like image 26
Thomas Gerstendörfer Avatar answered Nov 11 '22 16:11

Thomas Gerstendörfer