Wednesday, January 5, 2011

URL Rewriting Module Interferes with WCF REST Service Processing

I spent most of yesterday and a good chunk of this morning troubleshooting a problem with a WCF REST service I’ve been trying to create.  Specifically, I had a brain-dead simple WCF service that looked like this:

    [ServiceContract(Namespace = "AjaxRoomService")]
    public interface IAjaxRoomService
    {
        [OperationContract]
        [WebGet(ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped)]
        string SayHello();
    }

The implementation looked like this:

    public class AjaxRoomService : IAjaxRoomService
    {
        public string SayHello()
        {
            return "Hello";
        }
    }

And the actual .svc file looked like this:

<%@ ServiceHost Language="C#" Debug="true" Service="Alanta.Web.Services.AjaxRoomService" Factory="System.ServiceModel.Activation.WebServiceHostFactory" CodeBehind="AjaxRoomService.svc.cs" %>

Note that I was using the WebServiceHostFactory, so I didn’t need to have anything in my web.config file.  Simple, right? Everything should have worked, right?  But when I tried to call the service (i.e., by navigating to http://localhost:51150/Services/AjaxRoomService.svc/SayHello), I consistently received a 404 error.

I did my standard Google searches, but all the issues people described had to do with running the service in IIS, and I wasn’t even getting that far: I was just trying to get this running under Cassini, in Visual Studio. 

But after much troubleshooting and more than a little swearing, I finally put my finger on it.  We’re using a simple URL rewriting module that shouldn’t have been interfering with this, but it was.  The trouble was in this particular line of code in the URL rewriting module:

HttpContext.Current.RewritePath(rewrittenPath);

A debugger showed that it was rewriting the path from “/Services/AjaxRoomService.svc/SayHello” to “/Services/AjaxRoomService.svc/SayHello” – in other words, it wasn’t making any changes.  But as soon as I changed it to only rewrite the path if the path had actually changed, my problem went away:

// Only rewrite the path if the path has changed, as otherwise it interferes with .svc request processing.
if (string.Compare(HttpContext.Current.Request.Path, rewrittenPath, true) != 0)
{
    Debug.WriteLine(string.Format("Rewriting {0} to {1}", HttpContext.Current.Request.Path, rewrittenPath));
    HttpContext.Current.RewritePath(rewrittenPath);
}
Not exactly a dramatic discovery, but I figured it might benefit someone else at some point, so I’ll toss it out there for the Google indexer to discover, in the hopes that it helps someone else someday.
 

No comments :