Posts Tagged ‘ Web Development ’

ASP.NET MVC: Maintaining URL Permanence with Legacy Routes

What makes a cool URI?
A cool URI is one which does not change.
What sorts of URI change?
URIs don’t change: people change them.

– Tim Berners-Lee, creator of the interwebs

While working on our current ASP.NET MVC 3 project, we came across a requirement to maintain a large directory of .htm files that were used as content generated by users of the website.  While blowing off the dust and looking inside of the files we realized that there we lots of URLs that are supposed to be active pages.  Some of these were locations of images that were moving, while others were old ASP pages that are still redirected and even still register is the top 10 of search results for their associated keywords.  Immediately one of our developer’s heads began pounding with the pain of regular expression string replacement.

But wait!  These are permanent URLs that still have active SEO functionality.  Our client needs these links to stay active and not 404 their way into irrelevance.  Plus, it would be a pain to either:

  1. Go through each HTM file and string replace as many combinations we can find, or
  2. Use string replace each and every time we try to load the file

Enter Routing made easy with ASP.NET MVC 3.

First, we had to make sure the linked images in these files still display images when loaded up in the browser.  Most are located at the address:

<img src="http://www.mydomain.com/images/feature/myimage.jpg" />

..or something similar.  However, with the new design these images no longer lived at this physical location.  Hmm . . . to the Routes!

routes.MapRoute(
                "FeatureImage",
                "images/feature/{filename}",
                new { controller = "Image", action = "Feature" }
            );

Okay, great you defined a route.  But how do you give an image as a “View”?  Well, thankfully in ASP.NET MVC there is a FilePathResult.

public ActionResult Feature(string filename)
        {
            return File("~/content/images/features/" + filename, "image/jpeg");
        }

public class ImageController : Controller
    {
        public ActionResult Feature(string filename)
        {
             return File("~/content/images/features/" + filename, "image/jpeg");
        }
    }

There is also the option to actually create a stream and return a FileStreamResult as well, but this lets us do the same without having to open/close a stream reader.

So now that we have the image URL out of the way, what about those legacy ASP/ASPX routes that will no longer be valid?  And how can we do it without losing SEO value that our client has built up over the years?  Hmm . . . to the Routes!

Imagine we have the legacy route “/feature/showFeature.asp?fid={id}”

routes.MapRoute(
                "LegacyRoute",
                "feature/showFeature.asp",
                new { controller = "Features", action = "BackwardsCompatibleDetail" }
            );

And so the legacy route is now generated and matched, but how to handle that query string parameter?  Well you can define those in the Routing, but they are passed on as Nullable parameter objects to your methods on your controllers.

public ViewResult BackwardsCompatibleDetail(int? fid)
        {
            return View("Detail", _repository.GetById(eid.GetValueOrDefault()));
        }

And there you go!  You’re legacy route is now generated in the new MVC route table!

So that’s great and all, but what I really want is for those URLs to no longer be generated and instead just issue 301 redirects to the new URL path for this resource.  Phil Haack (Best. Name. Ever.) comes to the rescue with his RouteMagic library, available I might add via NuGet.  His example:

var route = routes.MapRoute("new", "bar/{controller}/{id}/{action}");
routes.Redirect(r => r.MapRoute("old", "foo/{controller}/{action}/{id}"))
  .To(route);

And the best part is a lot of this Routing framework is extendible, so we can create our own handlers and such to do even more complex things with the Routing.  But out of the bag, there are plenty of options with dealing with your SEO URL permanence and making sure those continue to bring in the traffic you need.  Viva Routing + MVC!

ASP.NET MVC: Don’t Fear the ViewBag

As we continue to work on our ASP.NET MVC3 project, I’m continuing to be impressed with how quick and lean the development process has gone so far.  Already, our small team is swarming and are empowered with figuring out the problems that are common at the start of a project.  One of these was a UI requirement that turned out to be an eye-opening use of one of MVC3’s more divisive features:   ViewBag.

Why the divisiveness?  Because the ViewBag is a dynamically-typed object.  If you’re a Ruby, Python, or Javascript programmer, you know all about everything being a nail.  For C# programmers comforted by a strongly-typed language, this is the type of stuff that we lose sleep on.  Properties on a dynamic object are defined at run-time, so to add a new property you just use it!  In fact, one of the first uses of this that you come across in an MVC project is the following:

@{
	ViewBag.Title = "My Home Page";
}

What is “Title”?  It’s a property on the dynamic ViewBag that is defined as soon you get or set the property.  We had this in prior verisons of MVC as ViewData, but notice the difference.

ViewData["MyObj"] = myObj;
MyObject o = ViewData["Title"] as MyObject;

ViewBag.MyObj = myObj;
var o = ViewBag.MyObj;

The ViewData was object typed, so you had to always cast it when trying to get the value.  This usually lead to a mess if you abused the ViewData and ended up with casts all over the place.

Now, let me say that I feel that dynamic objects in a strongly-typed language should be treated as if they were loaded weapons:  know how to use it, use it only if necessary, and keep the safety on!  So it was the other day that we found a great use to fire our ViewBag!!

