CoreCoder

LANGUAGES: C#

ASP.NET VERSIONS: 3.5 | MVC

Model: The M in ASP.NET MVC

Modeling Data for an ASP.NET MVC Application

By Dino Esposito

According to the original formulation of the MVC pattern, the model is the object that represents the application gateway to the business logic. The model holds the current state of the application and replies to requests for state changes coming from the view via user gestures. The model also is designed to execute actions requested by the controller, which typically results in state changes. In a nutshell, the model is the representation of any data consumed by view and controllers. But what about the MVC pattern as implemented in ASP.NET MVC?

Well, that s a slightly different thing. In ASP.NET you find a version of MVC adapted to a new medium the web that just wasn t around yet at the time in which MVC was first devised (in the 1980s). In terms of patterns, ASP.NET MVC implements the Model2 pattern rather than the classic MVC. On the other hand, Model2 was developed as an attempt to bring MVC and its separation of concerns to the web. Figure 1 shows a UML sequence diagram of how the Model2 pattern works (and subsequently ASP.NET MVC).

Figure 1

Figure 1:The sequence diagram for the Model2 pattern

What s the Model Really For?

There are a few differences between classic MVC and Model2. First and foremost, there s no direct contact, let alone an observer relationship, between view and model. Second, the controller renders the view and explicitly passes data to it. The user gesture is not captured and handled by the view as in classic MVC. In a web scenario, the browser captures the user s activity and posts a request to the web server. On the server side, it is a system component the front controller that intercepts HTTP requests and figures out from the URL and headers which controller will be in charge for the request. From the server perspective, the entry point in the chain is the controller, not the view as is the case in classic MVC. Today, people often speak of MVC with regard to the web, but what they actually mean (consciously or unconsciously) is Model2. And Model2 is exactly the pattern behind Microsoft s ASP.NET MVC Framework.

So what s the M in ASP.NET MVC? At the end of the day, the model is any object the controller can talk to that triggers business actions. Shape and color of the model depends on the architecture of your back end and the layers you have in place. If you use LINQ to SQL or Entity Framework to drive data access, you might be led to think that model means an object model. From a design perspective, this is incorrect. The model is primarily the gateway to the business logic.

The business logic is then made of business objects (including services, workflows, and ad hoc components) and an object model. The object model can be a collection of typed DataSets or, better yet, a LINQ to SQL or an Entity Framework object model. It also can be something different, such as a handcrafted hierarchy of plain .NET classes.

If the model is based on typed DataSets, then you need to write your own objects to manage persistence and perform calculations. If you opt for LINQ to SQL or Entity Framework, you can kill two birds with a single stone: You have an object-based representation of the data and a gateway object to call it the DataContext object in LINQ to SQL and the ObjectContext object in Entity Framework. In these cases, the underlying framework offers to manage persistence via its internal O/RM engine. The model , however, also can be based on a Service Layer pattern and manage persistence via any O/RM in the marketplace, including NHibernate and Genome. The model also can be articulated as a set of CSLA.NET business classes, as well as in a variety of other ways.

The model in modern MVC frameworks, however, is not simply a library of classes to describe the data being used. It is, instead, a layer of code that contains data to work with and behavior to be invoked by controllers.

In the rest of this article I ll focus on the characteristics of the model that represents the data, assuming you have another layer that cares about persistence. (This is a common scenario when you opt for a solution based on LINQ to SQL or Entity Framework.)

Validation in the Data Model

A data model for a layered application has three main requirements. It must expose a public interface for the data; it must provide a way to validate any instance of data; and it must publish an API to work with data and persist it. Persistence depends on the helper framework you use. Data modeling depends on the approach you take in design. It can be a database-centric approach, where you start designing your data classes from some existing database. It also can be a data-centric approach, where you design your classes in a persistence-agnostic manner and delegate persistence to a separate data access layer based on some O/RM tools.

What about validation, instead? Figure 2 shows the structure of a sample class to be used as the root of an object model that supports validation.

public class MyRootObject : ISupportValidation

{

public virtual bool IsValid

{

get

{

try

{

return new ValidationResults().IsValid;

}

catch

{

return false;

}

}

}

ValidationResults ISupportValidation.Validate()

{

ValidationResults errors =

new ValidationResults();

:

return errors;

}

}

Figure 2:Validation in a data model

The ISupportValidation interface looks like this:

interface ISupportValidation

{

bool IsValid{get;}

ValidationResults Validate();

}

ValidationResults is the class in your business logic responsible for reading and applying validation rules. Validation rules can be defined in a number of ways, and are checked by the business logic. For example, you can develop your own validation block where you use attributes on members to define rules. Here s a quick example:

public class Customer : MyRootObject

