Clean Up your Query String and Use Inline Forms to Pass Data (PostActionLink)

The Challenge

One requirements for my latest MVC application was that no data sensitive be passed via the query string. This includes elements like IDs, Usernames, Email, etc. Many of the MVC examples use the query string to pass value type data between screens. I needed a reusable method to add links to the screen which could pass information more securely and not require a ton if code.

An example use case is the need for “Edit” and “Delete” links on each record of a data list as seen below:

The default MVC Route suggests that IDs should be placed in the query string, and any additional information be added as additional values afterward. This is an easier method, but its far less secure and leaves a rather messy query string such as this:
[sourcecode language=”plain”]
http://www.mysampledomain.com/contoller/action/1047?email=contact@email.com&type=administrator
[/sourcecode]
Obviously there are ways to minimize the data in the query string, but what if you need to remove the information altogether? What if you use Guids for object IDs instead of integers? Here’s the solution that worked for me…

The Solution

Handling Your Routes

The Visual Studio template MVC application (as well as most sample applications) set the default Route as the following:
[csharp]
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
[/csharp]
This works well if you have a database whose objects have a key with a datatype of integer. A simple integer value type looks cleaner in the query string over something such as a GUID. However, most developers who have been around the sun a few times know that having incremental integers as ID always the best plan, and certainly not the most secure. Displaying integer IDs to the world in the query string is even more risky. Anyone with a few extra minutes and a little programming knowledge can increment the number in the URL until they gain access to a different set of information than was intended.

In order to prevent this from happening, the first thing we do is remove the ID field from the route.
[csharp]
routes.MapRoute(
"Default", // Route name
"{controller}/{action}", // URL with parameters
new { controller = "Home", action = "Index" } // Parameter defaults
);
[/csharp]
From here on out, we need to manually pass IDs and information from screen to screen.

From Get to Post

Since we are abstaining from using the query string to pass information, we must use the post action to get elements of data from page to page. I’ve seen a number of different methods for handling this type of situation, and all have their upsides and downsides. For this example, we’re going to use an Html Helper to create an inline form to wrap around a plain link.

Html Helpers

Html Helpers are similar to user controls in that they render small chunks of markup that can be used anywhere in the application. In this case, we need to render a form, with a dynamic list of hidden fields and a way to submit it. Shouldn’t be too painful, right?

Create the Helper Class

We need three main elements to make this concept function: a form, hidden fields with data, and a method to submit that form. The form created by this helper also needs to be able to exist on pages without interfering with existing functionality.

In order to keep things consistent and easy to find, I create my “HtmlHelpers” class in my <Project>.Web.Display namespace. I use this namespace is exclusively for Html Helpers and other functions which output HTML or other type of string element to be rendered by the browser.

To construct the form, we need to determine where to send the information. The first parameters in my PostActionLink helper method allow the Action, Controller, and Area to be passed in for just this purpose. Next, a simple Dictionary object is all that is needed to capture simple name/value pairs for hidden fields

Next, the Form Element is constructed using the TagBuilder class. The form ID is set to a new GUID in order to ensure no conflict can occur with other form elements in the page that implements this helper.

Lastly, the link to submit the form is added. This could just as easily be a button, image, DIV or SPAN as the concept is the same. The Onclick event of the link is used submit the form. A jQuery selector uses the defined Form ID GUID to find the form specific to this helper and submit it. The “return.false” prevents the anchor tag from executing its HREF action which, for this implementation is not defined.

NOTE: In order to use the jQuery selector, the jQuery libraries must be referenced on the page that implements this helper. If jQuery is not available, “document.getElementById()” can be used in its place.

The form tag can now be closed and the response rendered to an MvcHtmlString using the create method.

One method for adding form fields to the dictionary is to add the dictionary items inline. This is a great method if you have one or two items to add, but it’s easy to see how any more can become quite cumbersome.