We had a UI requirement that depending on where the user was in the site, that the color of some elements would change.  This was purely view-related logic and had nothing to do with our underlying model or business logic.  We quickly brought up a few options:

  • Pass some string value via the Controller using view models
  • Pass some string value via the Controller using the ViewBag
  • Use JQuery to do some CSS toggling
  • Create an extension method when creating the object that would determine the right CSS string

None of these options “smelled” right.  I didn’t want a pure view-related item like a CSS class name in my Controller code, JQuery seemed silly, and an extension method would require compiling code if something changed.  Then, I had a quick glance at that ViewBag.Title code and it clicked!  At the top of each of our sub-layout pages, we add this line of code that specifies the CSS class to be use to customize the color of our element for all pages that derive from the sub-layout page.

@{
    ViewBag.NavStyle = "nav_color_blue";
}

Then in our partial view that renders the element:

<a class="nav_global @ViewBag.NavStyle" href="@Url.Action(" Index", "Home")">home</a>

In minutes, we had our solution for this purely view-only requirement and didn’t have to clutter up code in our Controller or add silly workarounds.  This fits!  And if for some reason a page does not define the NavStyle property, it just defaults to empty string and the default color in the first CSS class.

So I have found a great use for ViewBag that doesn’t make the strongly-typed hairs on my back to raise in horror.  And you know what?  It felt gooooooood!  Yes, I will continue to make sure this dynamic object is used only if absolutely needed, but in this case we embraced the “get ‘er done” attitude and completed this requirement quickly and in a way that makes sense.  I look forward to other creative ways we can use the dynamic property to solve view-related issues and requirements.

ASP.NET MVC3 And Other Microsoft Web Development Goodies

Last week, Microsoft unleashed a whole slew of new web development products for us to get to get excited about here at Affirma.  In fact, I think I’ll still Vishal Joshi’s sentiment of feeling like we are in a “Web Development Candy Store”!  The timing couldn’t have been more perfect as well, as we are just kicking up a new web development project that I have determined to use ASP.NET MVC3 along with some of these other new tools.  So I thought I’d take a moment to post some of my favorite bits that I have experienced so far.

Razor View Engine

Maybe it’s me, but when I was previously working on ASP.NET MVC projects, I always felt like I had some code-smell funk emanating from me when I’d look at those view pages filled with server code syntax that I’ve been seeing from WebForms and even ASP development.  MVC development is quick and lean to me and I always wanted a syntax that matched.  Enter Razor!

Old Way  Sad smile

<div class="contacts">
<% foreach (var c in contacts) { %>
<b><%= c.Name %></b> - (<%= c.PhoneNumber %>)<br>
<% } %>
</div>

New Way Smile

<div class="contacts">
@foreach (var c in contacts) {
<b>@c.Name</b> - (@c.PhoneNumber)<br>
}
</div>

And it has all the in-line, multi-line, nesting, and HTML helper support that I would expect.  Just keeps things clean and development fluid.

Razor Layouts/Sections

Like master pages, only better!  Okay, so that may be debatable, but being able to define the body or sections for widgets and other partials in a clean and simple manner just makes more sense to me.

@if (IsSectionDefined("widget"))
{
    <div class="widget">
    @RenderSection("widget")
    </div>
}

@section widget {
<h3>Featured Articles</h3>
@Html.Action("Featured", "Articles")
}

SQL Compact 4

Okay, so we probably aren’t going to be deploying any of our website projects using SQL CE 4.  However, being an environment we many of us are on the go and working from different locations, it servers as a nice, lightweight database that our developers can use to whip up some code and features without having to make sure there is a SQL Server box to connect and query against.  Also, I think there are some cool rapid prototyping opportunities here to help us engage prospective clients.
NuGet

Just started using this, but I’m already a fan.  What is NuGet?  Simply put, it’s a quick and easy to way to integrate all those tools and packages you use to develop right into Visual Studio.  Starting up my new MVC3 project, I knew I wanted NUnit, RhinoMocks, Fluent Route testing, as well as some other tools that I knew were scattered around on my hard drive but wasn’t sure if they were up to date.  No worries!  Just open up the console and type “Install-Package MvcContrib.Mvc3.TestHelper-ci” and boom!  My test project is almost set up!  I foresee a lot of value with this tool moving forward, so I’m looking forward into how it develops.

MvcScaffolding

Speaking of NuGet, this is probably the coolest library I’ve downloaded so far from NuGet.  It integrates right into the console and allows me to quickly code-gen, or “scaffold”, some of the basic MVC structures I’ll need for my project.  I created my business object, and then via one line I was able to generate an Entity Framework Code-First context, Repository, Controller, and all the views for CRUD operations.  Now, I didn’t need all the CRUD operations, but so what!  It’s easy to go in and delete or tweak what I didn’t need.  The tool is great for stubbing out the very basic bones of your project that you can then go in and build on top of.  Plus, it supports T4 templates so who knows what other cool scaffolds will be created by the open source community!

I’ll continue to post other nuggets of goodness I come across while working on this project, but for now there is definitely an abundance of web development candy for me to geek out over the next few weeks.  Just ask some of the folks around the office, I’ve been a jabbering fool on a sugar-high all week!