Code Contracts and Controllers

Express controllers' preconditions using the new software contracts API in .NET 4

MVC controller actions have structural likenesses with classic postback event handlers, which you know well from Web Forms. Before you label this sentence as pure blasphemy and turn your attention elsewhere, let me point out that the major structural differences you'll observe between ASP.NET MVC and ASP.NET Web Forms live outside the controller class. For example, you'll find many differences in the way in which the request is being processed—no page-based approach, radically different request life cycle, different way of forwarding posted data, different way of generating the next view.

What would you find instead in a controller class? A controller class is a plain container of methods. I dare say that a controller only exists because we need classes to hold actions to execute against HTTP requests. The controller class is stateless and it's instantiated for each and every request. Its lifetime is fairly short, because it lives only to execute the selected action method. Controller actions contain only the code that "handles" the "event" generated by the HTTP request being processed. Controller actions are, in this regard, the MVC counterpart of postback event handlers.

Both event handlers and controller actions need to collect input data, perform an action against the back-end of the system, and arrange obtained results into a nice piece of user interface to return to the browser. Both event handlers and controller actions can be written as a messy tangle of object calls. Choosing ASP.NET MVC instead of Web Forms neither automatically cleans up your code nor enhances your ability to write clean code. Writing clean code for controller actions, however, is simpler and in a way easier, thanks to some new goodies you'll find in the .NET Framework 4. Enter code contracts in the reign of ASP.NET MVC controllers.

 

Introduction to the Code Contracts API

 

Code Contracts (CC) is the name of the technology behind the new Contract class defined in the System.Diagnostics.Contracts namespace within mscorlib. The Contract class implements software contracts—an old concept in software design—according to which each function should expose the terms of the service it can provide using a formal and unified language. A software contract is the sum of three elements: preconditions, postconditions, and invariants.

Preconditions list the conditions under which the function will execute. Failing to fulfill any of the preconditions set for the method will prevent the method from running. Postconditions identify the results that the execution of the function ensures. Finally, invariants describe possible conditions that remain constant within the host class before and after the execution of any functions. CC in .NET 4 provides a comprehensive and unified API to express (even partially) software contracts.

In .NET 4 projects, you enable and configure CC through the properties of the project in Visual Studio 2010. Note that you can employ different settings for Debug and Release configurations. An evergreen question lies behind software contracts: Should you disable contracts in production? In .NET 4, the framework doesn’t hold any position and leaves it all to you.

 

Inside Preconditions

 

In this article, I’ll focus only on preconditions and reserve postconditions and invariants for future columns. Preconditions are the part of software contracts that most developers are already familiar with. Many developers, in fact, often employ preconditions in well-written software, even though they might miss the whole theory of software contracts. The code snippet in Figure 1 shows a working example of preconditions.

As you can see, the GetPrice method begins with a list of IF statements, each aimed at ensuring that a given critical condition is successfully verified. The list of IF statements you see in Figure 1 is no more than the list of preconditions for the method GetPrice. So what’s the difference between this and CC? It’s just a different syntax, as Figure 2 shows.

To express a precondition, you use the method Requires<T>, where T is an exception type. The method Requires takes a Boolean expression and evaluates it. If the condition is not verified, then the specified exception is thrown.

Expressed using the CC API, the code of the controller is inherently cleaner, but functionally equivalent to the code shown in Figure 1. However, using the CC API has another benefit that goes beyond the runtime behavior of the code. The Contract class represents a unified syntax that other tools around Visual Studio 2010 can use to consume the same contract information. An IF statement is just a runtime statement; a Requires<T> call is also a piece of meta information that tells specialized tools about the expected behavior of the method.

One of the valuable tools that currently consume this information is the static code checker that may perform (usually in background) a static analysis of your code to signal possible places where the code breaks pre- or postconditions. In the end, it’s like having a fellow developer who, looking at your code, can tell if a given line will fail. You must enable static analysis on the project, as shown in Figure 3.

 

Preconditions on Legacy Code

 

So the difference between using classic if-then-throw statements (a practice that should be familiar to any developer) and CC seems to be the unified syntax that other tools can understand. What about legacy code?

