Feb 28, 2008

How To Create a WCF Custom Code Analysis Rule for Visual Studio

As most people know Visual Studio incorporates the FxCop static code analysis tool so you can perform static code analysis and check that your application follows good coding standards and doesn't contain nasty little surprises like forgetting to dispose of IDisposable objects, etc.

Recently I was doing some work with WCF and wanted to check that all methods with an OperationContract attribute had a FaultContract specified as well.  Unfortunately this isn't a rule that's part of the default code analysis rules, so I needed to create a Custom Code Analysis rule.  Unfortunately most of the samples on custom FxCop rules all seem to be based around doing spell checking or some other such frivolous checks, so hopefully this is something a little meatier for you to get into.

NOTE: The following "how to" is done with Visual Studio 2008.  Specific variations for VS2005 are shown in italics.

Also, a lot of this information was gathered from those who've gone before me.  Namely Nicole Calinoiu, James Guerts, Jason Kresowaty and others.  Many thanks to them for doing the hard yards and figuring out how things fit together.

Step 0 - We Need Something to Analyse

First, let's create a WCF project so we've got something we can run the rules against.

Create a new WCF Service Library project (.NET 3.0) - by default it will be called WcfServiceLibrary1 and will have a default service contract as shown:

    // NOTE: If you change the interface name "IService1" here, you must also update the reference to "IService1" in App.config.
[ServiceContract]
public interface IService1
{
[OperationContract]
string GetData(int value);

[OperationContract]
CompositeType GetDataUsingDataContract(CompositeType composite);

// TODO: Add your service operations here
}

As you can see the methods marked as OperationContract do not have any FaultContract attributes specified.


We're going to detect this with our custom rule because we want to make sure that the faults are explicitly declared.


Step 1 - Create a Class Library Project


Create a new class library project - we'll call it MyFxCopRules.  It can be a normal .NET 2.0 project.


Step 2 - Add References and Create a custom rule base class


You'll need to add 2 references to the MyFxCopRules project.  One for FxCopSdk.dll and one for Microsoft.Cci.dll. Both DLL's can be found in %ProgramFiles%\Microsoft Visual Studio 9.0\Team Tools\Static Analysis Tools\FxCop\


fxcop2


For FxCop to determine which classes in an assembly represent custom rules it will look for classes that implement the IIntrospectionRule interface.  When working with managed code you'll also need to implement the IManagedCodeRule interface.   Fortunately there is an abstract base class that implements these interfaces already - the BaseIntrospectionRule class.


So let's make Class1.cs a base class for all the custom rule we want to define.


Add a reference to the Microsoft.FxCop.Sdk namespace, change the name of the class to MyBaseRule and inherit from BaseIntrospectionRule as follows:

using Microsoft.FxCop.Sdk;

namespace MyFxCopRules
{
public abstract class MyBaseRule : BaseIntrospectionRule
{
}
}


[VS2005] In the using directives add Microsoft.FxCop.Sdk.Introspection


When creating a rule we need to tell the Introspection engine what the name of the rule is, the rule set it belongs to and the assembly it is declared in.  We could do this once per rule, or we can do it by adding the following constructor to our base rule class

        protected MyBaseRule(string name)
: base(name, "MyFxCopRules.Rules", typeof(MyBaseRule).Assembly)
{
}

Step 3 - Add a Folder And A Rule


Now we're going to create our rule.  Let's start by adding a folder to put all future rules in and then create a new class for our custom rule.  Add a folder to the project called "Rules" and a class called "EnsureFaultContractsAreDeclared".  It's good practice to name classes according to the rule they are validating.


You should now have a project as follows:


fxcop3


Step 4 - Define The Rule


OK! Now to the meat of it.  Let's define the rule itself.


First, we need to add references to the Microsoft.FxCop.Sdk and Microsoft.Cci namespaces.  Next we need to make our class inherit from the base class we defined earlier and pass the name of our rule to the base class constructor so that FxCop knows what our rule is called.  It's easy enough to do and you code should look like this:

