About the author

Morten Krogh-Jespersen is the founder of dotnamics - an IT company that develop products and consults in the programming field.

SEO-friendly HTTP module

by Morten Krogh-Jespersen 19. juli 2010 04:08

There’s a lot that you can do, to make your site more easy to discover by search-engines. One method is normalizing your URI’s, which can be done in different ways. There’s also a difference between ASP.NET Web Forms and MVC, in the way URI’s are handled and expressed.

As you probably know, Google and other search-engines punish duplicate content – and a single '/' is enough to confuse even Google. Therefore I follow some simple rules.

I’ve create a SEO-friendly HTTP module, that helps me do the following:

  • If the request-URI ends with ‘/’ then remove this from the request (for web forms, this should be the other way around)
  • Lowercase all URI’s
  • Check for default routing (‘/index’) – if this is the request, remove '/index' from the uri (for ASP.NET Web forms, this should be, if URI ends with ‘/’, then append ‘default.aspx’.
  • Check for www. this is a personal preference. Just choose one.

Instead of redirecting when we first find a problem, I append all changes to the URI, so that users (and bots) only receive one 301 Redirect.

Below is the httpmodule code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Text.RegularExpressions;

namespace dotnamics_mvc.HttpModules
{
    public class SeoFriendlyHttpModule : IHttpModule
    {
        public void Dispose()
        {
        }

        public void Init(HttpApplication context)
        {
            context.BeginRequest += new EventHandler(context_BeginRequest);
        }

        void context_BeginRequest(object sender, EventArgs e)
        {
            HttpApplication app = (HttpApplication)sender;

            string url = (app.Request.Url.Scheme + "://" + app.Request.Url.Authority + app.Request.Url.AbsolutePath);
            bool redirect = false;

            // check for trailing /
            if (url.EndsWith("/") && app.Request.Url.AbsolutePath != "/")
            {
                redirect = true;
                url = url.Substring(0, url.Length - 1);
            }

            // check for capital letters
            if (Regex.IsMatch(url, @"[A-Z]"))
            {
                redirect = true;
                url = url.ToLower();
            }

            // check for default routing (Index)
            if (url.EndsWith("/index"))
            {
                redirect = true;
                url = url.Substring(0, url.Length - 6);
            }

            // check for www
            if (url.Contains("www."))
            {
                redirect = true;
                url = url.Replace("www.", "");
            }

            if (redirect)
                Redirect301(app, url + app.Request.Url.Query);
        }

        private void Redirect301(HttpApplication app, string location)
        {
            // set status to 301 - Perm Redirect
            app.Response.StatusCode = 301;
            app.Response.Status = "301 Moved Permanently";
            app.Response.StatusDescription = "Moved Permanently";
            app.Response.AddHeader("Location", location);
            app.Response.End();
        }
    }
}

Tags: , , ,

ASP.NET | ASP.NET MVC | SEO | HttpModule

Dynamic data/controller in a masterpage in an ASP.NET MVC website

by Morten Krogh-Jespersen 13. juli 2010 03:28

A lot of web pages provide dynamic data on every page, this could for instance be an advertisement or a funny joke.

On the dotnamics website, there's a dynamic header on every page (except blog pages), which displays a customer reference, a product reference and so on.

I've seen some posts on how to do it, but almost everybody suggest building a base controller - BUT I don't like that idea. Building a base controller might be a good idea, but I think a controller should be encapsulated, and only solve the problem at hand. If you put to much information in a base-controller, you remove the purpose of the controller, imho.

I used the RenderAction html helper to solve the problem.

1: Create a controller, I called mine MasterPageController:

namespace dotnamics2010.Controllers
{
    public class MasterPageController : Controller
    {
        public ActionResult HeaderContent()
        {
            Models.ViewModels.MasterPage.HeaderContent headerContent = new Models.ViewModels.MasterPage.HeaderContent();
            headerContent.InPlaceShuffle();
            return View(headerContent);
        }
    }
}

What this does is, it calls a viewmodel, that generates different headers. I then shuffle the items, before i send the data to the view.

2: add a View:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<dotnamics2010.Models.ViewModels.MasterPage.HeaderContent>" %>

<div id="headercontent">
    <div class="items">
        <%
            foreach (dotnamics2010.Models.ViewModels.MasterPage.IHeaderContent content in Model)
            {
                %>
                    <div>
                        <% Html.RenderPartial(content.GetType().Name, content); %>
                    </div>
                <%
            }
            %>
    </div>
 </div>

3: Finally, include in masterpage like this:

                <div id="header_content">
                    <% Html.RenderAction("HeaderContent", "MasterPage"); %>
                </div>

I think this is the perfect solution.

Tags: , ,

ASP.NET | ASP.NET MVC | Masterpage