Published: 03 Dec 2009
By: Manning Publications

In this chapter, we’ll explore a model for a system that helps to manage a small conference, like a Code Camp. The model enables the application to provide an interesting service. Without the model, the application provides no value. We place great importance on creating a rich model with which our controllers can work.

Contents [hide]

About the book

This is the second chapter of the book ASP.NET MVC in Action. It has been published with the exclusive permission of Manning.


Written by: Jeffrey Palermo, Ben Scheirman, and Jimmy Bogard
Pages: 392
Publisher: Manning
ISBN-10: 1933988622
ISBN-13: 978-1933988627

Get 30% discount

DotNetSlacker readers can get 30% off the full print book or ebook at www.manning.com using the promo code dns30 at checkout.

Introduction

Without a model, software is not interesting. A model in the English language is just like a model in software: a representation of the real thing. In software, we represent the real world by using objects that are named after concepts we deal with every day. These objects have attributes and behaviors similar to those found in the real world. In this chapter, we'll explore a model for a system that helps to manage a small conference, like a Code Camp. The model enables the application to provide an interesting service. Without the model, the application provides no value. We place great importance on creating a rich model with which our controllers can work.

The style of modeling we'll use in this book is domain-driven design (DDD), as conveyed by Eric Evans in his book, Domain-Driven Design: Tackling Complexity in the Heart of Software. Covering the topic in depth is a book in itself; we'll tackle a small primer, which should enable you to follow the software examples in the rest of this book. After the DDD primer, we'll discuss how to best use the domain model; then we'll move through how to use a presentation model to keep controllers and views simple. We'll keep a keen eye on SoC, and we'll ensure that every class has a single, well-defined responsibility. Before digging deep, we need a good understanding of the basics of DDD.

Understanding the basics of domain-driven design

Developers can use different methods to model software. The method we prefer is domain-driven design, which looks at the business domain targeted by the software and models objects to represent the appropriate concepts. We refer to the domain model as the object graph that represents the business domain of the software. If the software lives in the online e-commerce space, we would expect to find objects such as Order, Customer, Product, etc. These are not just data-transfer objects either. They are rich objects with properties and methods that mimic behavior in that business space. Popular in .NET development, the DataSet object would not be appropriate in a domain model because the DataSet is a relational representation of database tables. Whereas the DataSet is a model focused on the data relationships and persistence, a domain model is focused more on behavior and responsibility. In our fictitious e-commerce application, when retrieving order history for a customer, we would want to retrieve an array or collection of Order objects, not a DataSet of order data. The heavy focus on the demarcation of behavior and the encapsulated view of data is key in DDD. If you are unfamiliar with domain-driven design, you may want to review some of the following references. Reviewing these publications is not necessary for the purpose of this book, but they will help you as you develop software in your career. From this point forward we'll defer to these resources for more detail on domain models, aggregates, aggregate roots, repositories, entities, and value objects. When discussing each of these concepts, we'll talk only briefly about their purpose and then move on. The next section is an overview of the core domain model for this book.

References for learning more

Domain-Driven Design: Tackling Complexity in the Heart of Software by Eric Evans - The most complete reference for DDD. Evans can be credited for making this collection of patterns known. He applies his own experience as he names patterns that work together to simplify complex software. Addison-Wesley Professional (2003).

Domain Driven Design Quickly by Abel Avram Floyd Marinescu - A 104-page book designed to be a more concise guide to DDD than Evans' book. This e-book is summarized mainly from Evans' book. Lulu Press, Inc. (2007).

Applying Domain-Driven Design and Patterns: With Examples in C# and .NET by Jimmy Nilsson - The author takes the reader through real, complete examples and applies DDD patterns along with test-driven development (TDD) and O/R mapping. Addison Wesley Professional (2006).

http://domaindrivendesign.org/-An evolving, information website maintained by Eric Evans, Jimmy Nilsson, and Ying Hu.

Domain model for this book

Throughout the rest of this book, our examples will be centered on the open source project, CodeCampServer. Authors of this book started the project, and it is being extended at the time of publishing by a strong network of contributors. This software can serve as the official website for a software conference, often called a Code Camp. The domain model is centered on the concepts present when managing a Code Camp. Since Code Camp is a common name (also common is TechFest or BarCamp), our central object is Conference. In figure 1, you see the complete domain model for the application, and we'll work with different pieces in the examples following in the chapter and the rest of the book.

