Sites.Local – for developers with too many local sites
Posted December 5th, 2009 at 5:28 pm by Matt Chepeleff
As an ASP/C# developer it’s key I work locally and save time wasted uploading files after every change to a page.  Then, when I’ve got a bunch of changes to share with a client and I want to update a staging/production environment, I can do it all at once.  Well, I resumed working on a project this afternoon that I haven’t worked on for a couple days – and I just couldn’t recall the local site address!
My laptop runs Vista Business and I use Internet Information Services (IIS) to run local apps. Â To map the various apps and keep everything running on port 80 I take advantage of the Windows Hosts file to create custom urls for local apps. Â For example, I can create an entry for clientname.localdev which enables me to setup and view a site at http://clientname.localdev/. Â You can learn more about Hosts files here if they’re new to you.
Back to this morning: I couldn’t recall if I setup localdev.project, project.localdev, project.local, or local.project. Â Only way to check is to open up the Hosts file and see what I had originally created. Â That’s when I thought: let’s write a quick page to read all the entries in my Hosts file. Â So I did, and I setup sites.local as my own, local directory of entries read directly from my Hosts file. Â Check it out:
I figured I’d create some categories to group the multiple entries I’ve got in my Hosts file – and add a quick flag for showing a category collapsed by default (more on this later). Â Here’s a modified (sample) Hosts file:
First, let’s look at a few changes to the Hosts file itself to make all this work:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | # Copyright (c) 1993-2006 Microsoft Corp. # # This is a sample HOSTS file used by Microsoft TCP/IP for Windows. # # This file contains the mappings of IP addresses to host names. Each # entry should be kept on an individual line. The IP address should # be placed in the first column followed by the corresponding host name. # The IP address and the host name should be separated by at least one # space. # # Additionally, comments (such as these) may be inserted on individual # lines or following the machine name denoted by a '#' symbol. # # For example: # # 102.54.94.97 rhino.acme.com # source server # 38.25.63.10 x.acme.com # x client host 127.0.0.1 localhost #ExcludeFromSites.Local ::1 localhost #ExcludeFromSites.Local #Sites.Local.Category: New Projects Category# 127.0.0.1 project1.local 127.0.0.1 project2.dev 127.0.0.1 anotherclient.devel 127.0.0.1 project3.local #Sites.Local.Category: Other Category Here# 127.0.0.1 project4.local 127.0.0.1 project5.dev 127.0.0.1 project6.local #Sites.Local.Category: Archived/Past Por {start:collapsed}# 127.0.0.1 project7.local 127.0.0.1 project8.dev 127.0.0.1 client23.devel 127.0.0.1 project9.local 127.0.0.1 project10.local 127.0.0.1 project11.dev 127.0.0.1 clientname.devel 127.0.0.1 project12.local |
This obviously is not my Hosts file – I created a sample file for demo purposes. Â But either way, there are a couple things to note here – most of which will make sense as you look at the upcoming .aspx and code behind:
Now onto the code – I made comments throughout the code behind to make things easy to follow. Â The code could certainly be simplified, but for the sake of clarity I expanded some of it.
First, the .aspx page:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="siteslocal_default" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>Local Site Addresses</title> <style type="text/css"> * { font-family:Arial; font-size:13px; } body { background-color:#dfd; } div#centercontent { width: 800px; height: 500px; text-align: center; position: absolute; left: 50%; top: 50%; margin-left: -400px; margin-top: -250px; } div#header { text-align:left; font-size:23px; font-weight:bold; height:30px; } div#content { border: 1px solid #000; padding: 30px; text-align:left; height:360px; background-color:#fff; overflow-y:scroll; } div#footer { text-align:left; font-size:12px; } div.category { margin-bottom:15px; margin-left:10px; } </style> </head> <body> <form id="form1" runat="server"> <div id="centercontent"> <div id="header">Local Site Addresses</div> <div id="content"> <asp:Literal id="litHosts" runat="server"></asp:Literal> </div> <div id="footer">The contents of this page are being read directly from the hosts file in C:WindowsSystem32driversetc</div> </div> </form> </body> </html> |
And for the meat of the page, here’s the code behind written in c#:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | using System.Web; using System.Web.UI; using System.IO; public partial class siteslocal_default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { StreamReader reader = File.OpenText(@"C:WindowsSystem32driversetchosts"); string line = string.Empty; while ((line = reader.ReadLine()) != null) { if (!line.StartsWith("# ") && !line.StartsWith(" ") && line != "#" && line != "" && !line.EndsWith("#ExcludeFromSites.Local")) { bool show_collapsed = false; string showhidecode = string.Empty; if (line.StartsWith("#")) { /******* Append the HTML for the start of a new category *******/ if (litHosts.Text != "") litHosts.Text += ""; //only append if we're not on the first category if (line.Contains("{start:collapsed}")) show_collapsed = true; string catText = line; catText = catText.Replace(" ", "").Replace("t", ""); //remove spaces and tabs catText = catText.Replace("{start:collapsed}", ""); //remove from display catText = catText.Replace("Sites.Local.Category:", ""); //remove category prefix catText = catText.Replace("#", ""); //remove any stray #'s //prep the javascript onclick code and div id string id = catText.ToLower(); string js = string.Format("document.getElementById('{0}').style.display",id); showhidecode = _ @"onclick=""if({0}=='block'){{0}='none';}else{{0}='block';}""".Replace("{0}", js); //append the <div> for this category's name litHosts.Text += string.Format(@"<div style=""cursor:pointer;"" {0}> _ <b>{1}</b></div>", showhidecode, catText); //append the <div> opening tag for this category litHosts.Text += string.Format(@"<div id=""{0}"" class=""category"" _ style=""display:{1};"">", id, show_collapsed ? "none" : "block"); } else { /******* Append the HTML for each item in the current category *******/ //first let's isolate the host name (assumes we don't need to display the IPs) //so...let's the find the index of the first space or tab string url = string.Empty; line = line.Trim(); int spacer_location = 0; spacer_location = line.IndexOf(' '); if (spacer_location == -1) spacer_location = line.IndexOf("t"); //display from the spacer to the end url = line.Substring(spacer_location, line.Length - spacer_location); url = url.Replace(" ", "").Replace("t", ""); //remove any spaces or tabs //write out this line litHosts.Text += string.Format(@"<a href=""http://{0}/"">{0}</a><br />", url); } } } litHosts.Text += ""; //close out the last div reader.Dispose(); } } |
The only other things to note are:
- I setup this page to run at http://sites.local and site this as my home page in Chrome – in IIS I changed the anonymous user to my own username (to ensure the code has permission to access the file)
- Be sure to not to start an entry in your Hosts file with a Tab – the code allows preceeding spaced, but would need to be changed to allow preceeding Tabs
That’s it, hope you find this useful and a bit of a timesaver too. Â Only took about 30 minutes to pull together, and I think you ought to be able to set it up in less time than that.
Happy coding!
Tags: Code
