In this tutorial, you will learn how to create a basic log-in page within a Umbraco CMS powered website. In this guide, you will learn about the SurfaceController what it is and how you can use it. You will also gain access to all the code required to build a simple log-in form using MVC. If you need to implement a restricted members area within your Umbraco website, read on 🔥🔥🔥

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. As seen below:

With the skeleton code for SurfaceController covered, let us 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:

To create a surface controller inherit from SurfaceController. You will need to implement three actions, a standard Index action to render the log-in view, a log-out action (does what it says on the can) and a validate action to process the log-in attempt. The validate action will be used to try and log the user into the website. If the credentials are successful the user will be re-directed to the homepage. If the credentials are invalid, the site visitor will be presented with an error message. Notice the names within the ActionName attribute. These action names are important to note down as you will need to use them within the HTML. You will not need to use Index or Validate directly. Also, note on Line 28 the use of TempData. This is used to pass data from the controller back to the form. In here you can add any validation or warning errors.

One word of caution, getting controller and action names correct is important. If you use the wrong name or make a typo in your HTML you will encounter this error:

Could not find a Surface controller route in the RouteTable for controller name xxx.

If you encounter this type of error, check for typos!

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

The view uses the view model we created as the backing model type. On Line 4, I use IsAuthenticated to determine which snippet of HTML to display to the user. If the user is logged in, they will see a logout button that will call the LogOut action in the surface controller. If the site visitor is unauthenticated, they will see the log-in form. On-Line 15, I use BeginUmbracoForm to create a mapping between the form and our surface controller. BeginUmbracoForm uses generics so T needs to be the name of the surface controller. The parameter is the action method name it should call so in this example MemberLogin

On-Line 21, I use TempData to render text log-in status information back to the user. TempData is a useful way to pass dynamic data between a controller and a view. Another way of doing this is by adding an error message property to the view model. I have used this approach so you can see the two options you can use to post data back to the HTML. Using TempData is easier to get working so it is the approach I recommend that you use. Use the technique that makes you happy 😊

Page Controller: A surface controller is a component level controller. A surface controller will not have a direct page URL to access it. As a surface controller in essence is a component, you need to add the command to render the log-in form partial view in the document-types view where you want it to appear. Rendering a partial view within the ASP.NET framework is done using the Action HTML helper, like this:

You should now have the partial view rendering on your page. When someone submits the form, the data will be posted back to the surface controller. If the details are valid a redirect happens. If not a message is returned using TempData and the form is updated. Job done 💥.


If you followed this tutorial, you should now have a simple web form that will log a user into your Umbraco website. You can download the code from this tutorial, from #ILoveUmbraco. Happy Coding 🤘