PEX, Ben Hall, and Some Other Notes

While checking out more ideas for my data generation tool/app/libraries I stumbled on this video of a presentation by Ben Hall.  The presentation “DDD7 Session Video – Microsoft Pex – The Future of unit testing?” is a great introduction to the PEX framework/toolset.  If you write unit tests, or are trying to get started writing tests, this is a great video to watch.

I watched the video and have a new level of admiration for this guy, and for Red Gate.  He’s using ReSharper (+ points), steps through code smoothly and logically (+ points), and above all he knows his information.  Excellent traits.

PEX Worries?

At 40:14 in the video Ben brings up a major point of contention that I too have.  I don’t really want to use PEX with the Microsoft Test Framework.  I?d much rather use NUnit, mbUnit, or SOMETHING besides Microsoft Test.  Even though, I know, the last dozen code entries I’ve posted uses the Microsoft Test Framework I intend to change that soon.  Ben goes on to point out that almost all of the major test frameworks are now supported.  This is awesome news!  I now have full motivation and have downloaded the PEX libs.

With That Written?

I’m now off to download NUnit and get rid of my Microsoft Tests.  I will prospectively go get XUnit too and start taking a solid look at that tool.

Data Generation Tools

While viewing this video Ben also mentioned a data generation project on CodePlex.  I couldn’t help but get a bit giddy about this fact.  So I checked it out.  Red Gate Generators – Red Gate also has a professional tool that they sell.  The libraries look pretty cool and solid, but I’ll have to review the library license before I know if I can use anything there or not.  I might have to just “not see” anything there.

Fini.

Data Generation, TDD Like

On the tail of my recent additions to the data generator app I?ve been building I fell right into a need for the middle name to be generated along with standard names.  Here?s how I went about fixing this situation up with a sling at TDD & such.

The first thing I did was a quick refactor, to change the previous FullName class I had been using in my previous Part 1, Part 2, and Part 3 examples to FirstLastAmericanName.  Next I added the first test for the new class I?ll create right afterward.  The test looked like this.

   1:  [TestMethod]
   2:  public void VerifyFirstMiddleLastName()
   3:  {
   4:      var name = new FirstMiddleLastAmericanName();
   5:      Assert.IsTrue(name.FirstName.Length == 0);
   6:      Assert.IsTrue(name.LastName.Length == 0);
   7:      Assert.IsTrue(name.MiddleName.Length == 0);
   8:  }

The test, of course doesn?t build, let alone run.  So I jumped into this new class and created the following.

   1:  namespace Generator.Core.Model
   2:  {
   3:      public class FirstMiddleLastAmericanName : IFullName
   4:      {
   5:          public FirstMiddleLastAmericanName()
   6:          {
   7:              FirstName = string.Empty;
   8:              LastName = string.Empty;
   9:              MiddleName = string.Empty;
  10:          }
  11:
  12:          public string MiddleName;
  13:
  14:          #region IFullName Members
  15:
  16:          public string FirstName { get; set; }
  17:
  18:          public string LastName { get; set; }
  19:
  20:          #endregion
  21:      }
  22:  }

So now I get a green light and I head right into the next test.

   1:  [TestMethod]
   2:  public void VerifyFirstMiddleLastNameObjectReturnsFromFactory()
   3:  {
   4:      var factory = new NameFactory();
   5:      var name = factory.Build(NameFactory.NameCulture.AmericanFirstMiddleLast) as FirstMiddleLastAmericanName;
   6:      Assert.IsTrue(name.FirstName.Length > 0);
   7:      Assert.IsTrue(name.LastName.Length > 0);
   8:      Assert.IsTrue(name.MiddleName.Length > 0);
   9:  }

