Automating Code Review Tools – FxCop – Part III
The third post in this series on Automating Code Review tools will cover FxCop. FxCop is a coding standard and introspective analysis tool that looks at code using a ruleset and analyzes things such as code design (“should this method be static, internal, etc”) and performance (“change this method to static because it never uses the ‘this’ member”).
I have added FxCop to the automation on several projects I run and found out the hard way just what Microsoft thinks of my code. Actually, there were not a lot of code errors that were show stoppers. Most of the errors came from the Microsoft.Design and Microsoft.Performance rule sets of FxCop. I also had a strong naming error on all my libraries, which I fixed with some quick public/private keypair generation tools (more on this later).
So today’s post is about automating FxCop and fixing some of the likely rule violations you are going to see in your output. You can also follow the FxCop Blog at http://blogs.msdn.com/fxcop/.
FxCop Setup and NAntContrib
The first thing to do is download and install FxCop. FxCop is only available as an executable so you have to install it first and then copy the files it puts in the installation path you specify to your project’s tools directory. This process is pretty straight forward and there are no other dependencies you have to resolve to get FxCop working from your project repository without having it installed on the development computer you are working on.
The second thing to do (if you haven’t already) is download and install NAntContrib. NAntContrib contains a lot of useful tasks that NAnt does not, including the fxcop task. In my project’s repository I have FxCop in ${root.dir}\tools\FxCop and NAntContrib in ${root.dir}\tools\NAntContrib.
NAnt Build File Setup
First you have to make the NAntContrib tasks available to your build files. I use properties to specify paths in my projects so I can reuse them in submodules of my project. For this example, we will assume you have set these up, along with the properties set below. The following should be put at the top of your build right under the project element:
<property name=”root.dir” value=”.” />
<property name=”build.dir” value=”${root.dir}\build” />
<property name=”tools.dir” value=”${root.dir}\tools” />
<property name=”tools.nantcontrib.dir” value=”${tools.dir}\NAntContrib” />
<property name=”tools.fxcop.dir” value=”${tools.dir}\fxcop” /><!– Load the NAntContrib Tasks –>
<loadtasks assembly=”${tools.nantcontrib.dir}\NAnt.Contrib.Tasks.dll” />
The Build Target
The next thing to do is define a build target that will compile your code. Before I added FxCop, here is what my build target looked like:
<target name=”build” depends=”clean,init” description=”Compiles the code into a DLL”>
<property name=”compile.dir” value=”${project::get-name()}.Source” />
<csc target=”library” output=”${build.dir}/${compile.dir}.dll” debug=”${debug.compile}”>
<sources>
<include name=”${compile.dir}/**/*.cs” />
</sources>
<references>
<!– Put necessary references here –>
</references>
</csc>
</target>
Setting Up the Environment for FxCop
Since we have loaded NAntContrib, the fxcop task is available to us, but we first have to do some setup. The fxcop task assumes that the FxCop executable (FxCopCmd.exe) is available from somewhere in your PATH environment variable. Since we removed it from Program Files, this is no longer true and we need to add the path to the FxCop directory to our PATH environment variable. We don’t want this to be permanent however since we don’t really want to mess with the environment any more than is necessary for our build to run. The following code should be placed under the properties and loadtask stuff we put in our build file earlier:
<!– FxCop PATH Resolution –>
<if test=”${not property::exists(’setFxCopPath’)}”>
<setenv name=”PATH” value=”${environment::get-variable(‘PATH’)};${tools.fxcop.dir}” />
<property name=”setFxCopPath” value=”true” />
</if>
You don’t actually need the if statement when using only one build file. I put this in a global properties file that is loaded in each build file. However, I do not want the PATH variable to be inundated with the fxcop directory so I test to see if I’ve already loaded it or not.
Adding FxCop to Your Build File
The next stop of course is to actually run FxCop on your assemblies and see what happens. So, without further ado, here is the target:
<target name=”fxcop” depends=”build” description=”Runs the FxCop tool over the set of libraries”>
<fxcop>
<targets>
<include name=”${build.dir}\*.dll” />
</targets>
<arg value=”/out:${reports.dir}\fxcop.xml” /> <!– Change the directory where the output is saved –>
<arg value=”/directory:${lib.entlib.dir}” /> <!– Look in the entlib directory for supporting libraries used in the project –>
<!– <arg value=”/rid:-Microsoft.Design#CA2210″ /> – Example of ignoring a specific rule – Ignore the Strong Naming Rule –>
<arg value=”/fo” /> <!– Force output even if there are no violatons –>
</fxcop>
</target>
This target is running FxCop on the specified libaries in the build directory. It saves the output file to a specific location (which our CI server can save as an artifact). It also looks in a directory where other used libaries are located (in the case that they aren’t all in your build directory). Finally, I added a flag to force output even when there are no violations (/fo). This ensures a report artifact is generated without using a bunch of if statements in my CI’s NAnt file.
Another nice thing about FxCop that does not occur with CAT.NET is that it will fail the build automatically when it finds violations. When violations are found the return code from the command line utility is greater than 0 and NAnt will automatically fail the build unless you specify failonerror=”false”. Therefore, you don’t need a lot of extra build file code to check for errors with this utility.
Common Errors – Assembly Not Strongly Named
The first error I ran into was the strong naming error (rule Microsoft.Design#CA2210). Basically, Microsoft likes all of their assemblies to be strongly named (cryptographically signed with a private key). To get around this, we need to sign our assemblies. Finding information on how to do this can be a little tricky, but the jist of it is:
- Open a Visual Studio 2005/2008 Command Prompt from the Start Menu (Start->Programs->Microsoft Visual Studio 2008->Visual Studio Tools->Visual Studio Command Prompt)
- Change to your project directory (cd C:\Dev\Project1)
- Run the command to generate a keyfile (sn.exe -k Project1.snk)
- You can also seperate the public/private key in the case where your private key is only available to a small group of people and others use the public key by running: sn -p Project1.snk PublicProject1.snk
- Define a property in your project specifying the path to the keyfile (<property name=”assembly.keyfile” value=”${root.dir}\Project1.snk” />)
- On your csc tasks add the following attribute: keyfile=”${assembly.keyfile}”
That’s it. Your assemblies will now be strongly named, and the violation will go away in FxCop. Obviously you may want to take this a step further and delay sign them and keep your private key available only in a secured location where deployment occurs.
Common Errors – Assembly Information Missing
The next error also deals with assembly attributes. When you define a new project in Visual Studio, it automatically adds an AssemblyInfo.cs file which contains things like the assembly title, description, copyright, keyfile, and more. there are a whole list of Assembly<Something>Attribute decorators you can use in your assembly. I have created a target that is called in all my compile targets right before I run csc that generates an AssemblyInfo.cs file for each project. The nice thing is that this lends itself to automating your versioning (another article) if you so choose. The target and an example of how I use it is below:
<target name=”GenerateAssemblyFile” description=”Generates an AssemblyInfo.cs File for inclusion in the compile methods”>
<asminfo output=”${compile.dir}\AssemblyInfo.cs” language=”CSharp”>
<imports>
<import namespace=”System” />
<import namespace=”System.Reflection” />
<import namespace=”System.EnterpriseServices” />
<import namespace=”System.Runtime.InteropServices” />
</imports>
<attributes>
<attribute type=”ComVisibleAttribute” value=”false” />
<attribute type=”CLSCompliantAttribute” value=”true” />
<attribute type=”AssemblyVersionAttribute” value=”${assembly.version}” />
<attribute type=”AssemblyTitleAttribute” value=”${assembly.title}” />
<attribute type=”AssemblyDescriptionAttribute” value=”${assembly.description}” />
<attribute type=”AssemblyCopyrightAttribute” value=”${assembly.copyright}” />
<attribute type=”ApplicationNameAttribute” value=”${assembly.name}” />
</attributes>
<references>
<include name=”System.EnterpriseServices.dll” />
</references>
</asminfo>
</target>
And the compile target that calls it:
<target name=”compile.models” depends=”init”>
<property name=”compile.dir” value=”${project::get-name()}.Models” />
<property name=”assembly.title” value=”Models Library” />
<property name=”assembly.description” value=”Models Library for the MVC framework” />
<property name=”assembly.name” value=”${project::get-name()}.Models” />
<call target=”GenerateAssemblyFile” /><csc target=”library” output=”${build.dir}/${compile.dir}.dll” debug=”${debug.compile}” keyfile=”${assembly.keyfile}”>
<sources>
<include name=”${compile.dir}/**/*.cs” />
</sources>
<references>
<include name=”${build.base.dir}/.Services.Proxy.dll” />
</references>
</csc>
</target>
The target creates a bunch of properties to use in the GenerateAssemblyInfo target and then calls the genertion target. ${assembly.version} can be predefined, or you can use the NAntContrib ‘version’ task to automate the version number information.
Conclusion
FxCop is a great tool to help your team stick to recognized framework coding standards that include design time, performance, and security issues. It still does not replace a human code review and it should only be used to augment your code review processes.




