Archive for mvc

ASP.NET MVC Pro’s and Con’s

In our current iteration of improving our software development strategy, ASP.NET WebForms simply doesn’t fit in with the new demands of being unit testable and flexible. It comes as no surprise that ASP.NET MVC has been getting all the headlines lately. Like many others, I’ve gotten the itch to try it out. In this post I’ll talk about what I believe are the main pro’s and con’s of the new style for building web applications.

Scale

PRO - No ViewState or "surprise crap"

In traditional ASP.NET WebForms, the luxury of pretending to behave like a Windows Form comes at a price. The ViewState is a reliable way of storing all of the state information for the form. Unfortunately, due to the limitations of the web, this data needs to be a giant string inside of a hidden form field. This ends up adding a substantial number of bytes to the page, making it slower and requiring extra bandwidth. Of course the ViewState is controllable, much like the dinosaurs in Jurassic Park.

Not only is the ViewState gone, but "mystery" generated HTML is also gone. You have strict control over the HTML. This gives you great power, but with great power comes great responsibility. Use it wisely, and you will have elegant XHTML output with no surprises. You need to really know your HTML, which in today’s web world is a prerequisite anyway.

PRO - Faster server-side

It’s hard to get any real performance data about MVC, but it’s been suggested that it’s potentially 8000 times faster. Supposedly it’s due to less processing since it simply processes a "template" instead of having to build a complicated control tree. Even if it’s twice as fast, or even marginally faster, that would be significant for popular sites, or give at least a slight boost to smaller sites.

PRO - Simplified model for multiple related views

One thing that I found much easier to do with MVC was to have multiple versions of a page that displayed the same data, but in a slightly different format. For example, on my RSS package tracking website, you can look at your tracking information in a full-featured desktop browser, a mobile browser, or an RSS reader. The data being displayed is always the same, but the actual rendered output was different. If I later want to make an iPhone specific version for example, I would simply make a new view, and use an existing controller action.

PRO - Unit testable

One of the biggest challenges with WebForms was that testing was difficult. Not only was the actual output not easy to test, but the code-behind would tend to be a place that would contain important code that would never get unit tested. With both MVC and WebForms, it’s best to keep your logic away from the page, but it’s not always easy or ideal. MVC makes it simple to unit test the logic that is specific to a page. To do so, you simply test the actions in your controllers, which are regular, easy to test classes.

CON - Difficult to convert an existing site

MVC is not only a framework in this case, but a style. It is possible to convert specific pages as needed, but the cost is high. The problem is that MVC is radically different, so the benefit of converting probably isn’t worth it for most of your existing pages.

If you decide to convert your site to MVC, you may also run into issues trying to maintain existing page addresses. The specific issue I’ve ran into is that routes cannot have a trailing slash. If you want to maintain existing URL’s that have trailing slashes, there is no way to have the built-in routing generate URL’s with a trailing slash. You may end up losing one of the big advantages that MVC has to offer.

CON - Not best for SEO out of the box

I’ve mentioned some of the SEO issues before, and all but the trailing slash issue have a reasonable workaround. The routing engine likes to allow multiple addresses to render the same page, instead of enforcing a single address for each page. Luckily, as Scott Hanselman mentions, you can use a URL rewrite engine to bend it to your will. I highly recommend spending some time writing intelligent rules that perform the necessary 301 redirects, because you don’t want to take chances with SEO (Search Engine Optimization).

CON - Challenges if you’re not running IIS7

It’s clear that the last couple of versions of IIS have been major improvements over their predecessors. IIS7 takes .NET integration to an entirely new level. There is already a good page that covers the challenges you’ll face if you’re not running IIS6. I’ll just list them here for brevity:

  • .NET needs to handle all page requests to ensure that the MVC pages will be processed. This leads to bad performance of static files.
  • HTTP Compression through IIS6 doesn’t work, because the MVC pages are dynamic.
  • The homepage gives a 404 when hosted on the root of a domain.

Summary

If I needed to build a new site from scratch, and was able to use IIS7, it would be extremely likely that I would choose ASP.NET MVC. It’s a joy to work with (possibly because it’s "new"), and just makes sense. If I needed to work with an existing site, I would certainly have to consider the pro’s and con’s I mentioned above. ASP.NET MVC gives us an amazing new tool in our huge Microsoft toolbox.

Removing duplicate page addresses in MVC

As I mentioned before, there are a couple of SEO issues with MVC. I’ll discuss two ways to get around the trailing slash issue. Recall what the issue was. MVC will happily serve up your URL’s both with and without a trailing slash:

  • www.test.com/path
  • www.test.com/path/

Search engines could potentially index both paths, and count them separately in their search results. The first solution is to make one of the versions return a 404 (page not found) response code. Hopefully, this would deter anyone from linking to the non-preferred version. We can do this by creating a custom route constraint, by implementing the IRouteConstraint interface:

public class TrailingSlashConstraint : IRouteConstraint
{
	private readonly bool _trailingSlash;