{

public Customer()

{

:

}

[NotNullConstraint(Message="Customer ID cannot

be null")]

[LengthConstraint(5, 5, Message="Customer ID must be

exactly 5 chars long")]

public virtual string ID { get; set; }

:

}

Attributes are part of the validation block and are checked within the Validate method. Each attribute expresses a business rule. In the previous example, the Customer ID is set to be non-null and exactly five characters long. In Microsoft s Enterprise Library 4.1, you ll find similar attributes and a ValidationResults class as used in this pseudo-code. In particular, you express business rules in Enterprise Library using attributes such as NotNullValidator, StringLengthValidator, RegexValidator, and so forth.

The responsibility of validating the state of an object definitely belongs to the business layer and precisely to objects that you use to perform operations. In no way does this responsibility belong to the presentation logic.

Connecting the Validation Layer and Controllers

In ASP.NET MVC, the controller scripts the application s back end and object model in order to obtain the data it needs to display in a new or updated view. So it is the controller that validates objects from the model before proceeding with operations. Here s a sample schema to follow:

// Controller method invoked from the UI
public class ProductController : Controller
{
public ActionResult Insert(Product p)

{

if (p.IsValid())
{

// Add product to the storage

}

}
}

Any data the controller obtains from the model is then serialized to the view so a fresh HTML page can be arranged. Likewise, the controller manages exceptions within the model, including business actions:

// Controller method invoked from the UI
public class ProductController : Controller
{
public ActionResult Insert(Product p)

{

try {

:

} catch {

:
}

}
}

In case of exceptions, it is up to the specific implementation of the controller to decide whether the native exception from the model should be managed so that the user interface doesn t even know about that and degrades gracefully with the empty data it receives. There s a more general alternative, though. It is based on the assumption that the controller swallows the original exception and replaces that with another exception that the view will handle. In ASP.NET MVC, however, the view is a sort of template processed by a view engine that receives data and fills it in. It s hard to handle exceptions at the view level. The controller is, ultimately, responsible for any exceptions raised within the model.

Validation in a LINQ to SQL Scenario

If you ever used LINQ to SQL to create the object model for your ASP.NET MVC application, you know that the model is created by a wizard. You certainly can put your hands on the generated file, but at the risk of losing any changes as you happen to restart the wizard. For this reason, classes in the LINQ to SQL model are partial. In this way, you can add your changes to additional partial classes and make them survive future changes made through the wizard.

One of the key changes you might want to make to LINQ to SQL classes relates to validation. LINQ to SQL classes are plain .NET objects with no dependency on the framework. First and foremost, properties of any classes in the model are annotated with rules inferred from the database schema. This means, for example, that data types are matched and nullability is handled properly. Likewise, columns with unique values are honored.

In addition, classes within the model feature a number of extensibility methods, namely partial methods that may, or may not, be implemented in some partial class. Many of these methods regard validation. Here s an example:

[Table(Name="dbo.Customers")]

public partial class Customer : INotifyPropertyChanging,

INotifyPropertyChanged

{

partial void OnValidate(System.Data.Linq.ChangeAction

action);

partial void OnCustomerIDChanging(string value);

partial void OnCustomerIDChanged();

partial void OnCompanyNameChanging(string value);

partial void OnCompanyNameChanged();

:

}

For each property in the class the wizard defines a pair of partial methods of the type OnXxxChanging and OnXxxChanged, where Xxx is the property name. These properties are automatically called from the setter of each property and provide an effective way for ensuring that no invalid values are assigned:

public partial class Customer

{

partial void OnCustomerIDChanging(string value)

{

if (value.Equals("KOEN2"))

{

throw new InvalidExpressionException("...");

}

}

}

The OnValidate method, instead, is a placeholder for you to define when you re looking for just one method to call to ensure that the object is valid.

Integrating Business Rules

Extensibility methods are not enough. They help you in preventing situations where code attempts to store invalid values into properties but don t support you much when it comes to business rules. A business rule is not simply a syntax rule and does not necessarily apply to just one property. It is recommended that you further decorate your LINQ to SQL classes with attributes or code that express and validate business rules. A possibility is defining a validation interface such as the aforementioned ISupportValidation and using partial classes to force it in any LINQ to SQL entity class.

The Validate method will then go through the list of checks necessary for each entity and report violations to the caller code. Here s a possible schema for a solution:

public ValidationResults Validate()

{

ValidationResults openPoints =

new ValidationResults();

if ( ... )

{

string message = "...";

openPoints.Add( new Violation( message );
}

:

}

Such a Validate method, or whatever name you want to give it, will be called from the code before persisting the object or, in general, at any time in which the validity of the object has to be checked.

Conclusion

Originally formulated to cover the creation of the entire application, the MVC pattern has been adapted to the web and fully implemented in the ASP.NET MVC Framework. The model in the pattern represents the gateway to the back end of the system, as well as any exposed business actions. At the same time, the model also incorporates the representation of the data within the application.

ASP.NET MVC doesn t mandate any specific approach or technology to build the model and add validation to it. So you can use LINQ to SQL s built-in facilities to implement syntax checks such as nullability and data types. At the same time, you can use extensibility methods to check business rules or you can integrate your own business validation layer on top of LINQ to SQL classes. The business validation layer can be created via Enterprise Library or it can be your own library. The freedom of implementation is unmatched; but make sure you don t overlook a layer to validate your MVC model.

Dino Esposito (dino@idesign.net) is an architect at IDesign, specializing in ASP.NET, AJAX, and RIA solutions. Dino co-authored Microsoft .NET: Architecting Applications for the Enterprise and Microsoft ASP.NET and AJAX: Architecting Web Applications.