Code Contracts #8: Sandcastle integration

Release 1.2.20903 (4 Sep 2009) of Code Contracts comes with a nice integration of contracts on classes and methods into Sandcastle documentation! By this, Code Contracts achieve an important goal: real „checked documentation“. This short article gives an overview of how to get your Sandcastle installation to handle contracts.

1) Install Sandcastle (+DocProject)

At first, of course you need a valid Sandcastle installation. Just go to the Sandcastle project page, download the latest release and install it. I recommend installing DocProject for Sandcastle and HTML Help Workshop and Documentation as well. This gives you a nice Visual Studio integration for creating documentation by Sandcastle.

2) Patch Sandcastle with Code Contracts files

Code Contracts documentation syntax is currently not included in the Sandcastle project. In order to make Sandcastle aware of the Code Contracts documentation items, you have to patch the Sandcastle installation with the Code Contracts files. For this, there exists a folder „Sandcastle“ in the Code Contracts installation directory (default is „Program Files\Microsoft\Contracts\Sandcastle„), which contains a file „Sandcastle.zip„.

If you’ve installed Sandcastle from the MSI package, just copy the contents from the „msi\vs2005“ folder of the UIP file to the following location of your Sandcastle installation: „Program Files\Sandcastle\Presentation\vs2005\„. Now you’re done and ready to generate documentation for your contracts!

3) Set up your project

First, if you want to generate documentation for a project in Visual Studio, go to the project properties and in the „Build“ option pane, check the XML documentation file option:

Activate the "XML documentation file" option

Then, to get the contracts injected into the generated XML doc file, go to the „Code Contracts“ option pane and select both the Build a Contract Reference Assembly and the Emit contracts into XML doc file options:

Select generation of Code Contracts documentation

Now, when you build your project, first the documentation of your project’s components will be created as XML file and then the contracts documentation will be injected in the same file.

4) Create your documentation!

For demonstation purposes, I’ve generated a project (including a new solution) AccountExample in Visual Studio, which holds just one class Account. This example class contains some contracts and looks as follows:

/// <summary>
/// Represents an account, to which you can deposit and from which you can withdraw money.
/// </summary>
public class Account
{
    private float _balance;
    /// <summary>
    /// The current balance of the account.
    /// </summary>
    /// <value>The account's balance.</value>
    public float Balance
    {
        get { return _balance; }
        private set
        {
            Contract.Requires(value >= 0);
            _balance = value;
        }
    }

    [ContractInvariantMethod]
    protected void ClassInvariants()
    {
        Contract.Invariant(_balance >= 0);
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="Account"/> class.
    /// </summary>
    /// <param name="balanceInitial">The initial balance, which will be set.</param>
    public Account(float balanceInitial)
    {
        Contract.Requires(balanceInitial >= 0);
        Contract.Ensures(Balance == balanceInitial);

        Balance = balanceInitial;
    }

    /// <summary>
    /// Deposits the specified amount to the account.
    /// </summary>
    /// <param name="amount">The amount to deposit.</param>
    public void Deposit(float amount)
    {
        Contract.Requires(amount > 0);
        Contract.Ensures(Balance == (Contract.OldValue(Balance) + amount));

        Balance += amount;
    }

    /// <summary>
    /// Withdraws the specified amount from the account.
    /// </summary>
    /// <param name="amount">The amount to withdraw.</param>
    public void Withdraw(float amount)
    {
        Contract.Requires(amount > 0);
        Contract.Requires(amount <= Balance);
        Contract.Ensures(Balance == (Contract.OldValue(Balance) - amount));

        Balance -= amount;
    }
}

Moreover, I’ve added a new DocProject to my solution, where I’ve chosen the „AccountExample“ project for generating the documentation from. With that we’re ready to roll!

When building the whole solution, first the assembly of the „AccountExample“ project is built. In this step, the following XML documentation file is extracted as well (note the injected contract tags – requires, ensures and invariant):

<?xml version="1.0"?>
<doc>
  <assembly>
    <name>AccountExample</name>
  </assembly>
  <members>
    <member name="T:AccountExample.Account">
      <summary>
            Represents an account, to which you can deposit and from which you can withdraw money.
            </summary>
      <invariant>_balance >= 0</invariant>
    </member>
    <member name="M:AccountExample.Account.#ctor(System.Single)">
      <summary>
            Initializes a new instance of the <see cref="T:AccountExample.Account" /> class.
            </summary>
      <param name="balanceInitial">The initial balance, which will be set.</param>
      <requires>balanceInitial >= 0</requires>
      <ensures>Balance == balanceInitial</ensures>
    </member>
    <member name="M:AccountExample.Account.Deposit(System.Single)">
      <summary>
            Deposits the specified amount to the account.
            </summary>
      <param name="amount">The amount to deposit.</param>
      <requires>amount > 0</requires>
      <ensures>Balance == (Contract.OldValue(Balance) + amount)</ensures>
    </member>
    <member name="M:AccountExample.Account.Withdraw(System.Single)">
      <summary>
            Withdraws the specified amount from the account.
            </summary>
      <param name="amount">The amount to withdraw.</param>
      <requires>amount > 0</requires>
      <requires>amount <= Balance</requires>
      <ensures>Balance == (Contract.OldValue(Balance) - amount)</ensures>
    </member>
    <member name="P:AccountExample.Account.Balance">
      <summary>
            The current balance of the account.
            </summary>
      <value>The account's balance.</value>
      <setter>
        <requires>value >= 0</requires>
      </setter>
    </member>
  </members>
</doc>

In a second step of the build process, the DocProject generates the documentation for the „AccountExample“ project by taking its XML documentation file. When finished, we’ll have a nice CHM file with the documentation of our example project.

In this documentation we can see our contracts now. On class level, we have our invariant:

Class invariants in Sandcastle documentation

And on method (+properties) level, we get the pre- and postconditions:

Method contracts in Sandcastle documentation

Conclusion

As you can see, contracts in documentation are really valuable. Including them in Sandcastle documentation brings the claim of „checked documentation“ to life! This really helps other developers to understand the intent of your classes by looking at the documentation. And by automatically generating documentation out of your code-based contracts, you can be sure that docu and code do not run out of sync. This really puts more value on Code Contracts and is a real practical advantage!

kick it on DotNetKicks.com

PDC 2008

Morgen geht es los mit der PDC, Microsoft’s jährlicher Professional Developer Conference, die nicht selten den Ausgangspunkt für viele der neuesten Technologien (nicht nur für Entwickler) dargestellt hat. Ich freue mich darauf, aus der Ferne von News in den Bereichen .NET, C# und Visual Studio zu erfahren und einen Ausblick darauf zu erhaschen, was Microsoft in der Zukunft mit diesen Technologien vor hat.

Im Vorfeld der PDC konnte man bereits einiges erfahren und auch die Agenda gibt einigen Aufschluss. Das Thema Parallel Computing ist sicher ein wichtiges für C# bzw. das .NET Framework und mit der Integration der Parallel Extensions wird Microsoft einen wichtigen Schritt in diese Richtung tun. Doch das kann nicht alles sein, gerade im Bereich Patterns ist da noch mehr nötig und hier wird auf der PDC sicherlich einiges auf uns zukommen.

Eins steht schon fest: .NET bekommt ein neues Logo. Hier ist es:

Mich freut’s… das alte war doch „leicht“ angestaubt und erinnerte eher an Zeiten von Windows 98 und ME anstatt an ein aktuelles Entwicklungs-Framework…

Also ich bin gespannt auf die News dieser Woche und werde in diesem Blog auf die besten davon eingehen.