Figure 1: Partial domain model for CodeCampServer, which will serve as the basis of future examples in this book.

Partial domain model for CodeCampServer, which will serve as the basis of future 

examples in this book.

Key entities and value objects

Figure 1 shows some of the entities and value objects in play within our domain model. The entities are the key objects in our domain model, such as Conference, Session, Track, and TimeSlot. With so many types in the diagram, you probably wonder what is special about these classes and what makes them entities. The reason these are entities is that they have the concept of an identity, a property which can be examined to determine uniqueness. The reason we give these objects an identifier is that these can stand on their own, and we can speak about these objects without other supporting concepts. It would make sense to list a collection of any of these objects. Entities can stand on their own, and we can reason about them in a collection or as a single object.

Value objects don't make sense on their own without the supporting context of an entity to which they belong. Two value objects in our domain model are Session Level and Conference Address. Also many properties of entities are value objects. Let's discuss Level and what context is required for it to make any sense.

A Level has a value that indicates the difficulty level of the session. It does not have an identifier. Level belongs completely to the Session class. Without Session, Level would have no context and would have no meaning. The purpose of Level is to denote the information that helps attendees of the conference choose what sessions may be appropriate. Being a value object, Level is defined by its properties and methods and has no identifier. It would not make sense to list out a collection or array of Level instances because without the Session, it has no meaning or purpose. Its relationship with other entities gives it meaning. The Session it belongs to and the difficulty level information it includes give it the context to convey meaning in the application, and when some other code needs the session's Level, it must ask the Session instance for the Level. The Session object will hand back this object. Like Level, other types without identifiers are value objects. Value objects are not glamorous and even describing them can be boring. The arrangement of entities and value objects into larger structures can be interesting.

Entities and value objects are useful in separating responsibilities in a domain model, but there is more. If we need to load a Conference entity for the Austin .NET User Group Code Camp, what does that mean? We see that our Conference object can have many Sessions, and that each Session has a Speaker. Going further, a Speaker has a WebsiteUrl property. Tracks, Sessions, and Attendees all have a relationship with a Conference. When we need to deal with a Conference object, must we have all associated objects in memory for any operation to make sense? The answer is no. In DDD, we divide our domain model into aggregates.

Aggregates

Aggregates are groups of objects that work and live together. We group them along natural operational lines, and one entity serves as the aggregate root. The aggregate root serves as the entry point and the hub of operations for all objects in the aggregate. An aggregate can have many objects, or it can just be a single entity, but the aggregate root is always an entity since it must be able to stand on its own, and only entities can stand on their own. In figure 2, we see some of the aggregates for CodeCampServer, with the Conference aggregate in the center.

The aggregate root is the Conference class, and another member of the Conference aggregate is Attendee. This is not the complete Conference aggregate, but it demonstrates some conventions of the aggregate pattern. It may seem trivial that we classify this object in the Conference aggregate, but specifying ownership is valuable.

Figure 2: The conference aggregate

The conference aggregate

We have specified that the Conference type owns the types in the Conference aggregate. Objects in other aggregates are not allowed to have a durable relationship with the nonroot objects in the Conference aggregate.

NOTE

Session holds a reference to Track, which is another aggregate root. Types in an aggregate are allowed to hold references to other aggregate roots only, not to other nonroot types in a different aggregate. For instance, even if only five Attendees could attend a session, Session would not be allowed to have a reference to the several Attendee instances because Attendee is a nonroot type in the Conference aggregate. In short, if a type belongs to an aggregate, types in other aggregates must not hold a durable reference.

The separation into aggregates enables the application to work with domain objects easily. If we did not draw aggregate boundaries, the entire domain model could easily devolve into a ball of spaghetti references. Conceivably, we wouldn't be able to use any objects without the entire object graph loaded into memory. Aggregate boundaries help us to define how much of the domain model is necessary for an interesting operation. For instance, if we want to show conference information on a screen with the location, directions, sessions, and speakers, we don't need to load the entire object graph. We only need the Conference aggregate and the other aggregate roots that are necessary. In fact, if we need only the start and end dates for the conference, we would not even have to load the entire Conference aggregate. Now that we are discussing how much of the object graph to load, you might wonder why we haven't yet discussed persistence to a database.

Persistence for the domain model

For this book, persistence is just not that interesting. Sure, we can imagine how we might load and save these objects from and to a relational database, xml files, web services, and so on, but when designing a domain model, persistence concerns are mostly orthogonal to the model. For most business applications, we'll have to durably save the state of the application somehow, but the domain model should not have to care whether that persistence is to XML files, a relational database, an object database, or if the entire state of the application is just kept around in memory

NOTE

Persistence is interesting and necessary for real applications. We are not discussing specific data access techniques because that topic is orthogonal to the ASP.NET MVC Framework. The MVC framework is a presentation layer concern, and it can work with many data access strategies. Your back-end data access decisions do not change if you use the ASP.NET MVC Framework instead of Web Forms, Windows Forms, WPF, Silverlight, or even a console UI.

Regardless of the persistence mechanism, the domain model includes a concept for loading and saving object state. Notice how we are not talking about loading and saving data. In the domain model, we are concerned about objects, not data. We need to load object state and persist object state. We do that using repository types. In domain driven design, we dedicate a repository to each aggregate, and the repository is responsible for loading and saving object state. The repository performs the operations on the aggregate root only. In the case of the Conference aggregate, we'll work with a type called IConferenceRepository. In figure 3, we see the repository whose responsibility it is to perform persistence operations on the Conference aggregate. For more examples, we have a repository for each aggregate in our domain model. Some of them are listed here:

  • IConferenceRepository - Persistence operations on the Conference aggregate
  • ISessionRepository - Persistence operations on the Session aggregate
  • ITimeSlotRepository - Persistence operations on the TimeSlot aggregate
  • ITrackRepository - Persistence operations on the Session Track aggregate

Figure 3: IConferenceRepository-all persistence operations on the aggregate root

IConferenceRepository-all persistence operations on the aggregate root

Let's examine the Conference aggregate once again as it relates to persistence. Suppose that when managing a Code Camp with this application we add several attendees. In the application we would add Attendee instances to our Conference instance and then pass our Conference to the Save() method of IConferenceRepository. The repository would be responsible for saving the Attendee instances as well because these objects live within the Conference aggregate. The repository's responsibility is to manage persistence for the Conference aggregate, which means every object in the aggregate.

You are probably wondering what mechanism we are using for persistence because we still have not mentioned it. With this book, you can download the full source code and examine the classes that implement our repository interfaces, but for the purpose of exploring the ASP.NET MVC Framework, we find it irrelevant and a distraction to explore the data access code, and we'll keep this book's focus on the presentation layer, which is where the ASP.NET MVC Framework lives. The repository interfaces will provide the objects we need to work with for all the examples in this book, and the controller classes will depend on these repository interfaces as well as other logical service types. Since data access and a screen controller have completely different concerns, a screen controller in this book will never concern itself with how any sort of data access is performed, or that data access is happening at all. A screen controller will call methods on dependencies, which will often be repositories, and when calling the Save() method on IConferenceRepository, the screen controller does not care whether the implementation saves the object in an in-memory cache, an XML file, or a relational database. The controller will merely call the repository and trust that what is behind the interface will work appropriately.

NOTE

No doubt you have seen some examples where controller actions directly contain data access code. With LINQ to SQL being new and growing in popularity, conference talks are featuring ASP.NET MVC Framework demos where a controller action performs a LINQ to SQL query. This works for small or short-lived applications, but it is inappropriate for long-lived business applications because of the coupling. For years, the industry has known that coupling presentation concerns with data access concerns is a recipe for disaster. These concepts gave birth to the well-known data access layer. When using the ASP.NET MVC Framework, a controller is part of the presentation layer. The best practice still stands to avoid putting data access in your presentation layer; any data access concern in a controller action creates technical debt that will put a tax on maintenance for the life of the application.

One benefit that we can capitalize on immediately when separating our data access layer from the presentation and business layers is unit testing. While unit testing our screen controllers, you will notice we frequently fake out the repository interfaces so that they return a canned list of objects as the context for a test. Unit testing controllers should never involve any persistence mechanism or exercise external dependencies. We'll cover the unit testing of controllers in much more detail in chapter 3, but in a unit test, the repository implementation will never come into play. A substitute object will always be provided for the interface. At this point, we have enough information about our domain model to proceed, but the domain model is not the only type of model that we need. The domain model is important because it represents unique concepts in the real world. A conference can have many attendees, so that is how we model it. An attendee describes a person who is coming to the conference, and that is how we represent it in code. Now, what about a schedule listing? When listing the time slots, sessions, and speakers, how do we work with that in the presentation layer (in our screens)?

Presentation model

The domain model represents concepts as they truly are, but often a screen in our application needs a transformed representation of the domain model. For displaying a schedule of a conference, we need a flattened, or projected, model. This is the presentation model, a model that exists only for specific presentation needs. In the case of a schedule, we'll need to show the start time, end time, title, and speaker for every session. We can easily ask the repositories for the objects fully populated, and then we have all objects we need. However, if we place the responsibility on the screen controller for navigating the object graph and pulling all the appropriate pieces out, we are muddying the responsibilities of the controller. If the application is sufficiently trivial, we may let the controller take care of this, but that would be a judgment call for you to make. In CodeCampServer, our controllers will be quite thin. The controller is responsible for coordinating dependencies and forwarding objects for display on to the view. Controller code is code that is coupled to the framework being used for the UI. We want to get away from framework code as quickly as possible. Whose responsibility, then, is it to filter and arrange the conference schedule so it is in a shape suitable for display?

Presentation model responsibilities

This is where the presentation model shows its value. The presentation model is responsible for transforming the domain model into a representation that is useful for the presentation layer, namely, the controller and view. Whereas the domain model is an n-dimension object graph that accurately represents the real world, the presentation model takes these objects and projects them into a flatter model that can easily be represented on a graphical screen.

NOTE

The presentation model can be many things. Ultimately, it is an object model that serves a particular screen, not the entire domain. This object model can be populated in isolation, or it can take responsibility to populate itself when a domain object is passed into the constructor. The presentation model goes in the /Models folder in an ASP.NET MVC Framework application. The presentation model is part of the presentation layer and should not be referenced by the rest of the application. Typically a complex screen will require a presentation model object graph.

Let's revisit our conference listing example. It would not be appropriate for a controller to pass a Conference object to the view and hope the view knows how to traverse the object graphic in order to render the correct information. This is too much responsibility for the view. The controller needs an object that it can send to the view so that there is only one way for the view to render the object or structure of objects. If the view has a decision to make, we have introduced the possibility for a functional bug in the part of the code that is the most difficult to test. We want to pull all decisions back into the heart of the application where they can easily be tested. For this, we'll have ScheduleController use a new object in the presentation model called ScheduleForm. The controller will map a conference into a ScheduleForm instance by leveraging IScheduleMapper. See figure 4 for the ScheduleForm structure.

The ScheduleForm class, along with header information, can provide us with a collection of TimeSlotAssignmentForm objects, each of which are presentation objects and are easy to render. ScheduleForm also has a collection of TrackForm objects. These two collections will form the two axes of the table that the view is going to render for the schedule page. The view merely has to translate the graph of objects into a table. What makes a presentation object easier to render on a screen than a domain object?

Figure 4: The presentation model contains classes specific to a particular screen. Logic that decides how to structure the domain model for presentation on a screen can be factored into presentation model's classes.

The presentation model contains classes specific to a particular screen. Logic that decides how to structure the 

domain model  for presentation on a screen can be factored into presentation model's classes.

Projecting from the domain model

A presentation object is easier to render than a domain object because it discards the natural depth of a domain model object graph and provides a flattened, or projected, interface. In our view, we can ask the ScheduleForm for the two collections of objects that are the headers and rows of the schedule table when rendered to the screen. The presentation model is intentionally structured to naturally represent the presentation of the information. The goal of the presentation model is to match the view's desired structure closely. Figure 5 shows what the full structure looks like.

At the session level, SessionForm is not complicated. The SessionForm is responsible for representing a single cell in the schedule table on the screen. With track on the table header and time along the first column, sessions will be rendered in the appropriate track and time slot. The SessionForm has the properties that will be rendered so that the schedule makes sense.

NOTE

The presentation model is not the only type of specialized model we could use. We have service models, storage models, security models, and messaging models. The common factor among these is that these object models lie at the extremities of the application and enable the application to interact with the outside world. The presentation model helps the presentation layer, which interacts with a human user. A messaging model would represent state and behavior necessary for messaging information to other systems asynchronously. It is conceivable that the UI could even send a message to the domain in a more complex system with large data entry screens.

The difference in these models is portability. Domain model objects are not portable. They are contained within the bounded context where they are useful. Presentation model objects are portable from the application layer up to the UI. A messaging model would be portable for serialization across MSMQ or similar transfer mechanisms. We would not send our domain objects directly in messages because we would end up coupling other systems to the shape and types of our domain model. Instead, the messaging model (call it whatever you like) represents the shape necessary to communicate with the external system or application layer.

The presentation model simplifies the domain model for rendering and helps make the numerous decisions that are necessary for rendering objects. If a controller or view were left with all these decisions, the likelihood of a defect would increase, and the amount of code in the controller or view would grow, causing maintainability to decrease. The presentation model is a key element of the presentation layer and should come into play any time a screen needs to work with an object that is not just an object but a deep object graph. For simple domain objects, or for merely displaying object header information, a presentation model object might not be necessary, but if you find yourself digging into an object graph in our view, pull back and consider introducing a presentation object. The unit tests are easy and quick, and the view becomes much simpler.

Figure 5: The full presentation model for the schedule page. Presentation models usually have primitive properties.

The full presentation model for the schedule page. Presentation models 

usually have primitive properties.

Working with the model

Congratulations! You now understand all you need to know to follow the rest of the examples in this book. Although you could study DDD for years, understanding this small Code Camp domain model is sufficient to master the techniques presented in the following chapters. Now that we understand the model we'll be working with, let's put it together and use our Code Camp domain model. We'll start with a user story: “As a community member, I want to navigate to http://codecampserver.org/austincodecamp2008/schedule so that I can see a schedule of the conference by day, time slots, and track.”

About user stories

User stories are widely used by teams using Extreme Programming and other Agile methodologies. A user story is a placeholder for extensive conversation that takes place between the software customer and the software team. It is the widely accepted practice for a user story to contain a persona (or the type of user) who finds the functionality valuable. The user story describes what the persona wants to do and why. This format helps to keep the team focused on a task that is beneficial to a certain kind of user.

Crafting the route

We know from the previous chapter how to create routes that will map a URL to a particular controller and action. In this case, we are breaking away from the simple {controller}/{action} route in favor of a URL that is obvious and intuitive. Furthermore, we are using a route API from MvcContrib inside of CodeCampServer. Chapter 5 will cover ASP.NET MVC routes in depth. This section focuses on how the model can integrate with the routes. The part of the URL, austincodecamp2008, is actually the unique key that will identify which conference we are dealing with. In other words, for the next Code Camp, the URL might be http://codecampserver.org/austincodecamp2009/schedule, and so on. Since the first token in the URL is dynamic, we have a fairly interesting route, but not difficult to craft. The second token, schedule will denote the controller to use for this request. Now that we have examined each piece of the URL, take note of the entire route added to the RouteTable as shown in listing 1. This code is in the RouteConfigurator class.

Listing 1: A route that maps the desired URL to the proper controller and action

This route has concerns other than ensuring the ScheduleController is invoked. The {conferenceKey}/{controller} portion is the most interesting for now. The constraints ensure that only our conference-centric controllers are available after the conference key. The framework will match the route with the URL and ensure the ScheduleController is executed with the Index action by default.

Crafting the controller action

We are very confident that the Index method of the ScheduleController will be invoked for this request, but we must have our controller in place so that we have a place to add the proper code. We'll create a ScheduleController class in Website/Controllers/ in our solution. We'll then inherit from the Controller base class and create an Index action method. In CodeCampServer, all controllers have a layer supertype (as defined by Martin Fowler in his book, Patterns of Enterprise Application Architecture) called SmartController. SmartController derives from Controller. In your own application, you might adopt your own controller supertype. The shell of the controller class should look similar to listing 2.

Listing 2: The shell of the ScheduleController class

This is the start of our controller class and action that will help display a conference schedule using a view named Index. We'll be leveraging an IModelBinder instance to bind the conference key from route data to a Conference object. Next we need to test drive the logic that will map the conference into the presentation model that is appropriate to forward to the view.

Test-driving the feature

Logic in the application needs to have an automated test to verify that it works correctly. TDD is a technique that helps design loosely coupled, maintainable code while at the same time building up a complete regression suite of automated unit tests. We are going to test-drive the Index action method for our controller. We have added the action method first because we decided on the name when we created the route. To test-drive this functionality, you will need to create an NUnit test fixture in your unit test project. In our project, we'll call it ScheduleControllerTester.cs. Examine the full unit test in listing 3.

