Archive for June, 2008

SSL Links/URLs in MVC

// June 11th, 2008 // 14 Comments » // MVC

A couple days ago a reader sent me a question regarding how to use SSL with the MVC framework. Specifically the reader wanted to know the easiest way to make an Ajax call to a HTTPS page from a non HTTPS page. The tricky part here is to do so without hard-coding any URLs (as one of the best practices of the MVC framework is that views and controllers should be divorced from the routes that access them).

Currently an ActionLink like:

   1: <% =Html.ActionLink( "Test", "About", "Home" ) %>

… outputs the following hyperlink:

   1: <a href="/Home/About">Test</a>

I’ve created a few extension methods that enable you to fully-qualify these URLs and change the protocol to HTTPS at run-time. Using the extension method "ToSslLink" like so:

   1: <% =Html.ActionLink( "Test", "About", "Home" ).ToSslLink() %>

… now outputs a hyperlink with protocol, server, port, etc:

   1: <a href="https://localhost:57626/Home/About">Test</a>

If you’re using Ajax, however, you’ll be more interested in getting to the URL directly rather than building an entire hyperlink. In that case you can use "ToSslUrl":

   1: <% =Url.Action( "About", "Home" ).ToSslUrl() %>

… to output this:

   1: https://localhost:57626/Home/About

Here is the code for the extension methods I’ve created, hopefully some of you will find this useful:

   1: using System.Text.RegularExpressions;
   2: using System.Web;
   3:  
   4: namespace SquaredRoot.Mvc.Extensions.Ssl
   5: {
   6:     /// <summary>
   7:     /// Provides helper extensions for turning strings into fully-qualified and SSL-enabled Urls.
   8:     /// </summary>
   9:     public static class UrlStringExtensions
  10:     {
  11:         /// <summary>
  12:         /// Takes a relative or absolute url and returns the fully-qualified url path.
  13:         /// </summary>
  14:         /// <param name="text">The url to make fully-qualified. Ex: Home/About</param>
  15:         /// <returns>The absolute url plus protocol, server, & port. Ex: http://localhost:1234/Home/About</returns>
  16:         public static string ToFullyQualifiedUrl( this string text )
  17:         {
  18:             //### the VirtualPathUtility doesn"t handle querystrings, so we break the original url up
  19:             var oldUrl = text;
  20:             var oldUrlArray = ( oldUrl.Contains( "?" ) ? oldUrl.Split( '?' ) : new[]{ oldUrl, "" } );
  21:  
  22:             //### we"ll use the Request.Url object to recreate the current server request"s base url
  23:             //### requestUri.AbsoluteUri = "http://domain.com:1234/Home/Index"
  24:             //### requestUri.LocalPath = "/Home/Index"
  25:             //### subtract the two and you get "http://domain.com:1234", which is urlBase
  26:             var requestUri = HttpContext.Current.Request.Url;
  27:             //### fix for Mike Hadlow's reported issue regarding extraneous link elements when a querystring is present
  28:             //var urlBase = requestUri.AbsoluteUri.Substring( 0, requestUri.AbsoluteUri.Length - requestUri.LocalPath.Length );
  29:             var localPathAndQuery = requestUri.LocalPath + requestUri.Query;
  30:             var urlBase = requestUri.AbsoluteUri.Substring( 0, requestUri.AbsoluteUri.Length - localPathAndQuery.Length ); 
  31:  
  32:             //### convert the request url into an absolute path, then reappend the querystring, if one was specified
  33:             var newUrl = VirtualPathUtility.ToAbsolute( oldUrlArray[0] );
  34:             if( !string.IsNullOrEmpty( oldUrlArray[1] ) )
  35:                 newUrl += "?" + oldUrlArray[1];
  36:  
  37:             //### combine the old url base (protocol + server + port) with the new local path
  38:             return urlBase + newUrl;
  39:         }
  40:  
  41:         /// <summary>
  42:         /// Looks for Html links in the passed string and turns each relative or absolute url and returns the fully-qualified url path.
  43:         /// </summary>
  44:         /// <param name="text">The url to make fully-qualified. Ex: <a href="Home/About">Blah</a></param>
  45:         /// <returns>The absolute url plus protocol, server, & port. Ex: <a href="http://localhost:1234/Home/About">Blah</a></returns>
  46:         public static string ToFullyQualifiedLink( this string text )
  47:         {
  48:             var regex = new Regex(
  49:                 "(?<Before><a.*href=")(?!http)(?<Url>.*?)(?<After>".+>)",
  50:                 RegexOptions.Multiline | RegexOptions.IgnoreCase
  51:                 );
  52:  
  53:             return regex.Replace( text, ( Match m ) =>
  54:                                         m.Groups["Before"].Value +
  55:                                         ToFullyQualifiedUrl( m.Groups["Url"].Value ) +
  56:                                         m.Groups["After"].Value
  57:                 );
  58:         }
  59:  
  60:         /// <summary>
  61:         /// Takes a relative or absolute url and returns the fully-qualified url path using the Https protocol.
  62:         /// </summary>
  63:         /// <param name="text">The url to make fully-qualified. Ex: Home/About</param>
  64:         /// <returns>The absolute url plus server, & port using the Https protocol. Ex: https://localhost:1234/Home/About</returns>
  65:         public static string ToSslUrl( this string text )
  66:         {
  67:             return ToFullyQualifiedUrl( text ).Replace( "http:", "https:" );
  68:         }
  69:  
  70:         /// <summary>
  71:         /// Looks for Html links in the passed string and turns each relative or absolute url into a fully-qualified url path using the Https protocol.
  72:         /// </summary>
  73:         /// <param name="text">The url to make fully-qualified. Ex: <a href="Home/About">Blah</a></param>
  74:         /// <returns>The absolute url plus server, & port using the Https protocol. Ex: <a href="https://localhost:1234/Home/About">Blah</a></returns>
  75:         public static string ToSslLink( this string text )
  76:         {
  77:             return ToFullyQualifiedLink( text ).Replace( "http:", "https:" );
  78:         }
  79:     }
  80: }