I needed to then add the NameCulture enumeration.  This I added directly inside of the NameFactory.  I reviewed the other classes and name spaces I had setup.  At this time it seemed like the best place to put the enumeration.

   1:  namespace Generator.Core.Factories
   2:  {
   3:      public class NameFactory
   4:      {
   5:          public enum NameCulture
   6:          {
   7:              American,
   8:              AmericanFirstMiddleLast,
   9:              British,
  10:              French,
  11:              Japanese
  12:          }

Make note that is a very partial code segment. Also make note, I?m not adding anything except functionality right now for that second value AmericanFirstMiddleLast. I left off the rest of the class as it will be changing a lot and I?ll copy in each part as I change it. In this entry I?ll be refactoring so that the enumeration is a legitimately used part of the code base and how it reverberates through. The next thing was to get at least a basic method to get a green light for the test listed. What I ended up with to get to that point is as follows.

   1:  public IFullName Build(NameCulture nameCulture)
   2:  {
   3:      var name =
   4:          new FirstMiddleLastAmericanName
   5:              {
   6:                  FirstName = "test",
   7:                  MiddleName = "test",
   8:                  LastName = "test"
   9:              };
  10:
  11:      return name;
  12:  }

Now it?s time to get some real randomness in the names.  I first wrote out a test.

   1:  [TestMethod]
   2:  public void VerifyFirstMiddleLastNameIsRandom()
   3:  {
   4:      var factory = new NameFactory();
   5:      var nameOne = factory.Build(NameFactory.NameCulture.AmericanFirstMiddleLast) as FirstMiddleLastAmericanName;
   6:      var nameTwo = factory.Build(NameFactory.NameCulture.AmericanFirstMiddleLast) as FirstMiddleLastAmericanName;
   7:
   8:      Assert.AreNotEqual(nameOne.FirstName, nameTwo.FirstName);
   9:      Assert.AreNotEqual(nameOne.MiddleName, nameTwo.MiddleName);
  10:      Assert.AreNotEqual(nameOne.LastName, nameTwo.LastName);
  11:  }

This got me to a stage where I actually have a good test that will make sure I?m getting solid random names back.  After this test, with the red light received, I set out and applied these changes the Build method I created above.

   1:  public IFullName Build(NameCulture nameCulture)
   2:  {
   3:      var rand = new Random(DateTime.Now.Millisecond);
   4:      var entities = new GeneratorEntities();
   5:
   6:      List<Names> firstNames = (from name in entities.Names
   7:                                where name.Type == "Female First Names" || name.Type == "Male First Names"
   8:                                select name).ToList();
   9:      List<Names> lastNames = (from name in entities.Names
  10:                               where name.Type == "Last Names"
  11:                               select name).ToList();
  12:      List<Names> middleNames = new List<Names>();
  13:
  14:      middleNames.AddRange(firstNames);
  15:      middleNames.AddRange(lastNames);
  16:
  17:      var firstMiddleLastAmericanName =
  18:          new FirstMiddleLastAmericanName
  19:              {
  20:                  FirstName = firstNames[rand.Next(0, firstNames.Count)].Name,
  21:                  MiddleName = middleNames[rand.Next(0, middleNames.Count)].Name,
  22:                  LastName = lastNames[rand.Next(0, lastNames.Count)].Name
  23:              };
  24:
  25:      return firstMiddleLastAmericanName;
  26:  }

That should give me a full range of middle names.  Next step, that?s right, write a test.  After this test I noticed something though?

   1:  [TestMethod]
   2:  public void VerifyMultitudesFirstMiddleLastNameIsRandom()
   3:  {
   4:      var factory = new NameFactory();
   5:      var list =
   6:          factory.Build(NameFactory.NameCulture.AmericanFirstMiddleLast, 1000) as
   7:          List<FirstMiddleLastAmericanName>;
   8:
   9:      for (int i = 0; i < list.Count; i++)
  10:      {
  11:          int compareUp = i + 1;
  12:          if (compareUp == list.Count)
  13:          {
  14:              compareUp = 0;
  15:          }
  16:          Assert.AreNotEqual(
  17:              list[compareUp].FirstName + list[compareUp].MiddleName + list[compareUp].LastName,
  18:              list[i].FirstName + list[compareUp].MiddleName + list[i].LastName);
  19:      }
  20:  }

Yeah, I needed to do some serious refactoring.  With this test, not even building, I jumped into resolving the Build methods.  During each of these stages of the refactor I made a point to run all of my tests, except the one above.  This way I assured I didn?t break anything else.  My final NameFactory code looked like what is below.  Take a good look at the following code, and below I?ll have listed a few of the major refactor changes I made.

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using Generator.Core.Model;
   5:
   6:  namespace Generator.Core.Factories
   7:  {
   8:      public class NameFactory
   9:      {
  10:          public NameFactory()
  11:          {
  12:              entities = new GeneratorEntities();
  13:              random = new Random(DateTime.Now.Millisecond);
  14:              firstNames = new List<Names>();
  15:              lastNames = new List<Names>();
  16:              middleNames = new List<Names>();
  17:              namesList = (from name in entities.Names select name).ToList();
  18:          }
  19:
  20:          private readonly GeneratorEntities entities;
  21:          private readonly Random random;
  22:          private List<Names> firstNames;
  23:          private List<Names> lastNames;
  24:          private readonly List<Names> middleNames;
  25:          private readonly List<Names> namesList;
  26:
  27:          public enum NameCulture
  28:          {
  29:              American,
  30:              AmericanFirstMiddleLast,
  31:              British,
  32:              French,
  33:              Japanese
  34:          }
  35:
  36:          public IFullName Build(NameCulture nameCulture)
  37:          {
  38:              return CreateNames(nameCulture, 1)[0];
  39:          }
  40:
  41:          public IFullName Build()
  42:          {
  43:              return CreateNames(NameCulture.American, 1)[0];
  44:          }
  45:
  46:          public List<IFullName> Build(NameCulture nameCulture, int numberOfNames)
  47:          {
  48:              return CreateNames(nameCulture, numberOfNames);
  49:          }
  50:
  51:          private List<IFullName> CreateNames(NameCulture nameCulture, int numberOfNames)
  52:          {
  53:              firstNames = GetFirstNames();
  54:              lastNames = GetLastNames();
  55:
  56:              switch (nameCulture)
  57:              {
  58:                  case NameCulture.American:
  59:                      var firstLastAmericanName = new List<IFullName>();
  60:
  61:                      for (int i = 0; i < numberOfNames; i++)
  62:                      {
  63:                          firstLastAmericanName.Add(MapName(new FirstLastAmericanName()));
  64:                      }
  65:
  66:                      return firstLastAmericanName;
  67:
  68:                  case NameCulture.AmericanFirstMiddleLast:
  69:                      middleNames.AddRange(firstNames);
  70:                      middleNames.AddRange(lastNames);
  71:
  72:                      var americanFirstMiddleLastNames = new List<IFullName>();
  73:
  74:                      for (int i = 0; i < numberOfNames; i++)
  75:                      {
  76:                          var fullName = new FirstMiddleLastAmericanName();
  77:                          fullName = MapName(fullName) as FirstMiddleLastAmericanName;
  78:                          fullName.MiddleName = middleNames[random.Next(0, middleNames.Count)].Name;
  79:                          americanFirstMiddleLastNames.Add(fullName);
  80:                      }
  81:
  82:                      return americanFirstMiddleLastNames;
  83:
  84:                  default:
  85:                      throw new ArgumentOutOfRangeException("nameCulture");
  86:              }
  87:          }
  88:
  89:          private IFullName MapName(IFullName name)
  90:          {
  91:              name.FirstName = firstNames[random.Next(0, firstNames.Count)].Name;
  92:              name.LastName = lastNames[random.Next(0, lastNames.Count)].Name;
  93:              return name;
  94:          }
  95:
  96:          private List<Names> GetFirstNames()
  97:          {
  98:              return (from name in namesList
  99:                      where name.Type == "Female First Names" || name.Type == "Male First Names"
 100:                      select name).ToList();
 101:          }
 102:
 103:          private List<Names> GetLastNames()
 104:          {
 105:              return (from name in namesList
 106:                      where name.Type == "Last Names"
 107:                      select name).ToList();
 108:          }
 109:      }
 110:  }

The first thing I did was create the GetFirstNames & GetLastNames methods to clean up some of the junk that was in the Build methods.  Immediately I realized that I could make it even more performing by removing the actual queries against the database by simple returning the whole table into memory ? take a look at the last line of the constructor for that.  I completed that clean up, with appropriate lists being created.  Another thing I added was the mapper method.  I?m not 100% sure I like that method, but it sort of cleaned up things a little, but in turn it just doesn?t seem as elegant as it should be.

Overall I got it down to a single hit against the database & more in memory movements of the lists.  Also setup several private properties.  After a minute I thought, ?I?ll toss those setup some readonly members and save a bit of memory??  So I tried that and it worked out well.  I went through a number of other refactor steps and ended up with what I have listed above.  Next task was to see if my test would work.  So I uncommented my test and tried to run it.  It blew up with exceptions, so I dug in.

I immediately realized I had to do a little last minute refactor of my test also.  My final test ended up list this, which it appears to be, a bit more readable.  I might follow up though, with an entry cleaning this up even more.

   1:  [TestMethod]
   2:  public void VerifyMultitudesFirstMiddleLastNameIsRandom()
   3:  {
   4:      var factory = new NameFactory();
   5:      List<IFullName> list = factory.Build(NameFactory.NameCulture.AmericanFirstMiddleLast, 100);
   6:
   7:      for (int i = 0; i < list.Count; i++)
   8:      {
   9:          int compareUp = i + 1;
  10:          if (compareUp == list.Count)
  11:          {
  12:              compareUp = 0;
  13:          }
  14:
  15:          var fullName = list[compareUp] as FirstMiddleLastAmericanName;
  16:          var fullNameBase = list[i] as FirstMiddleLastAmericanName;
  17:
  18:          Assert.AreNotEqual(fullName.FirstName + fullName.MiddleName + fullName.LastName,
  19:              fullNameBase.FirstName + fullNameBase.MiddleName + fullNameBase.LastName);
  20:      }
  21:  }

Hope that was useful and happy Presidents day at ya.  Fini.

Getting Up To Date, Staying Up To Date?

I jumped in head first to get things updated.  Went after the ASP.NET MVC Engine, grabbed the toolkit for Silverlight, made sure the Silverlight SDK was updated, got the Deep Zoom Composer, Blend installed, made sure SP1 was installed, grabbed the WPF toolkit, and?   ok, at this point I lost track.  I think my home machine is fully updated.  Now the question is, are the other three machines updated?

Aaaaaaaaaaaaaaaaggggggggggggghhhhhhhhh!

Oh well, time to hit the ground running and get up to speed.  With some of the work I?ve been completing, I?ve seriously been contemplating a move to a new domain for my tech work (I already own it, so don?t go try to guess what it is an nab it!).  This way I can add it as a DBA (Doing Business As name) and get to work on expanding my reach in the community.

For now though, I just finished up my three part series I just posted and have started on some more entries in that vein.  I?ll also have some interesting and functional data generation utilities coming available soon.  Stay tuned!  😉

Test Driven Development Built Name Generator Part 3

Part 1, Part 2.

Now it is time finally for the random name generation.  I’ve gotten everything into place, so it’s just a matter of grabbing the names and randomizing among them.  Just as a check, after Part 2 was finished I had a total of 98,572 rows of data, or simply 98,572 names.

Many times I would not write actual unit tests against the database as it breaks isolation.  This time though, I’m making an exception.  First I added a reference to Generator.Core, System.Data, and System.Data.Entity.  I then created a new unit test class called DatabaseTests and added the following test to get things rolling.  Keep in mind, since these tests break isolation, I don’t write them in the red light green light idea of TDD.  My assumption is that they only prove the database is setup, running, the connection string is correct, and other minor configuration based and server based components.  In addition, yes, these are somewhat silly tests, such as the RetrieveFirstName() test has a bit of redundancy to it, but the point is to have an automated test to assure that the data has been moved into the database and is returning appropriately.

[TestClass]
public class DatabaseTests
{
    [TestMethod]
    public void RetrieveFirstFemaleName()
    {
        var entities = new GeneratorEntities();
        var returnName = (from name in entities.Names
                          where name.Type == "Female First Names"
                           select name).FirstOrDefault();
         Assert.IsNotNull(returnName);
         Assert.IsTrue(returnName.Name != string.Empty);
     }

     [TestMethod]
     public void RetrieveLastName()
     {
         var entities = new GeneratorEntities();
         var returnName = (from name in entities.Names
                           where name.Type == "Last Names"
                           select name).FirstOrDefault();
         Assert.IsNotNull(returnName);
         Assert.IsTrue(returnName.Name != string.Empty);
     }

     [TestMethod]
     public void RetrieveFirstMaleName()
     {
         var entities = new GeneratorEntities();
         var returnName = (from name in entities.Names
                           where name.Type == "Male First Names"
                           select name).FirstOrDefault();
         Assert.IsNotNull(returnName);
         Assert.IsTrue(returnName.Name != string.Empty);
     }

     [TestMethod]
     public void RetrieveFirstName()
     {
         var entities = new GeneratorEntities();
         var returnName = (from name in entities.Names
                           where name.Type == "Female First Names" || name.Type == "Male First Names"
                           select name).FirstOrDefault();
         Assert.IsNotNull(returnName);
         Assert.IsTrue(returnName.Name != string.Empty && returnName.Type == "Female First Names" ||
                       returnName.Type == "Male First Names");
    }
}

The next step now was to refactor the existing tests to prove the assembly of the name data transfer objects that would hold the first name and last name derived from the returned entity objects.

The first thing I did was break out the actual name objects into their respective files.  I did this using ReSharper, because it’s super insanely simple with ReSharper.  After that I put the class files in the project that has the model.  Next I fixed the namespaces to Generator.Core.Model.  The class files after these changes looked like the code below.

IFullName.c

namespace Generator.Core.Model
{
    public interface IFullName
    {
        string FirstName { get; set; }
        string LastName { get; set; }
    }
}

FullName.cs

namespace Generator.Core.Model
{
    public class FullName : IFullName
    {
        public FullName()
        {
            FirstName = string.Empty;
            LastName = string.Empty;
        }

         #region IFullName Members

         public string FirstName { get; set; }
         public string LastName { get; set; }

         #endregion
     }
}

NameFactory.cs

namespace Generator.Core.Model
{
    public class NameFactory
    {
        public static IFullName Build()
        {
            return new FullName {FirstName = "TestFirst", LastName = "TestLast"};
        }
    }
}

Now that we have these files moved out to the project where all the munging will happen, I’m going to start the actual refactor of the tests.  What I’ve come up with for the test refactor is as follows.

using Generator.Core.Model;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Factory.Tests
{
    [TestClass]
    public class FactoryNameBuilder
    {
        [TestMethod]
        public void VerifyFullNameObjectInstantiatesWithNames()
        {
            var name = new FullName();
            Assert.IsTrue(name.FirstName.Length == 0);
            Assert.IsTrue(name.LastName.Length == 0);
        }

        [TestMethod]
        public void VerifyFullNameObjectReturnsFromFactory()
        {
            var factory = new NameFactory();
            IFullName name = factory.Build();
            Assert.IsTrue(name.FirstName.Length > 0);
            Assert.IsTrue(name.LastName.Length > 0);
        }

        [TestMethod]
        public void VerifyFullNameIsRandom()
        {
            var factory = new NameFactory();
            IFullName nameOne = factory.Build();
            IFullName nameTwo = factory.Build();

            Assert.AreNotEqual(nameOne.FirstName, nameTwo.FirstName);
            Assert.AreNotEqual(nameOne.LastName, nameTwo.LastName);
        }
    }
}

In the factory I removed the fake return and fleshed out the appropriate build method.

using System;
using System.Collections.Generic;
using System.Linq;

namespace Generator.Core.Model
{
    public class NameFactory
    {
        public IFullName Build()
        {
            Random rand = new Random(DateTime.Now.Millisecond);

            GeneratorEntities entities = new GeneratorEntities();

            List FirstNames = (from name in entities.Names
                                      where name.Type == "Female First Names" || name.Type == "Male First Names"
                                      select name).ToList();
            List LastNames = (from name in entities.Names
                                     where name.Type == "Last Names"
                                     select name).ToList();

            FullName fullName = new FullName();
            fullName.FirstName = FirstNames[rand.Next(0, FirstNames.Count)].Name;
            fullName.LastName = LastNames[rand.Next(0, LastNames.Count)].Name;

            return fullName;
        }
    }
}

Run the tests now and you have a random name gold mine.  However, I wanted a bit more than that.  With another test added…

[TestMethod]
public void VerifyMultipleNameReturn()
{
    var factory = new NameFactory();
    List<IFullName> list = factory.Build(1000);

    for (int i = 0; i < list.Count; i++)
    {
        int compareUp = i + 1;
        if (compareUp == list.Count)
        {
            compareUp = 0;
        }
        Assert.AreNotEqual(list[compareUp].FirstName + list[compareUp].LastName, list[i].FirstName + list[i].LastName);
    }
}

…then the extra Build method.

public List<IFullName> Build(int numberOfNames)
{
    var rand = new Random(DateTime.Now.Millisecond);
    var entities = new GeneratorEntities();

    List<Names> FirstNames = (from name in entities.Names
                              where name.Type == "Female First Names" || name.Type == "Male First Names"
                              select name).ToList();
    List<Names> LastNames = (from name in entities.Names
                             where name.Type == "Last Names"
                             select name).ToList();

    var names = new List<IFullName>();

    for (int i = 0; i < numberOfNames; i++)
    {
        var fullName = new FullName();
        fullName.FirstName = FirstNames[rand.Next(0, FirstNames.Count)].Name;
        fullName.LastName = LastNames[rand.Next(0, LastNames.Count)].Name;
        names.Add(fullName);
    }

    return names;
}

and now I have a strong verification that I get solid randoms for 1000 name pairs.  I bumped it up to 2000 too just for fun, and didn’t hit duplicates until I put it up to 200,000.

File Extension ".svc" Annoyance!

REST Services are intended to have clean URIs.  So when Microsoft started pushing their REST over WCF Services I thought, “SWEET”, lemme get some of that.  While working with these services though a problem arose, “http://www.soemthing.com/someservice.svc&#8221; is NOT a very clean REST URI.  I just don’t dig nonsense like this so I went digging about for a fix.

Sure one can go into the whole process of doing some URI rewriting, but I wanted something fast, simple, and deployed in about 10-15 minutes.  HTTP Modules to the rescue!

First I created a regular class project and created a class file called RestUriCleanup.cs.  I then added the following code into the class file.

   1:  using System.Web;
   2:
   3:  namespace StandardServicesApplication
   4:  {
   5:      public class RestUriCleanup : IHttpModule
   6:      {
   7:          #region IHttpModule Members
   8:
   9:          public void Init(HttpApplication context)
  10:          {
  11:              context.BeginRequest +=
  12:                  delegate
  13:                      {
  14:                          var ctx = HttpContext.Current;
  15:                          string path = ctx.Request.AppRelativeCurrentExecutionFilePath;
  16:
  17:                          int i = path.IndexOf('/', 2);
  18:                          if (i > 0)
  19:                          {
  20:                              string svc = path.Substring(0, i) + ".svc";
  21:                              string rest = path.Substring(i, path.Length - i);
  22:                              string qs = ctx.Request.QueryString.ToString();
  23:                              ctx.RewritePath(svc, rest, qs, false);
  24:                          }
  25:                      };
  26:          }
  27:
  28:          public void Dispose()
  29:          {
  30:          }
  31:
  32:          #endregion
  33:      }
  34:  }

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

In the web.config file I added the following configuration settings in the httpModules Section.  Notice that the ScriptModule is already included as a handler as of .NET 3.5.

   1:      <httpModules>
   2:        <add name="RestUriCleanup" type="StandardServicesApplication.RestUriCleanup, StandardServicesApplication" />
   3:        <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
   4:      </httpModules>

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

Now at this point things can get tricky.  Depending on the version of IIS you’ll possibly need to make some changes at this point.  IIS 6.0 is setup as follows.  Open up the management console and right click the app or virtual directory and click on properties.  Click on the Home Directory tab and click on the Configuration button.

Once you have that dialog open then Insert a new wildcard application map.  Find and select the aspnet_isapi.dll file.  It should be located here:  “C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll“

Make SURE when you are adding the file, do NOT leave or check the Verify that file exists box.  I repeat, do NOT check it.

That’s it.  You now have your *.svc extension removed from your services file and should have nice clean REST based URIs.  This process is slightly different on IIS 7 w/ Vista or Windows Server 2008.  First off you do NOT need to create a wildcard on IIS 7 but you will need to go in and create a setting in IIS for the HTTP Module.  If interested let me know and I’ll add another blog entry for that, but for now…  this is how one gets rid of the *.svc extension.