Introducing Advanced Code Contracts with the Entity Framework and Pex (Cont.) Add Contracts to Your Entities As promised at last, I will now explain how to add contracts to model-generated ADO.NET entities. The goals of this demonstration are not only to show you how to define real-world contracts for the Entity Framework, but also to present advanced integration techniques and strategies made possible by the design of Code Contracts. You will see how powerful contract injection can get and why Code Contracts is not just shipped as a simple class library. | " | You can even add contracts to third-party assemblies.
| " |
For the purpose of this exercise, I will add contracts to Customer, Address, and Product entities generated from the AdventureWorksLT2008 database. As you’ll discover, you have some options before you to do that. The choice of the technique to use depends on the type of contract you need and of the availability of the entities source code. As I’ll demonstrate, you can even add contracts to third-party assemblies, within certain limits. Figure 2 shows the related table schemas of the entities, which I’ll use as a reference to define matching contract clauses.  Figure 2: The Address, Customer, and Product entities related-database table schemas.The Visual Studio companion solution for this article consists of a few C# projects, and is presented in Figure 3. The Client project is a console application with full runtime checking enabled. You can run it to see the numerous samples presented here in action. I will cover the other projects in the next sections.  Figure 3: The Visual Studio companion solution for this article.Before starting, please note that you can apply the strategies I’ll be unveiling to any type of project. They are not restricted to ADO.NET entities or the Entity Framework. Code Contracts Conditions I’ve been enforcing preconditions in my everyday programming for years, either with homemade class libraries or existing frameworks, such as the Enterprise Library Validation Application Block (VAB) (http://entlib.codeplex.com). Some time ago, as part of the Enterprise Library Contrib project (http://entlibcontrib.codeplex.com), I provided an ArgumentValidation class, which enables you to validate method arguments using the VAB validators without the burden of the Policy Injection Application Block Validation Call Handler: ArgumentValidation.Validate( "arrayIndex", arrayIndex, new RangeValidator(0, 9));
What I like about the VAB validators is that they look nice; just by seeing their names you understand what your code is doing. Besides that, they centralize comparison logic in one single unit of work. With the Code Contracts Library, the previous statement would look like this: Contract.Requires(arrayIndex >= 0 && arrayIndex <= 9);
One of the first things I thought of when I started using Code Contracts was: Wouldn’t it be cool if the Code Contracts Library had something to make my conditions look as nice as the VAB validators? What about some helpers to make the code more readable? So, here come the Code Contracts Conditions. They’re a small bunch of extension methods I created to provide centralized comparison logic for the contract clauses. The Conditions are available as part of the Code Contracts Extensions project on CodePlex (http://ccextensions.codeplex.com). Each of these methods is flagged with the Pure attribute, a Code Contracts attribute which indicates that the callee has no visible side-effect from the caller point of view: [Pure] public static bool IsInRange<T>( this T value, T lowerBound, T upperBound) where T : IComparable<T> { Contract.Requires(!value.IsNull());
return value.CompareTo(lowerBound) >= 0 && value.CompareTo(upperBound) <= 0; }
Because extension methods are static, you can invoke them as extensions or call them directly: Contract.Requires(arrayIndex.IsInRange(0, 9)); Contract.Requires( Condition.IsInRange(arrayIndex, 0, 9));
Feel free to visit CodePlex and propose your own extensions. The followings are some more examples of the Conditions in action: Contract.Requires(!customer.IsNull()); Contract.Requires(!collection.IsNullOrEmpty()); Contract.Requires(value.IsMatch("^[a-z]*$")); Contract.Requires(Contract.ForAll( positiveNumbers, (int number) => number.IsGreaterThan(0)));
I don’t recommend using the Code Contracts Conditions with static checking. Although you can have the Static Contract Verifier understand some of the Conditions by providing the Ensures method to describe the return values, in general it lacks, for now, the ability to evaluate methods with undeterminable or complex contracts (such as Regex::IsMatch). Again, I choose to take full advantage of runtime checking versus static checking. Since I’ll be using the Code Contracts Conditions while adding contract clauses to the ADO.NET entities, I included the CodeContractsExtensions project directly in the Visual Studio companion solution for the article, where it’s referenced by those of the other projects that need it. Interface Preconditions and Postconditions The C# project Entities in Figure 3 contains an ADO.NET Entity Data Model which was used to generate the Customer and Address entities in the EntitiesModel.Designer.cs file: public partial class Customer : EntityObject //... public partial class Address : EntityObject //...
I’ll start with the Customer entity. It comes with a bunch of properties like FirstName, LastName, Phone, and others that match the Customer table schema introduced in Figure 2. What you want to do is to add contracts to these properties and make sure that the value for each property behaves accordingly to the schema. You could directly edit the generated code and insert your clauses there, but this is a very bad practice, as any regeneration of the Customer class from the model would erase all your changes. There’s a better way: Since Customer is a partial class, you can extend it in a separate file. But how can you extend properties in one file if the code of these properties is in another file? The magic comes from the Contract Rewriter. Remember that it injects contracts in your assemblies after compilation. I also mentioned earlier that contracts can be inherited. All you have to do is to figure out a way to tell the Contract Rewriter that your Customer properties inherit the contracts you want them to enforce. The solution turns out to be pretty simple: you’ll add to the Customer class an interface whose signature matches that of the Customer properties. Figure 4 demonstrates that by using the refactoring features of Visual Studio, you can select the Customer class and, thru the context menu, extract its interface. This way, you can create the ICustomer interface.  Figure 4: Extracting the ICustomer interface.After that, you augment ICustomer with a special Code Contracts attribute, ContractClass. Then define a dedicated contract class for ICustomer, ICustomerContract, which you also decorate with an attribute, ContractClassFor. What is left to do is to have the ICustomerContract class inherit from the ICustomer interface and implement the interface explicitly. It is in that implementation that you can define your contracts for the ICustomer interface. Note that interface contracts are always provided by a concrete class. Listing 5 presents the ICustomer interface, the ICustomerContract class, and a sample contract for the Phone property. As you can see, you can specify contracts to match the database schema requirements as well as strengthen them-here by refusing a null value and adding a regular expression that must be matched by the phone number. To make the Customer class inherit your contracts, you simply indicate that it implements the ICustomer interface by using a separate Customer.cs file: public partial class Customer : ICustomer { }
When the Contract Rewriter runs over the Entities assembly, it will automatically inject the contracts from the ICustomer interface into Customer’s properties. Since the rewriting occurs at the assembly level, your entity generated-code is left untouched. As an example of the benefits you get from using Code Contracts, any attempt to make an invalid Phone assignment will now immediately trigger a contract failure: Customer customer = new Customer(); customer.Phone = "0123xyz"; /* Precondition failed: value.IsMatch(@"^(\d{3}- \d{3}-?\d{4}|1 \(\d{2}\) \d{3} \d{3}-\d{4})$") */
LINQ to Entities If you use Linq to Entities, you can benefit from having contracts in place. However, keep in mind that you must manipulate the strongly typed entities containing the contract clauses: Entities entities = new Entities(); IQueryable<Customer> customers = (from customer in entities.Customer select customer).Take(5);
foreach (Customer customer in customers) Console.WriteLine("{0}: {1}", customer.FirstName, customer.EmailAddress);
This means that if you create anonymous types, you must first convert them to full-blown entities to take advantage of your contracts, as shown in Listing 6. Remember that only the corresponding fields in the strongly typed entities are initialized. If you try to access uninitialized ones, you may trigger contract failures depending of the nature of your contract clauses. Third-party Contract Reference Assembly Previously, you altered the Customer partial class. Sometimes, you may not have access to your entity’s source code. One very cool feature of Code Contracts is that you can create contracts for assemblies even if you don’t have their source code. The ThirdPartyEntities project of the companion solution contains an ADO.NET Entity Model that defines a Product entity. For the purpose of this demonstration, pretend that the project comes from a third party and that you can’t modify it. Instead of using a project reference when you need it, you’ll use a direct assembly reference. So, how can you add contracts to the Product entity contained in the ThirdPartyEntities project without modifying it? The first thing to do is to create another project whose output assembly bears the same name (that is, ThirdPartyEntities). This is what I’ve done with the ThirdPartyEntities.Contracts project. Then, in its Code Contracts property pane (Figure 1), you must check the Build a Contract Reference Assembly option. After that, you define the same Product class in the ThirdPartyEntities.Contracts project. The difference is that the implementation of the class will only contain the contract clauses you want to apply to the Product class. Listing 7 shows what this skinny Product class looks like. When you compile the ThirdPartyEntities.Contracts project, it will create the ThirdPartyEntities.dll and ThirdPartyEntities.Contracts.dll assemblies. This latter assembly contains the contracts you have defined for the Product entity. To use it in the Client application, don’t reference the assembly; instead, go to the Client project’s Code Contracts property pane (Figure 1) and add the path to ThirdPartyEntities.Contracts.dll in the LibPaths box: ..\..\..\ThirdPartyEntities.Contracts\bin\Debug
To make your Requires method kick-in in the Client project, you also must check the Call-site Requires Checking option. When you build the Client project, the Contract Rewriter will pick up ThirdPartyEntities.Contracts and do its magic with the Product entity. But be warned! There are important differences between using a contract reference assembly in that fashion and implementing contracts directly in your entities. First, the Contract Rewriter creates proxies for the Product methods and properties; it doesn’t inject the contracts into the Product class itself. Calls from the Client application to the Product entity will use these proxies, which contain the contracts, when calling the original methods and properties. Also, keep in mind that since the third-party assembly isn’t instrumented with contracts, any internal calls it makes won’t benefit from your contracts. Furthermore: - Only the Requires method is enforced by proxies.
- If you derive a type from a third-party assembly class or interface, it will inherit contracts from a contract-reference assembly only for methods and properties it overrides.
- Invariants are not inherited.
- On the bright side, if you look again at Listing 7, you’ll see that I’ve done something that I couldn’t have done by using an interface while working with the Customer entity: provide a contract for a static method.
In the end, building a contract reference assembly is powerful, but it has its limitations. If you are curious about this feature, explore the standard Microsoft .NET contract assemblies that ship with Code Contracts; this is the implicit way you use them. | & | | Blogs
Jonathan "Peli" de Halleux has an active Blog about Pex at http://blog.dotnetwiki.org. You can also visit http://winsharp93.wordpress.com/tag/code-contracts for some blogging on Code Contracts. Forums
Join the discussions about Code Contracts at http://social.msdn.microsoft.com/Forums/en-US/codecontracts or Pex at http://social.msdn.microsoft.com/Forums/en-US/pex. CodePlex Code Contracts Extensions Project
The Visual Studio companion solution for this article, the Code Contracts Conditions, and the support classes for object validation, self validation, and lazy initialization are all available at http://ccextensions.codeplex.com. Visual Studio Editions
As of this writing, both Code Contracts and Pex are pre-release software, but they come with commercial licenses and you can start using them today. The Contract Rewriter is currently available with Visual Studio Standard Edition or higher and the Static Contract Verifier with Visual Studio Team System. Pex only works with Visual Studio Team System Development Edition or Visual Studio Team System Test Edition. Both projects are compatible with Visual Studio 2008 or 2010 and will mostly remain separate downloads after Visual Studio 2010 is released. |