In this tutorial, you will learn how to create a contact us for m within Umbraco CMS.

Surface Controller

If you have experience in building sites using vanilla ASP.NET Framework MVC, you will be aware of the Controller base class. To create a new controller, you inherit from this special type and things magically work. To create a log-in form you need two things, a way to render the form and a way to deal with the data posted back to the server. Within a Umbraco website, the page routing rules are more complicated compared to a normal MVC site. A page URL does not directly map to a controller and an action. A Url maps to a virtual page that lives within a database. The controller used to render any Umbraco page is based on the document type that was used to create it. This means a mapping needs to be made on each page request between the virtual page and the controller required to render it.

The handy thing about Umbraco is all this routing is usually taken care of for you. As a developer, all you need to do is write code and things magically work. How do you deal with posting back data to a Url? As the Url does not map to a controller, posting back data will simply result in a 404 error 🤔

To post data back to the server, you need a routing rule to exist to map the request to a controller. You could create a custom rule yourself that allowed a form to successfully post data back to the server. Creating a rule for each and every form is not ideal. This is why Umbraco CMS ships with a special controller called the SurfaceController. Using this controller will automatically hook up all the routing rules for you in the background.

When you build forms with Umbraco, always think SurfaceController 😊. A surface controller also provides access to some useful Umbraco objects, like the current Umbraco page. Due to the automatic routing and the access to useful Umbraco properties, using a surface controller is more useful compared to manually having to hook everything up in code yourself. The code to create a basic SurfaceController is similar to a normal controller.

Surface controller are key in getting any custom form to work in Umbraco. Let us now go over the other components required to build an MVC form in Umbraco:

View Model: To design a well-architected MVC website, we will need a view model to pass the data from the form to the controller and vice-versa. In this example, the view model will look like this:

Controller: The next step is to add the logic to the controller to process the log-in attempt and return the correct HTML. The code to do this is shown below:

In the controller, we define two actions, an index action to render the view and a SubmitForm action to process the  data. In the SubmitForm action note how you can still use vanilla MVC validation. This action uses the ValidateAntiForgeryToken attribute to prevent cross-site scripting attacks. It also uses the IsValid property to validate the submitted contact form details are valid.

I have omitted the code to process the form as this will be custom to your needs. I assume you may want to send an email, or submit the data in a database table. On Line 16, I use TemmpData to pass information from the controller back to the form. TemmpData is handy to pass validation warnings and those types of messages back to the view.

Partial View: A surface controller is a component controller rather than a page level controller. In order to render the contact form HTML you can use a partial view. In my partials folder, I create a view called ContactForm.cshtml. The contents look like this:

On Line 9 we use TempData to render any messages added within the controller within the TempData object back to the visitor. I use the vanilla MVC helpers @Html.ValidationSummary(true) and @Html.AntiForgeryToken() for security.

The final piece of the puzzle is to render the form on a page. Remember, a surface controller is a component controller. The rules are different compared to a standard RenderMvcController. RenderMvcController will have a direct URL to access it. You can use this URL to perform route hijacking to call the controller. When you use a surface controller you will not have a direct URL to load the form. Instead, you render it on a page as a component. In ASP.NET Framework, components are rendered as a partial view. A surface controller needs to be placed on a page rather than accessed directly. In this example, you can render the form using this snippet:

In order to build a form in Umbraco, use the surface controller. The surface controller has special methods and properties that hook into Umbraco. A surface controller will auto hook up the routing so you can easily post form data back to the server. The important thing to note is that a surface controller is a component controller and not a page controller. You render it on a page rather than access it directly. Happy Coding 🤘