using Microsoft.FxCop.Sdk;

namespace MyFxCopRules.Rules
{
public class EnsureFaultContractsAreDeclared : MyBaseRule
{
public EnsureFaultContractsAreDeclared()
: base("EnsureFaultContractsAreDeclared")
{
}
}
}

[VS2005] In the using directives add Microsoft.FxCop.Sdk.Introspection and Microsoft.Cci


Of course, this rule is pretty much useless right now as it doesn't actually do anything.


What we need to do is implement a Check() method.  There are various Check() methods that the BaseIntrospectionRule class exposes and these methods are called by the introspection engine each time it visits a code element.  When the Check() method runs it should report back any problems it finds in a ProblemCollection.  Obviously if there are no items in the collection it means the rule evaluated successfully.


Because the rule we are writing is going to be checking that method level attributes are correctly defined we will implement the Check(Member member) method.

        public override ProblemCollection Check(Member member)
{
if (VerifyAttributes(member.Attributes))
{
this.Problems.Add(new Problem(this.GetResolution(member), member));
}
return this.Problems;
}

private static bool VerifyAttributes(AttributeNodeCollection attributes)
{
bool isOperationContract = false;
bool hasFaultContract = false;
foreach (AttributeNode attribute in attributes)
{
if (attribute.Type.FullName == "System.ServiceModel.OperationContractAttribute")
isOperationContract = true;
if (attribute.Type.FullName == "System.ServiceModel.FaultContractAttribute")
hasFaultContract = true;
}
if (isOperationContract)
return !hasFaultContract;
return false;
}

[VS2005] Use the type AttributeList instead of AttributeNodeCollection for the VerifyAttributes parameter


[VS2005] Use RuleUtilities.Format(member) instead of member in the GetResolution() call


So, what happens when FxCop evaluates this rule?


1. The Check() method gets called and the current Member (method or property) being checked is passed in.


2. We take the collection of Attributes that the member has associated with it and pass them to the VerifyAttributes helper method.


3. VerifyAttributes does a simple scan through the Attribute collection looking for any attributes of the appropriate type.  If an [OperationContract()] is found but we don't find a [FaultContract()] we return false to true to the Check method to indicate we have a problem.


4. Back up in the Check method we create a new Problem and add it to the ProblemCollection before returning control back to FxCop.


Step 5 - Define a Rules.XML file


We're not quite done yet.  If we were to take this code, compile it and then try to use it we would see a rule group appear in Visual Studio, but we wouldn't see any rules in the group.


This is because we haven't yet created an XML file that defines the rule behaviours when problems are found.  The code determines if a problem exists, the XML file determines what do show when a problem is found.


Go and add a Rules.XML file to the project and ensure that the Build Action is set to "Embedded Resource" as shown


fxcop4


Inside the file add the following XML

<?xml version="1.0" encoding="utf-8"?>
<
Rules FriendlyName="My Custom Rules">
<
Rule TypeName="EnsureFaultContractsAreDeclared" Category="MyRules.Usage" CheckId="MU0001">
<
Name>Supply Fault Contracts for all WCF Operations</Name>
<
FixCategories>Breaking</FixCategories>
<
MessageLevel Certainty="95">Warning</MessageLevel>
<
Resolution>WCF Operation Contracts need to have a fault contract defined using the [FaultContract()] attribute</Resolution>
<
Description>Fault Contracts need to be applied to all WCF services</Description>
<
Owner>Richard Banks</Owner>
<
Email></Email>
<
Url>http://richardsbraindump.blogspot.com</Url>
</
Rule>
</
Rules>

Hopefully the properties are all obvious enough.  If you have problems check that the TypeName doesn't have any spelling mistakes in it.


Step 6 - Deployment