The good news is that, in regards to Requires<T>, you're not required to update existing code by rewriting if-then-throw statements. You can leave your code as is and just append an EndContractBlock call to the list of IF statements. The effect is the same and you preserve most of your code while ensuring that external tools can interpret statements as effective preconditions. Figure 4 shows what you should obtain.

Note that preconditions should always appear at the beginning of the method. Neither regular code nor other contract calls can precede preconditions.

 

Requires<T> and Requires

 

If you read through the CC documentation, you'll run across a simpler and non-generic variation of the Requires<T> method:

 

Contract.Requires(productId >0);

 

Small differences exist between Requires<T> and Requires, even though they mostly achieve the same behavior. Requires doesn’t let you set the type of the exception that will be thrown when the conditions is not met. If a Requires clause fails, a system exception is thrown—specifically, an exception of type ContractException.

Furthermore, Requires<T> requires more configuration work to use than the simpler Requires. In the CC tab within the solution properties window, you must select an Assembly Mode of "Standard Contract Requires" if you plan to use at least one Requires<T>. If you only use Requires, the choice is not restrictive. Note the default value of the assembly mode is "Custom Parameter Validation." The wrong setting, however, only  triggers a compiler error, which can be fixed in a moment.

You can catch CC exceptions via the ContractFailed event. Here’s how to set it:

 

Contract.ContractFailed += (YourExceptionHandler);

 

The exception handler looks like that shown below:

 

static void Contract_ContractFailed(Object sender, ContractFailedEventArgs e)
\\{
      Console.WriteLine("Failure due to \\{0\\}: \\{1\\}",
              e.FailureKind, e.Condition);
      e.SetHandled();
\\}

 

Each CC exception carries specific information aggregated in the ContractFailedEventArgs class. The class offers a property Message that contains a message about the reason for the exception, as well as FailureKind and Condition properties that inform you about the kind of failure detected (whether it is precondition, postcondition, or other) and the condition that was not verified. When adding a custom exception handler, you should explicitly set when (or if) the exception handling must be considered terminated. As in the previous snippet, the SetHandled call tells the CC infrastructure that the exception has been fully handled and that it's no longer required that it bubbles up the stack.

 

Quantifiers

 

The Requires and Requires<T> methods work great for checking input parameters of controller methods. However, they evaluate on a single individual condition. The condition might include one or more parameters and be formed by one or more Boolean operators. In any case, it's an expression that involves parameters by name. What if you need to evaluate a collection of data?

The typical example is when a controller method gets an enumerable list of objects that are to be validated individually. Unfortunately, the following rather intuitive code, is not permitted:

 

public ActionResult Get(Int32\\[\\] customerIds)
\\{
   foreach(var id in customerIds)
   \\{
       Contract.Requires<ArgumentException>(id >0);
   \\}
   :
\\}

 


The reason is that an unacceptable mix of regular code and CC code is found at the top of the method. CC meta information is not as pure and easily identifiable as it should be. However, the CC API offers a couple of quantifiers that you can use to achieve the same results: ForAll and Exists.

You use ForAll to check whether all elements in a collection verify a given condition. You use the Exists operator to check whether at least one element matches the given predicate. Needless to say, Exists stops at first match. Here’s how to rewrite the preceding code to use the ForAll quantifier:

 

public ActionResult Get(Int32\\[\\] customerIds)
\\{
   Contract.Requires(
      Contract.ForAll(customerIds, (id) => id >0)
   );  
   :
\\}

 

 

Let Code Contracts Help You

 

Code Contracts is not a technology specific of ASP.NET MVC, because the technology belongs to the .NET Framework 4. As such, the technology is widely helpful to developers writing any type of application or library. Code Contracts helps you identify the prerequisites and warranties that a method has. It's good from a design perspective and it's also great to keep the code clean.

With regard to ASP.NET MVC controllers, CC is a great help for reformulating if-then-throw statements at the beginning of methods in a more succinct and readable way. In addition, CC lets you make statements about conditions that the execution of a method ensures. This aspect of CC (postconditions) is not particularly significant in the context of ASP.NET MVC controllers, but it helps in the building of helper services consumed by controllers. CC takes you closer to having code statically check the correctness of other code—a revolutionary step that might leave many of you a bit baffled. But don’t be scared; give it a try.

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish