Render Online Forms with ASP.NET MVC Display Templates and The Code Generator—Part 1

   —   

This how-to article explains how Kentico Online Forms are included in the Dancing Goat ASP.NET MVC 5 sample site by using best practices. Those practices include usage of the view model design pattern, the repository pattern, strongly typed MVC display templates, partial views, and the System.ComponentModel.DataAnnotations attributes. The second part of the article will introduce a new community project—a Kentico module that would further automate the implementation of Kentico Online Forms (and possible other FormEngine data) in MVC sites. The second part of this article will also tell you how to create a new Online Form in Kentico from scratch and how to include it in an MVC site.

Note: The article was adjusted to support Kentico 10!

Here you can navigate to the Part 2 of this article.

One of the best use cases for MVC is displaying well-structured, strongly-typed data. In Kentico, an example of such data is Online Forms’ items. The idea behind this article is: Why should a developer write lots of code when there is built-in functionality, in both MVC and Kentico, that can save him/her from custom coding?

Let me explain some of the basics of MVC, how our Dancing Goat MVC sample site is implemented, and how Online Forms play in the big picture of the sample site and Kentico platform.

A Bit of ASP.NET MVC Background

In contrast to ASP.NET Web Forms, ASP.NET MVC allows the developer to have full control over the emitted HTML code. But, at the same time, it allows the leveraging of the easy-to-use display templates and editor templates for any model that is passed to the view by the controller.

For MVC beginners, the simplest description of those templates would be:

A display/editor template is an HTML/Razor or C# code that is designed for rendering the HTML code of a specific .NET model class. There are pre-defined templates in the MVC stack and the developer can also create her/his own templates. Once a class appears in the (view) model, MVC gets the associated template (using naming conventions) and renders it automatically.

There is an older but excellent article series on the topic written by Brad Wilson. Brad is a former Microsoft employee who had taken part in the development of MVC and xUnit. The series is short (five parts, about an hour of study) and it is literally a prerequisite to this article. It is, indeed, very good reading material!

A Short Excerpt of the Articles

For those that still wish to be teased into reading the series, the following text is the shortest possible excerpt of the articles.

With the following model:

public class Contact { public string FirstName { get; set; } public string LastName { get; set; } public int Age { get; set; } }

… and the following view:

@model Contact @Html.DisplayFor(model => model.FirstName) @Html.DisplayFor(model => model.LastName) @Html.DisplayFor(model => model.Age)

… the resulting HTML would look like:

Almost no other coding is necessary. And the same can be done with just:

@model Contact @Html.DisplayForModel()

And when the DisplayFor or DisplayForModel is replaced with EditorFor or EditorForModel, the output looks like the following:

ASP.NET MVC knows the type of each component of the model and chooses a display template or editor template automatically.

Moreover, the true beauty of MVC comes with System.ComponentModel.DataAnnotations. When the model gets decorated with the DataAnnotations attributes, MVC is smart enough to handle most of the formatting and validation with minimum to no effort.

For example, if we added a newly decorated property:

[EmailAddress] public string Email { get; set; }

… then, MVC would not only render it as a hyperlink but, in editor mode, enforce all the required validation rules for an email address format.

There is an example in Brad’s articles of all that can be achieved just by using the built-in ASP.NET MVC and the DataAnnotations functionality, without any custom HTML, Razor or C# code involved:

To fully customize the HTML, all that’s needed is to add a display/editor template file into the proper folder in the MVC site.

If the model consists of other models (by using composition or aggregation), MVC will handle that. All that’s needed is to define how deep (or shallow) the rendering should be.

This was just a teaser for Brad’s series. I really recommend reading it first. Otherwise, the following text wouldn’t be able to show the real power of it.

A Bit of Kentico Background

On the Dancing Goat MVC sample site (DG for short), the pages are rendered with the help of generated model classes of the content only Page Types. Apart from these classes, there are also artifacts such as HTML helper methods, view models, repositories, or an IoC container in play. It can be seen that the DG site follows the best practices in the industry and, of course, all other MVC solutions can follow them too.

Before we get to the Kentico module, let me quickly explain how the DG site processes pages. Then, I’ll also demonstrate that an Online Form is also treated with these above-mentioned artifacts, just like the other data in the page. Then I’ll show that with Online Forms, the editor templates and DataAnnotations really start to shine.

The Process of Rendering Pages

The overall process of displaying an MVC page can be captured in the following diagram. The diagram shows the basic scenario of a GET request.

Legend:

  1. The controller accepts a GET request and selects the appropriate ActionResult method
  2. When the data properties in the controller have to be instantiated, the IoC container decides which specific repository type will be instantiated
  3. The IoC container then returns the appropriate data to the repositories
  4. The controller gets those repository models from the repositories and compiles a view model out of them
  5. The controller selects the appropriate view with some potential partial views
  6. The controller puts the view model data into the view and returns the resulting HTML code to the user agent

For a detailed explanation, I will now use an existing page in the DG site as an example, the Contacts page.

It displays both:

  • an Online Form and
  • the ordinary text and images of the page.

In the DG site, the Contacts page is handled by the ContactsController controller class. The GET request is handled by the Index() action result method. This method (and its back-end methods) builds its view model, selects the default view, and passes the view model into it.

The View Model Design Pattern

The concept of a view model is not proprietary to Kentico. It is a general best-practice design pattern. Its purpose is to compose a well-structured package of data that is only required by a particular view.

In the background, the index view model of the Contacts page is composed of models for the company’s contact information, cafes, and the message model. The message model is the representation of our Online Form.

The GetIndexViewModel() method loads data from repository fields created using the Inversion of Control design pattern (IoC).

Again, neither the repository pattern nor the IoC are proprietary. Kentico’s DG site just follows the industry’s best practices.

The Repository Design Pattern

This pattern allows us to decouple things and abstract from the specifics of the data source, which serves the data to the controller class. It works in close alignment with the IoC pattern (see below).

In plain English, instead of instantiating the class generated in the Page Types application, the controller instantiates repository classes (with the help of the IoC and repository model classes). The controller then doesn’t have to know anything about Kentico and the developer can let the application swap Kentico classes with any others.

The Inversion of Control (IoC) and Dependency Injection (DI) Design Patterns

The aspirations of this paragraph is not to describe IoC and DI in full. It will just be described how IoC is used in this case to implement dependency injection.

The idea behind IoC and DI is that the data in the fields shouldn’t always be of a specific class that’s retrieved from the database. These patterns were invented so that the methods of one class (the controller class in our case) should be usable (testable) with other data coming from some in-memory, XML or other data sources. An IoC container can be instructed to persist parts of the site’s content using mock classes into .csv files or, for example, through Entity Framework. The container can dynamically select data sources depending on the current context (development versus production, running on Azure versus running in Amazon, etc.)

It works in the way that the controller class contains private read-only, interface-defined fields that can be instantiated only through the constructor. Then there’s a parametrized constructor that accepts data conforming to interface that both the database-originated class and the test-data-originated class implement. And in the background, there is an IoC container (AutoFac in our case) that intercepts and handles all requests for constructing objects. Upon each instantiation request, it passes the appropriate objects of appropriate specific repository classes to the controller’s constructor, depending on the current context (production/test runs).

In the DG project, there are repository classes that implement the interfaces in the way that they simply map the properties of repository models to the respective properties of the classes generated in the Page Types application in the Code tabs of various page types (café, contact, country, etc.)

So, the overall point of the repository pattern is to decouple from the specifics of Kentico or a database engine. And the point of IoC is that the IoC container listens in the application to fill the controller fields with repositories conforming to a common interface.

All the above design patterns are not only used to display data off the Kentico database, but also in the opposite direction – to gather data via Online Forms and put them to the database.

The Implementation of the Online Form

The form is represented by the mFormItemRepository field. Its class binds the properties of the MessageModel repository model class to the DancingGoatMvcContactUsItem class’s properties at runtime. The view of the Contacts page includes a partial view of the Online Form. The view model has the Message property of the aforementioned type MessageModel.