One important missing element from all is this posting to a form via HTTPS from a non-HTTPS page. You can certainly create your form tags manually and populate the action attribute using Url.Action(…).ToSslUrl(), but you cannot try and combine these extension methods with the Html.Form(…) helper that is most commonly used inside a using statement.

Note: The above code was updated on July 7th, 2008 to fix a bug reported by Mike Hadlow. Thanks Mike!

Kick It on DotNetKicks.comShout It on DotNetShoutOuts.com

Help Decide Sandcastle’s Fate

// June 10th, 2008 // 11 Comments » // Tools

Sandcastle – the .Net community equivalent of RDoc/JavaDoc and the spiritual successor of the now defunct NDochas been removed from CodePlex. It’s fate is currently up in the air and Microsoft is asking you for input on what should happen next. It was pulled down after the community at-large expressed reservations about Sandcastle being hosted on CodePlex while not being published under an Open Source license or even being posted in source form at all. According to the announcement on MSDN, the possible future for Sandcastle involves two scenarios:

  1. Publish the source code for Sandcastle and revive this project in Codeplex

  2. Migrate sandcastle to MSDN Code gallery at http://code.msdn.microsoft.com

I for one would love to see Sandcastle released as an open source project on CodePlex. It seems to me that Microsoft has had a great deal of success lately with releasing the MVC Framework as an open source project and I hope that they continue the trend. If you have used Sandcastle or foresee the need to have automatic code documentation generation on a project in the future, please do not hesitate to leave a comment letting the powers that be know how you feel.

Kick It on DotNetKicks.comShout It on DotNetShoutOuts.com

We’re Back

// June 8th, 2008 // 2 Comments » // Life

After two weeks in gorgeous St. Lucia on honeymoon at the Grande St. Lucian, my new bride and I have returned to DC. Take a look at a few of the pictures we snapped along the way.

A Few Pictures

After a hectic weekend, we got our first chance to relax at National Airport, waiting to depart for Miami and then on to St. Lucia.

OurHomeInStLucia

The backyard of our home away from home. To the right you can see our private pool (with the waterfall in the background). Not pictured: our outdoor shower & hot tub, plus a hammock that proved perfect for reading and relaxing. All this and only a stone’s throw from the beach!

Our butler scheduled an intimate dinner for the two of us at Gordon’s, a restaurant at the end of a pier only a few minutes walk from home. If you’ve never stayed at an all-inclusive, I highly recommend it. It was nice to eat at fine restaurants every night and just get up and leave without worrying about any bill.

Hobie

First order of business the first morning in St. Lucia? Sailing. Lots of sailing. My hopes of sailing every day were not to be (so much else to do!), but I did manage to go out every other day or so.

SwimUpBar

We heart swim-up bars.

St. Lucia’s most famous landmarks, the Pitons, in the background. Also the namesake of St. Lucia’s most popular beer (which tastes remarkably like Corona).

ForestBridge

A tour guide led us into the outer fringes of the rainforest, where we wanted to swim in a waterfall.

Waterfall

Which we did.

BackOfBoat

There was a lot of boating in St. Lucia. This was taken on a wild, wet ride back from the Pitons.

PoolRaft

We spent considerably more time in the humongous beach-side pool than on the beach proper. Lesson learned? The ocean needs more swim-up bars.

Windsurfing is hard. Hard, hard.

Riding horses bare-back in the surf is fun, but it also gave me a very healthy respect for the invention of saddles.

Taken on the bow of a 50+ foot catamaran, which I’m trying to figure out how to add to my Amazon wish-list. 

ByTheFountain

Uh oh, the trip is almost over, hurry up and take some nice photos!

AgainstATree

Who are these tan people, and what have they done with the folks from the first picture?

InTheBungalow

With picture time over, it’s time to relax in a beach-front bungalow until the sun goes down. Afterward it is off to pack and bid St. Lucia farewell in the morning.

This is only a small selection of our wonderful two weeks. If anyone else is considering a trip with their significant other to the Caribbean, we cannot recommend St. Lucia highly enough and Sandals Grande St. Lucian was a wonderful place to stay.

Kick It on DotNetKicks.comShout It on DotNetShoutOuts.com