In this tutorial, you will learn how you can post data back to a controller using a surface controller. Mastering Surface controllers will make your life easier when working with forms in Umbraco. I've written about route hijacking before within an Umbraco website. Route Hijacking, will tel your website how to route a virtual page request to your MVC controller.
What is a surface controller?
When we work with plain old MVC, controllers are defined by creating a class and inheriting from 'Controller'. A surface controller is an Umbraco specific controller. If you use Reflector to look at the surface controllers base code you will notice that it inherits from the normal MVC controller. A surface controller can do everything a normal MVC controller can do. The reason why you'd use a surface controller is that it does some extra Umbraco specific features behind the hood when it comes to works.
To be really clear, if you have a web page and the only thing you want to do is display some text, then use RenderMvcController, or, a normal MVC controller. If you need a page that has a custom form on it, like a login form, a contact me form, or a search box uses a surface controller.
Before we go into some code, it's probably a good idea to talk about what exactly these Umbraco related things are. The two-bit points are, a surface controller has access to the current page Umbraco object.
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 (like MVC). This class will need to inherit from the SurfaceController.
The code above is pretty straightforward. I've defined two actions, one to render the page and one to deal with a form submission. It's the surface controllers job 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 missed out a lot of code. If you want to create a log-in page, then I suggest you read, How To Create a Login Page With Umbraco 7 which will fill in all the gaps.
If you tried to post back to a controller without it inheriting from the Surface Controller, Umbraco wouldn't know which controller to call. 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 I did as well. 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 is used in a partial controller
- An action to handle the submit, which has to use [HttpPost]
Your view would then look something like this:
This is a very simple example, you will need to use the 'BeginUmbracoForm' helper to get started. One even stupid thing I did the first time I tried to implement a surface controller, we to accidently leave a HTML tag in between BeginUmbracoForm. Do NOT do this because it will screw everything up!
I encountered the following error :
'Can only use UmbracoPageResult in the context of an Http POST when using a SurfaceController form'
If you need to get information back from your users, whether it be a form, a log-in page etc.. you will need to use a surface controller in order for the postback to call the correct controller.
As you can see from the code above, except for a few differences like the name you have to call your controller and the type you inherit from, the code looks pretty much the same as a standard MVC 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.