The _SendMessage.cshtml partial view belonging to the form has this simple code:

@model DancingGoat.Models.Contacts.MessageModel @using (Html.BeginForm("SendMessage", "Contacts")) { @Html.AntiForgeryToken() <div class="FormPanel"> @Html.ValidationSummary(true, "", new { @class = "ErrorLabel" }) @Html.ValidatedEditorFor(model => model.FirstName) @Html.ValidatedEditorFor(model => model.LastName) @Html.ValidatedEditorFor(model => model.Email) @Html.ValidatedEditorFor(model => model.MessageText) <input type="submit" value="@ResHelper.GetString("General.Submit")" class="btn btn-primary" /> </div> }

The MessageModel repository model class looks like this:

using System.ComponentModel.DataAnnotations; namespace DancingGoat.Models.Contacts { public class MessageModel { [Display(Name = "General.Firstname")] [DataType(DataType.Text)] [MaxLength(200, ErrorMessage = "General.MaxlengthExceeded")] public string FirstName { get; set; } [Display(Name = "General.Lastname")] [DataType(DataType.Text)] [MaxLength(200, ErrorMessage = "General.MaxlengthExceeded")] public string LastName { get; set; } [Required(ErrorMessage = "General.RequireEmail")] [Display(Name = "General.EmailAddress")] [EmailAddress(ErrorMessage = "General.CorrectEmailFormat")] [MaxLength(100, ErrorMessage = "DancingGoatMvc.News.LongEmail")] public string Email { get; set; } [Required(ErrorMessage = "General.RequiresMessage")] [Display(Name = "General.Message")] [DataType(DataType.MultilineText)] [MaxLength(500, ErrorMessage = "General.MaxlengthExceeded")] public string MessageText { get; set; } } }

The last thing to show is the KenticoFormItemRepository repository class.

using CMS.OnlineForms.Types; using DancingGoat.Models.Contacts; namespace DancingGoat.Repositories.Implementation { /// <summary> /// Represents a collection of form records. /// </summary> public class KenticoFormItemRepository : IFormItemRepository { /// <summary> /// Saves a new form record from the specified "Contact us" form data. /// </summary> /// <param name="message">The "Contact us" form data.</param> public void InsertContactUsFormItem(MessageModel message) { var item = new DancingGoatMvcContactUsItem { UserFirstName = message.FirstName, UserLastName = message.LastName, UserEmail = message.Email, UserMessage = message.MessageText, }; item.Insert(); } } }

There is almost no other code in the project that deals with HTML formatting or the validation of this form. There’s just the ValidatedEditorFor() HTML helper extension method mentioned in the above partial view. But it is just a wrapper of helper methods for a label, editor control, and validation message. Nothing else.

So this is the beauty of ASP.NET MVC display/editor templates: very feature-rich, out- of-the- box functionality that has absolutely no constraints while also offering easy to use display templates with all the strongly typed goodness such as IntelliSense™.

Final Words

The article (together with Brad Wilson’s articles linked above) showed how flexible and extremely rapid the MVC development can be when using the display/editor templates and the DataAnnotations attributes. The article also explained how the Kentico Dancing Goat MVC sample site uses the industry best practices: view models, repositories, and IoC. I’ve also shown which artifacts in the DG site were used for processing page data, with relation to Online Forms.

Teaser for Part 2

Be sure to check out Part 2 of this article in the upcoming weeks. I’ll prepare a preview version of a Kentico module that can generate the repository model code and partial view code of Online Forms created in Kentico administration UI. I’ll publish the project on GitHub so that we all can contribute to it!

Applies to:

Kentico 9, Kentico 10

Share this article on   LinkedIn Google+

Jan Lenoch

I'm a developer advocate for Kentico Cloud. I listen to Kentico Cloud developers' voice. I manage our forums, prepare polls and I publish technically oriented articles. I also give feedback to the internal teams about developers' experience.