Listing 3: Unit test creates mock objects using Rhino Mocks, a .NET mocking library

NOTE

The S method is defined as return MockRepository.GenerateStub<T> (argumentsForConstructor);. It resides on the base class as a shortcut. Because these examples are part of the larger CodeCampServer codebase, it will be valuable for you to explore the code included with this book.

It is important to realize that we are setting up a fake object that implements IScheduleMapper. We are passing this stub to the controller's constructor, and our controller will use it without knowing the difference. It is worth noting that the application uses an IoC, or inversion of control, container to manage dependencies. This means that we have a custom controller factory use our IoC container to create the controller complete with whatever dependencies are declared by the constructor. We'll cover controller factories in greater depth later in chapter 3, but realize that this is a best practice not just for controllers but for C# code in general. You can see the IoC container usage by opening the full solution delivered with this book. In general, a class should openly declare dependencies by requiring they be passed in through the constructor.

To complete this test, we call the Index() method with the Conference object, then assert that the view name and ViewData.Model are correct. We cannot compile at this point because the constructor we need does not exist. Let's add the constructor, run the test, and it will fail as expected in figure 6.

We'll now move back to our controller class, and write the interesting code until our unit test passes. The resulting controller code is shown in listing 4.

Listing 4: The complete controller class for showing a conference schedule

Figure 6: Running the unit test with JetBrains ReSharper shows the test failure, which is what we expect at this point.

Running the unit test with JetBrains ReSharper shows the test failure, which 

is what we expect at this point.

The Rhino Mocks dynamic mock library

When performing automated testing on code libraries, developers and testers find it beneficial to simulate dependencies on which the code relies. By substituting a dependency, the code under test can be evaluated objectively and repeatedly. This technique delivers great results, but the code clutters the readability of the test and the code that results is bulky. This is where mocking frameworks like Rhino Mocks come in. Rhino Mocks can generate derived classes on the fly. This includes interface implementations as well as abstract class derivations. These dynamically created classes can return hard-code values or assert that a particular method is called with specific arguments. You can read more or download at http://www.ayende.com/projects/rhino-mocks.aspx. Oren Eini is the creator of Rhino Mocks, a vibrant open source project with many contributors.

The new code is the constructor and the guts of the action method. There does not appear to be much code, so can it possibly be correct? Is that really all the code that's necessary in the controller? Yes! Let's examine what's going on. First, we are saving our IScheduleMapper in a private field so we can access it later. Remember that we do not care what object is passed into the constructor as long as it matches the type required. Next, we take the Conference passed into the Index method and use it to ask the IScheduleMapper instance to "map" it into an array of ScheduleForm objects. Once we are finished, we'll call View() on the Controller base class passing in our presentation object. This will cause the Index view to be rendered with an array of ScheduleForm objects stored in the ViewData.Model property. To prove that the code we are writing is correct, let's go back and run our unit test to ensure it passes, as shown in figure 7.

Figure 7: With the controller fully implemented, the unit test passes, and we can move on.

With the controller fully implemented, the unit test passes, and we can move on.

Now that you have expertly test-driven a controller action, all that's left is to finish off this feature with a view that takes the presentation object and formats it properly into HTML. In the controller we are creating a ScheduleForm array by passing in a Conference that the IScheduleMapper will project into the shape necessary to render the screen. Although we won't publish the full code of the ScheduleMapper class here, it is useful to look at the structure of the ScheduleForm presentation object graph shown in figure 8. The supporting objects represent the time slots and tracks used to create the visual representation in the view. Using these objects, the view can easily render the schedule.

Finishing the view

We'll get into all the different ways to use views in chapter 4, but for now, we'll take the simple route and not make use of many view helpers. You will learn about view helpers later, but for this feature, we'll stick with simple HTML. Following convention, we'll create an MVC View Page in Website/Views/Schedule/. The rest of the work is just formatting, so we'll format the name of the conference in big letters at the top of the screen and then show the sessions in a table below. If you are curious about the layout used, browse through the solution delivered with the book. Examine listing 5 for the full source for View.aspx.

Figure 8: The complete ScheduleForm presentation model nicely encapsulates the presentation concern that would otherwise have cluttered our controller and view.

The complete ScheduleForm 

presentation model nicely encapsulates the presentation concern that would otherwise have cluttered our controller and view.

Listing 5: A view that formats our presentation object, ScheduleForm, as HTML

Note that we are using <%= operators to output properties of the presentation object. The code in listing 5 is such a mix of server-side code and markup that you might have trouble following it. When we discuss views in depth, we'll introduce techniques to simplify the view and extract even view logic into helpers. You can imagine what this view would look like if we attempted to pass the Conference object directly instead of a ScheduleForm object. To get the speaker name, the view would have to traverse three different object relationships and even perform lookup logic. It would be a mess. The view in listing 5 formats our presentation object and completes the current feature. If you run the application, you'll see a screen similar to figure 9.

Figure 9: When we run the application, we see our controller and view work as intended. With a well-defined domain model and presentation model, the controller and view can become quite simple. Test data is used; the session names are not descriptive.

When we run the application, we see our controller and view work as intended. 

With a well-defined domain model and presentation model, the controller and view can become quite simple. Test data is used; the session 

names are not descriptive.

Summary

You have just completed a whirlwind tour of the M in Model-View-Controller. Key takeaways from this chapter are understanding both the importance of a rich domain model and when a presentation model makes controllers and view simpler. The domain model represents concepts as they exist in the real world. The names should be the same, the operations (methods) should be the same, and the relationships should mirror how the concepts are used in reality. With an intelligent domain model, the application has a solid core to build around.

Left to work with aggregates alone, the controller must take the responsibility for extracting information out of the object graph for the view to render. This makes the controller more complicated and harder to test. Complexity and difficult testability both result in more costly maintenance. This is where the presentation model comes in. Use presentation model objects to project a deep domain object graph into a flattened view that is easy for a view to render. Creating these presentation objects is a snap for a controller, and when used properly, test-driving controller logic becomes easy and predictable.

With a proper model in place, the controller and view are straightforward. As you build your applications around the ASP.NET MVC Framework, do not forget the paramount importance of the model. Model comes first in the pattern name, and it should come first in your application. If you take shortcuts with the model, the controllers and views are going to be much more difficult to manage. The model is the core of each layer in the application. If the core is rotten, the entire application will soon smell quite bad.

Get 30% discount

DotNetSlacker readers can get 30% off the full print book or ebook at www.manning.com using the promo code dns30 at checkout.

<<  Previous Article Continue reading and see our next or previous articles Next Article >>

About Manning Publications

Manning Publication publishes computer books for professionals--programmers, system administrators, designers, architects, managers and others. Our focus is on computing titles at professional levels. We care about the quality of our books. We work with our authors to coax out of them the best writi...

This author has published 33 articles on DotNetSlackers. View other articles or the complete profile here.

Other articles in this category


jQuery Mobile ListView
In this article, we're going to look at what JQuery Mobile uses to represent lists, and how capable ...
JQuery Mobile Widgets Overview
An overview of widgets in jQuery Mobile.
jQuery Mobile Pages
Brian Mains explains how to create pages with the jQuery Mobile framework.
Code First Approach using Entity Framework 4.1, Inversion of Control, Unity Framework, Repository and Unit of Work Patterns, and MVC3 Razor View
A detailed introduction about the code first approach using Entity Framework 4.1, Inversion of Contr...
Exception Handling and .Net (A practical approach)
Error Handling has always been crucial for an application in a number of ways. It may affect the exe...

You might also be interested in the following related blog posts


Using T4MVC strongly-typed helpers with Telerik Extensions for ASP.NET MVC read more
Spec Explorer: A Model-Based Testing tool read more
12 ASP.NET MVC Best Practices read more
MvcContrib working on Portable Areas read more
RELEASED ASP.NET MVC 2 Preview 2 read more
Html Encoding Code Blocks With ASP.NET 4 read more
Presentation Models: Cohesion read more
Business Apps Example for Silverlight 3 RTM and .NET RIA Services July Update: Part 25: ViewModel read more
MvcContrib version control has moved to GitHub read more
How to use Ninject 2 with ASP.NET MVC read more
Top
 
 
 

Please login to rate or to leave a comment.

Free Agile Project Management Tool from Telerik
TeamPulse Community Edition helps your team effectively capture requirements, manage project plans, assign and track work, and most importantly, be continually connected with each other.