Using CodeContracts Reference Assemblies in Client Applications

It is useful when designing interfaces to be able to define the design-contracts for those interfaces, however because interfaces cannot contain code, CodeContracts cannot be written for them directly. Instead, contracts are defined through the of “buddy” contract abstract classes that are not really classes at all, but just place holders for the contracts in the interfaces.

Consider the simple interface below:

[ContractClass(typeof(MyServiceContracts))]
public interface IMyService{
   string Echo(string str);
}

To define a simple not null contract, we create a class as follows:

[ContractClassFor(typeof(IMyService))]
public abstract class MyServiceContracts : IMyService{
  public string Echo(string str){
    Contract.Requires<ArgumentNullException>(str != null);
    return null;
  } 
}

You can see that the buddy class implements the interface it is the buddy for. Because this buddy class is never intended to be referenced, the actual implementation is not important other than the contracts it defines.

To build the reference assembly, make sure you set the Contract Reference Assembly option to “Build” in the project settings, on the Code Contracts tab.

Using the Reference Assembly

There was surprisingly little information on how to actually use a reference assembly to enforce constraints on interfaces, so I created a test harness as follows:

class Program{
  public class MyServiceImpl:IMyService{
    public string Echo(string str){
      throw new NotImplementedException();
    }
  }

  static void Main(string[] args){
    IMyService service = new MyServiceImpl();

    Console.WriteLine(service.Echo(null));
  }
}

If the contracts worked and enforced at the interface level, then I should get a null argument exception thrown, else if they don’t work I would get the “NotImplementedException”.

I copied the built interfaces assembly to a separate, new folder location on my machine, leaving the CodeContracts assembly alone for now. I then added a reference to the interface assembly from my client code. When I ran the test, I did not get the contract exception. I then checked the code contracts settings for the project to make sure I was enabling full runtime checking. I then noticed that the Assembly Mode was set to “Custom Parameter Validation” so I changed it to “Standard Contract Requires”, ran the test and still got no contract exception.

I then copied the CodeContracts reference assembly from the first project to the location of the interface assembly and re-ran the test. Still no code contract exception. This was really beginning to bug me.

A burst of inspiration hit me and I re-built the client application (instead of merely re-running it) and well hello, I got the contract exception I was longing for.

I also experimented with locating the contracts reference assembly in the folder called CodeContracts in the same place as the interface assembly, and it works as well.

Conclusion

This post has covered how to use contracts reference assemblies in client applications. It is necessary to either co-locate the reference assembly where the real assembly is placed, or in a folder “CodeContracts” in that location. It is also necessary to turn on CodeContract runtime checking and use “Standard Contract Requires”, and a rebuild is required to pick up CodeContract assemblies.

Advertisements
This entry was posted in .Net, CodeContracts and tagged . Bookmark the permalink.

One Response to Using CodeContracts Reference Assemblies in Client Applications

  1. porges says:

    Yep, you need to rebuild because Code Contracts will rewrite the code at compile-time in your client application, according to the contracts in the library’s reference DLL. If there isn’t a reference DLL there at compile-time there’s nothing for Code Contracts to work on, and you won’t have any contracts 🙂

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s