Now compile the project and make sure everything is OK.  Then close Visual Studio 2008.


Copy your custom FxCop rules assembly from your output folder into the Visual Studio rules folder - typically C:\Program Files\Microsoft Visual Studio 9.0\Team Tools\Static Analysis Tools\FxCop\Rules


Restart Visual Studio and open the solution again.  If you now go to the properties page for the WcfServiceLibrary1 project you should see something like the following:


fxcop5


If you then run Code Analysis for the project (Build->Run Code Analysis...) you should see the following in the Error List window:


fxcop6


You're all done!  You  now have a working rule that does something other than check spelling :-)


You can double check that the rule works properly by adding [FaultContract(null)] to one of the operation contracts methods and seeing that when you re-run analysis that there is one less MU0001 warning.


P.S. If you're into FxCop then you'll probably want to add some rule suppressions to your rule classes as well as the code for the custom rule will violate a few of the standard FxCop rules (CA1014 & CA2210).

Feb 27, 2008

An "Agile" Agile Presentation

I did 2 presentations on agile today as part of the Readify Developer Network events that Readify holds for the developer community (they're free so please come along).  As I recently did an hour long presentation on "Agile From a Developers Perspective" I wanted to avoid repetition so I thought I'd try to do something a little different and do a presentation on agile in an agile manner, where I let the audience (the customer) define the content of the presentation (setting the requirements and the priorities).

Below is a video (33 minutes) of the second presentation, recorded live.  There's not a lot to see on screen and you don't get to see me waving my hands around, but the audio is quite good and I'd like to think that you'll get some value from it.  The presentation itself deals with the following questions:

  • How do you do estimating with an unknown target?
  • Can a team be agile in a company with a "traditional" environment?
  • How do you do up front estimating - especially related to fixed cost?
  • Which agile methodology should we use?
  • How much documentation is needed before we start & how much should we create as we go?
  • How do you pick a good agile team member - what qualities of a person do we look for?
  • How do we handle scope changes in terms of the overall project?

 

P.S. This video is hosted on Google Video and not YouTube because of YouTube's 10 minute length limitation.

Feb 11, 2008

I'm Twittering

Thanks, I think, to Jim Benson (aka OurFounder) and Darren Neimke both talking about social networking recently and as a practical follow up to my own semi-related post about it, I'm now finally twittering.   I've sworn in the past that I wouldn't do this because of the attention breaking issues, however I've found that it's actually pretty easy to tune out when I need to get stuff done. I suppose it's just personal discipline.  A bit like ignoring the Readify tech list and only reading blogs at the start/end of the day.  I think I may have to eat my words on this one.  Either that or admit I'm a twit - how embarrassing!

 

Anyhoo - if you want to subscribe to my updates you can find me at http://www.twitter.com/rbanks54

Detecting Duplicate Code

I’ve recently stumbled across a tool that detects duplicate code (aka code clones) called CCFinder.  It’s definitely not the simplest thing in the world to download and install, and it’s a little bit painful to exclude generated files (it has to be done manually) but it does do make finding repeated code a lot easier than with a tool like Simian.  Why?  Because you get a visual indication of where the duplicates are and can see the code itself.  Plus you have greater control over the rules used to detect duplication of code.

Now before I run through things, it should be noted that I’d expect to see some level of "detected duplication" in any non-trivial code base.  There are often scenarios where one part of the code will have a similar structure to other parts even though they're performing different functions or you'll have generated code or have situations where avoiding duplication adds more complexity than it is worth.  Even so, the amount of duplication detected in any code base should be kept as small as possible as it keeps your code maintainable and means that fixes and changes only need to be made once.  There's nothing worse than fixing a bug in one part of the code, not realising the same code actually exists elsewhere and also needs fixing.

To give you an idea of what CCFinder shows have a look at the following screen shots:

This first picture is showing code clone metrics per file and a visual indication of where the code clones are.

In the left panel (the file listing) various metrics are shown per file:

  • LEN: File length (in tokens – variable names, method calls, etc)
  • CLN: Number of Code Clones
  • NBR: Neighbors – Number of other files that share a code clone in this file
  • RSA: Ratio of Similarity to another file.  Lower is better.
  • RSI: Ratio of Similarity within the file. Lower is better.
  • CVR: Coverage – Percentage of tokens covered by another code clone (and indication of how much of the code is duplicated)

In the right hand panel we have a visual indicator of where the clones are.  The long diagonal line can be thought of as a mirror line and the black marks on each side of that diagonal are the clones.  The large boxes are directory boundaries, so we can see which directories have more duplication than others.

ccfinder2

We can also use Source view to see the duplicates between files.   For example this shows a SetDateLabel() method in two different files where the code only differs by the parameter being called.  It would be a great refactoring candidate.

If it's not obvious the section between the file listing and the code windows is a visual indicator of which file sections the two source windows are showing, and where the duplicated code is within those files.

ccfinder5

You can also see code clones within the same file as well:

ccfinder4

I've only used it for a short while, but I'm finding it to be very, very useful.  If you can work through the crappy web site and the awful download/registration process hopefully you'll find it just as useful.

If you want the software, it’s free but you will need to register to get a license.  Go to http://www.ccfinder.net/index.html and download it from there.

Feb 4, 2008

I Get By With a Little Help From My Friends

Darren recently posted about getting help through networking.  I hadn't actually seen his post when I drafted the following, but it's really quite useful.  If you don't have a good network of people you can ask questions of then go and have a read (in fact, go have a read of it anyway).

----

<Ad Voice>

Want to know the answer to a technical problem and you want it fast?

Want advice on how to get around that tricky widget architecture design problem you’ve been scratching your head about?

Customer wants you to help with something you’ve never seen before in your life?

Coffee stains turning your teeth brown?

Well – look no further!!  Your answers are here!!

</Ad Voice>

In all seriousness (or as serious as I can get) if you want answers to something then here’s your choices in increasing order of effectiveness.

Reference Docs

Go to the MSDN docs (or the manual for whatever you have a problem with).  It's OK if you know what you’re looking for – terrible if you don’t.  And if you knew what you were looking for you wouldn’t have a question now, would you?

Search Engine

Type a search phrase into Google.  Wade through 1,763,209 pages for that needle in a haystack.  Get confused with all the results, waste 3 hours.

Forums & Mailing Lists

If Phone-A-Friend fails (see below) and there’s no answer on that phone thingy, they’re busy, they don’t know, etc - then ask a forum or mailing list.  [You might want to use MSDN forums, ASP.NET forums, mailing lists, or whatever else is appropriate for you]

It’s what they're for.  Don't be a lurker and remember that the more active you are, the more you'll get known by others and the more likely you are to grow your network of contacts.

Give it a little time though - people might not always have an answer at the ready  (they might be busy, or they don’t know either) and if your question spawns an off-topic thread, feel free to slap people silly with a wet mackerel and bring it back to the question at hand.

Oh, try and maintain a sense of humour as well, and be aware that in large forums there will be a number of differing opinions.

Most importantly, don't just receive help, give it as well.  And always show your thanks and appreciation to those that offer assistance.

Phone-A-Friend

This is by far the best option.  Here’s how it works:

Think of someone who has dealt in the area you have a question in.

Ask them!!

I know, I know!  It's just like rocket science!

I also know that asking questions can be really difficult at times – so here's are a number of handy tools you can use to get over your fear of talking.

Send an email:

clip_image004

Send an instant message:

clip_image008

Or, if you are feeling brave, use a phone:

clip_image010

(I know – it's scary using that phone thing isn’t it!)

Is that clear enough?  I hope so.  Now, go get networking and get those answers you seek :-)

 

P.S. I'm more than happy to be a part of your network - feel free to invite me.