In this tutorial, you will learn how you can post data back to a web server within a Umbraco CMS-powered website using a surface controller. Mastering Umbraco Surface controllers will make your life easier when working with forms. The surface controller is a special type of controller that ships with Umbraco that deals with postbacks. In order for this surface controller to work, something called route hijacking I used. Route hijacking is a specific Umbraco term for using a controller in your website. If you are new to route hijacking, you can learn more here. If you want to learn more about forms and Umbraco, read on!

What Is A Umbraco Surface Controller?

When we work on a vanilla ASP.NET MVC website something called a controller is used to define pages. Controllers are defined by creating a class and inheriting from a special type called Controller. In the same way that vanilla MVC defines its own controller, so does Umbraco. A SurfaceController is a Umbraco specific controller. If you use Reflector to look at the surface controllers base code you will notice that it also inherits from the normal MVC Controller. This means a surface controller can do everything a normal MVC controller can and more. The reason why you would pick SurfaceController over a normal Controller is that it does some extra Umbraco specific features behind the hood. Most importantly, routing! The Umbraco controller also contains properties that will give you access to the current page Umbraco object.

SurfaceController is not the only controller that ships with Umbraco. If you just need to render some text on a page without posting back to the server, you should use RenderMvcController instead (more info here). If you need a page that has a custom form on it, like a login form, a contact me form or a search box using SurfaceController.

One thing to note when using SurfaceController is that it needs to be used on components/partials. It is not meant for page-level routing. If you try that you will encounter 404 errors when posting back! Always reference your form components within the view of a Umbraco page!!!!

How To Create A Surface Controller

To create a surface controller, create a new class in your projects Controllers folder. Your controller's name needs to always end in Controller.cs, so HomepageController.cs. This is an ASP.NET MVC requirement and not some special Umbraco requirement. This class will need to inherit from SurfaceController. The code to do this is shown below:

The code above is pretty straightforward. I've defined two actions, one to render the page and one to deal with form submissions. SurfaceController defines some code that will allow the form submission action to correctly route with the right parameters when a website visitor submits a form. In the example above, for brevity, I've kept the HTML to a minimum. If you want to see the code to create a working component, I recommend reading, How To Create a Login Page With Umbraco 7 which should fill in all the gaps.

If you tried to post back to a controller without inheriting from SurfaceController, Umbraco would not be able to do the routing unless you specifically define a rule within the routing table (normally done in RouteConfig.cs). Writing Umbraco MVC, as you can see is very similar to normal ASP.NET MVC. Getting the Surface controller to post back and submit can take a while to get right. If you are struggling don't worry as the first time I tried to do this it took me ages! if you are struggling to get the routing to work, below lists some useful tips:

  • The display action and the post-submission action names need to be different. If you don't do this Umbraco can get its knickers in a twist
  • A surface controller isn't used on a page. A surface controller should be used as a component on a page. The form component needs to be located on a page. The SurfaceController can be thought of as a partial controller
  • To handle the submit, the submit action needs to be decorated with [HttpPost]

Assuming you have a working controller, you will need a view to render the HTML. Your view will need a form and could look something like this:

Notice on Line 3, BeginUmbracoForm is used to define the form element. This will render the correct tags and configurations for you. A stupid thing that I did on my first form, was to accidentally add an extra form HTML tag in-between BeginUmbracoForm, Do NOT do this because it will screw everything up! If you do that, you will encounter the following error :

Can only use UmbracoPageResult in the context of an HTTP POST when using a SurfaceController form

That pretty much sums up the basics of creating a form in Umbraco. If you want to post information back using a form on your site use a SurfaceController. As you can see from the code above, except for a few differences like the type you inherit your class from, the code looks pretty much the same as a standard MVC form controller. This is because Umbraco isn't rewriting the rule book, instead, it's working with the framework and adding hooks in at certain points. Happy Coding 🤘