	public TrailingSlashConstraint(bool trailingSlash)
	{
		_trailingSlash = trailingSlash;
	}

	public bool Match(HttpContextBase httpContext, Route route, string parameterName,
		RouteValueDictionary values, RouteDirection routeDirection)
	{
		return _trailingSlash == httpContext.Request.Url.LocalPath.EndsWith("/");
	}
}

Then, when you define the route, supply an instance of the constraint:

routes.MapRoute("mobileVersion", "m",
	new { controller = "home", action = "mobile", id = "" },
	new TrailingSlashConstraint(false));

The second solution is to redirect the non-preferred version to the preferred version. We can do this by either creating a custom HTTP Module, or by using a canned product like the free UrlRewriter.NET.

Should I use a trailing slash or not?

This is one of the problems with MVC. In ASP.NET webforms, you could use a default page to avoid having to specify a file in the URL. This gets you the nice MVC style paths. The good part was that if someone accessed the version without a trailing slash, it would automatically redirect to the version with the trailing slash. So in ASP.NET WebForms, the trailing slash was obviously preferred since it was the default behavior.

Now, in ASP.NET MVC, they decided to make the default behavior the opposite. It does serve up both versions as I mentioned, but when it generates links, they don’t have a trailing slash.

If you’re long term solution is to use MVC, I recommend dropping the trailing slashes, just to avoid the pain. I’m really hoping that by the time the final version of MVC comes out, they’ll give us an option to define routes that should have a trailing slash.

ASP.NET MVC, What about SEO?

I’ve started working the the latest preview of the ASP.NET MVC framework. I’m completely converting one of my sites, because learning by doing is typically the best way. Unfortunately, I’ve run into some alarming SEO (Search Engine Optimization) issues with this new paradigm (or more specifically, the Microsoft implementation).

Duplicate Ducks!

Duplicate Content

Duplicate content is a major issue. If a search engine (Google, which we’re primarily concerned with) finds multiple identical pages, it could be seen as a spam technique. Google likes original content, and penalizes duplicate content.

The problem is that the ASP.NET MVC default routing is too forgiving. If I have a page with this address: "/controller/action/id", the routing engine happily serves it up at "/controller/action/id/". There is no reason to not be strict on this. In ASP.NET WebForms, if you forget the trailing slash, it will automatically perform a 301 (permanent) redirect to the version with the trailing slash.

ASP.NET MVC has a bug (I’m calling it that) that won’t let you define a URL as requiring a trailing slash. Below, I’ve defined a route as a sample. In the URL to match, I have a trailing slash. In the routing code, the trailing slash is removed when it’s added to the routing table. This also has the side-effect of generating the URL’s without a trailing slash.

routes.MapRoute(
	"Legacy-Firefox",
	"Firefox-Extension/",
	new { controller = "Home", action = "Firefox", id = "" } );

Since routes can be configured to reuse actions and controllers, it makes more paths to follow. If I again use the route defined above, I end up with all of these valid addresses that could potentially be linked to and indexed:

  • a.com/Firefox-Extension
  • a.com/Firefox-Extension/
  • a.com/Home/Firefox
  • a.com/Home/Firefox/
  • a.com/Home/Firefox/anythingyouwant

If you’re lucky, Google won’t penalize duplicate content. However, if Google indexes the same content using multiple URL’s, you won’t get the benefit of focusing the PageRank. A similar situation occurs with you have a site that can be addressed like "cnn.com" and "www.cnn.com". They counted as separate pages, that end up competing for good rank.

Legacy URL’s

I’m sure there is a large group of people that are anxiously awaiting to take advantage of the new MVC style development. Many of them will undoubtedly have existing URL’s they want to preserve.

There are a couple of ways to handle this issue. The search engines would prefer that your URL’s simply remain the same. This is possible, but requires some fancy routing. The SEO community highly recommends this approach (with good cause).

Another way to handle it is to adopt the new REST style URL’s that typically make the most sense with an MVC approach: "/controller/action/id". Then, setup 301 redirects from the old addresses to the new one’s. This article discusses the technical details. In theory, this should be the best scenario. However, Google themselves say to get the incoming links pointed to the new addresses ASAP. The truth is, this solution sucks. I’ve actually done this with a site. It was search engine suicide for a couple of months. I eventually got my old position back, but lost a significant amount of revenue because of it.

Yet another way that I found is to set up multiple routes so that the content is accessible with both the old and new addresses. If you’ve been paying attention, you’ll know that this counts as duplicate content, and is very, very bad. I was in shock when I found this approach being advocated.

Conclusion

I’m not saying the routing system is completely wrong, I just think it would be set up so that the easy way of migrating a site is the correct way, or as close to it as possible. I don’t want to have to write custom routing. At the very least, come up with a way to designate that a particular action has a single path (and cancel out additional paths in other routes). It would also be nice if there was a way to use the old style urlMapping section in the web.config for legacy URL’s.

If I’m completely wrong about how the routing works, let me know. It’s difficult to find good information (which is understandable right now), and I’m admittedly still in an early learning stage.