Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
Markdown Monster - The Markdown Editor for Windows

Removing the .SVC Extension from WCF REST URLs


:P
On this page:

I’ve been getting a lot of questions in the last few months regarding the URLs that WCF REST uses. WCF REST – new in .NET 3.5 – provides a pure Web based Binding (webHttpBinding specifically) that allows for creating REST based URLs that return non SOAP Http results in Xml, JSON, RSS, Atom or raw binary formats. One of the nice things that you can do with WCF REST endpoints is that you can specify a UriTemplate that allows you to customize the way the URL looks when accessing the endpoint.

For example I might have a method endpoint defined like this:

[OperationContract]
[WebInvoke(
    Method = "GET",
    ResponseFormat = WebMessageFormat.Xml,
    BodyStyle = WebMessageBodyStyle.Bare,
    UriTemplate="Quotes/{symbol}")  
]          
StockQuote GetStockQuote(string symbol);

Normally a WCF endpoint is accessed through the .SVC file plus a path that specifies the method name plus any parameters specified on the query string (or in POST data). Without the URI template to load a stock would look like this:

http://localhost/wcfAjax/RestStockService.svc/GetStockQuote?symbol=MSFT

Using the UriTemplate the URL becomes a little nice and more readable:

http://localhost/wcfAjax/RestStockService.svc/Quotes/MSFT

Note that once you apply a UriTemplate the method/parameter syntax no longer works – only a single endpoint URL maps to the specific endpoint.

Url formatting is of course mostly semantics – the latter URL is easier to parse by a human consumer having more of the feel of a breadcrumb that leads you down the path. You can also create your own ‘rules’ for this so if you also wanted to return that same data in a different format like Json (where the original returned XML) you might want to set up a second endpoint that does this and looks like this:

[OperationContract]
[WebInvoke(
    Method = "GET",
    ResponseFormat = WebMessageFormat.Json,
    BodyStyle = WebMessageBodyStyle.Wrapped,
    UriTemplate = "Quotes/{symbol}/json")
]        
StockQuote GetStockQuoteJson(string Symbol);

and can be called like this:

http://localhost/wcfAjax/RestStockService.svc/Quotes/MSFT/json

WCF REST allows for some welcome URL flexibility which is a nice feature when dealing with REST based endpoints.

One important limitation with UriTemplate to keep in mind that parameter mapping ( inside of {} ) only works with string parameters, so even simple type mapping like int, bool, or dates don’t work with them.

Getting rid of the pesky .SVC Extension

One of the first questions I usually get when I talk about the WCF REST features usually is: How do I get rid of the .SVC extension in those URLs? Back to semantics, eh? If you look at the URLs above you notice that each of the URLs references the .SVC file including its .SVC extension. The UriTemplate defined on the WCF endpoint method specifies the a path that follows the .svc file, so whatever template you set up it is appended to the main service URL which ends in the .Svc file.

Here are two approaches you can use to remove the .svc extension and both of them work through Url Redirection at the server level.

IIS 7 Rewrite Module

A couple of months ago Microsoft released the IIS 7 Rewrite module which allows you to easily and declaratively define Url Rewrite rules in your Web.config file. The module provides RegEx based replace syntax and is ideal for fixing up .SVC urls. What’s nice is that it also includes a nice UI for the IIS 7 Management console so that you can visually see all rewrite rules installed and even experiment and test them out.

IisRewrite

To get a URL like this:

http://localhost/wcfAjax/Rest/RestStockService/Quotes/MSFT/json

You can use the following rule definition:

<?xml version="1.0" encoding="UTF-8"?><configuration>
    <system.webServer>
    <rewrite>
        <rules>
            <rule name="RestStockService" stopProcessing="true">
              <match url="^rest/reststockservice/(.*)$"/>
              <action type="Rewrite" url="rest/reststockservice.svc/{R:1}" />
            </rule>
        </rules>
    </rewrite>
    </system.webServer>  
</configuration>

You use RegEx expressions to match the service Url without the .svc extension. The RegEx expression is based on virtual directory as its base path – it’s important that you consider any subdirectory paths in the URL. As you can see my service lives in a Rest folder underneath the virtual directory root and that’s reflected in the match expression for the URL searched for. Note the RegEx group after the service name – an explicit group is used to capture the entire extra path of the URL so it can be used in the rewrite operation. You can reference any of the group matches as {R:1} for the first group match ( {R:0} is the entire match).

This is a pretty painless way to do URL routing that’s easy to modify declaratively and store in a configuration file.

You can download the IIS RewriteModule here:

http://www.iis.net/downloads/default.aspx?tabid=34&g=6&i=1691

I’d highly recommend this module even if you’re not using it for WCF REST Urls. It’s been really useful to me in setting many URL rewriting tasks that I previously used custom modules for.

Custom Http Module

The IIS Rewrite module only work in IIS 7 only unfortunately so if you’re running IIS 6/5 or you need more sophisticated URL routing than RegEx expressions can provide you can create a custom module.

IIS 5/6 requires Wildcard Mapping

If you’re not running IIS 7 in order for this to work you need to enable Wildcard Script Mapping and map the wild card map to ASP.NET. Wildcard script mapping sets up all URLs to be routed through the ASP.NET pipeline so every resource – static or otherwise - is fired through ASP.NET so you can run HttpModules against them. This allows even extensionless Urls to (like http://localhost/wcfAjax/Rest/RestStockService/Quotes/MSFT/json ) fire through your ASP code and hit your modules.

Once you have requests firing into the ASP.NET pipeline you can then set up an HttpModule that reroutes requests. The following is a somewhat generic .svc rerouting mechanism where you can just specify a part fragment that is treated as a service.

/// <summary>
/// Redirect module that allows specifying a set of .svc urls
/// by stripping the svc extension off and accessing without it.
/// 
/// To use add any non-svc path segments (ie. service.svc should be service)
/// to the ServiceMap below.
/// 
/// Note that any path that uses one of these service map entries needs to 
/// end with a trailing backslash.
/// </summary>
public class  ServiceRedirector : IHttpModule
{

    static List<string> ServiceMap = new List<string> 
        {
              "reststockservice", 
              "ajaxservice",  
              "jsonstockservice"
        };        

    public void Dispose()
    { 
    
    }

    public void Init(HttpApplication app)
    {       
        app.BeginRequest += delegate
        {
            HttpContext ctx = HttpContext.Current;
            string path = ctx.Request.AppRelativeCurrentExecutionFilePath.ToLower();

            foreach (string mapPath in ServiceMap)
            {
                if (path.Contains("/" + mapPath + "/") || path.EndsWith( "/" + mapPath) )
                {
                    string newPath = path.Replace("/" + mapPath + "/", "/" + mapPath + ".svc/");
                    ctx.RewritePath(newPath, null, ctx.Request.QueryString.ToString(), false);
                    return;
                }
            }
        };
    }
}

The idea is that you provide a list of Urls (statically in this case but you could easily modify this to load the list dynamically either from config settings or some external source) that are to be routed as simple strings. In short the names of the URL that you want routed without the SVC extension. This code still assumes you want to route to the same name as the SVC file (ie. /reststockservice/ becomes /reststockservice.svc/).

Other than that the code just runs through list and and tries to match it to the current URL. If found it replace the match by adding the .svc extension to it and off it goes.

To hook up the module you’ll need to add it to your web.config:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.web> <httpModules> <add name="ServiceRedirector" type="WcfAjax.ServiceRedirector"/> </httpModules> </system.web>
<system.webServer> <validation validateIntegratedModeConfiguration="false" /> <modules> <add name="ServiceRedirector" type="WcfAjax.ServiceRedirector"/> </modules> </system.webServer>
</configuration>

The <system.web> section is for IIS 5/6, <system.webServer> for IIS 7. The module’s code is a pretty simplistic approach that uses simple string replacement to expand non-.SVC Urls to .SVC urls, but it should give you enough of an idea on how to create something more flexible should you need it. This approach works both in IIS 5/6 with the wildcard script mapping or in IIS 7 where no mapping is required as all requests already fire through the ASP.NET pipeline.

While it’d by nice if WCF had a  native mechanism for removing the .SVC extension from URLs, you can see that’s it’s pretty straightforward to do so either with the IIS 7 Rewrite Module or by creating a small custom module.

Does it really matter?

I’m not sure if changing a Url by removing an extension is really providing any benefits, perceived or otherwise. To me this is semantics. Sure a Url without the .svc looks nicer, but who cares? For the most part COMPUTERS not people access those Urls and computers have no sense of esthetics <s> at least last time I checked. And if it’s an API, it’s still only a developer who looks at it once and surely a developer can determine the difference between a URL with or without an extension buried in the extra path.

I think what it really comes down to is having a clean URL structure that's natural to follow. Certainly an API that is consistent will be easier to learn for a developer to use and easier to work with in the long run. Whether stripping of an .SVC extension helps that cause or whether you use a query string vs. a path separator is arguable at least in my mind. The biggest concern for an API is consistency - it should be logical, readable and most of all consistent. And frankly query strings are the easiest way to be consistent because they are non-positional unlike path separators which are.

However, as I mentioned at the outset of this post – a lot of people actually seem to care quite vehemently about the Url format, because it’s easily one of the most frequent requests I have heard since I started writing/speaking about WCF. Hence this post.

So, what’s it to you? Does the URL matter and if so why?

Posted in ASP.NET  AJAX  WCF  

The Voices of Reason


 

Tim Heuer
December 15, 2008

# re: Removing the .SVC Extension from WCF REST URLs

I think the URL doesn't matter. I would imagine full REST purists say it does. But there is nothing in the REST "spec" or manifestos that state such. Some people believe it shouldn't reveal the technology as it makes it less portable, but I argue as long as you respect the permalink it doesn't matter (http://timheuer.com/blog/archive/2008/01/22/respect-the-permalink-not-the-file-extension.aspx). Just as you demonstrate routing (URI templates) here, if you changed technology you could do the same thing applying a template to existing URIs. I never "got" the reason why people don't like a .whatever in their URI. It's just another part of the URI and just as ugly as slashes and other the other stuff that, as you point out, the computer is the only one who really cares. I apply the mother-in-law factor to everything...does she care about the URI? Not as long as she can bookmark it.

Audi
December 15, 2008

# re: Removing the .SVC Extension from WCF REST URLs

Hi Rick,

Great blogging! I'm wondering why Microsoft, Google, Sun, and the the big guns haven't noticed your talent yet. Are you working for a company right now (I mean other than your "company")? Have you tried making an "offer" (of what you can do for these companies) in return for an employment opportunity?

I just hate to see a genius' energy and talent go to waste (--I don't mean any disrespect to what you're probably contented or happy doing, but I think you deserve better for all the hardwork!).

I hope it will just be a matter of time before you become one those Google or Microsoft Program Managers!

KUTGW,
Audi

Rick Strahl
December 16, 2008

# re: Removing the .SVC Extension from WCF REST URLs

@Tim - Totally agree with you on your post. But semantics or not, the question keeps coming up frequently and I think it's good that the options are there to satisfy the semantic wonks.

Kumar
December 17, 2008

# re: Removing the .SVC Extension from WCF REST URLs

I am not sure but I think to make extensionless urls to work in IIS7, all requests (Even for static contents like images) will have to pass through IIS pipeline which will unnecessarily load extra modules and suffer from performance. So what are the benefits for extensionless urls other than semantics

Rick Strahl
December 17, 2008

# re: Removing the .SVC Extension from WCF REST URLs

@Kumar - the IIS pipeline is fired everytime regardless. But yes, when you introduce a managed module the path is a little different as it has to enter managed mode, whereas a pure static file request for say an HTML file normally doesn't hit managed code at all in IIS.

However, the overhead of this is minimal and negligible in all but the highest load scenarios.

Benefits other than semantics? Nothing that I can think of.

Ben Amada
December 18, 2008

# re: Removing the .SVC Extension from WCF REST URLs

I'm not usually concerned what characters are in a Url. Especially if the Url is not typically seen by humans. But if my mother-in-law can also bookmark a Url without undesirable characters in it (e.g. without .SVC), then why not create a Url without those characters. Everyone will be satisifed in the end.

Rick Strahl
December 18, 2008

# re: Removing the .SVC Extension from WCF REST URLs

@Ben - I doubt your mother in law will be accessing REST urls directly. Heck I doubt YOU will be accessing REST URLs directly (other than possibly for testing). REST URLs tend to be APIs, rarely are they directly accessed by typing the URL into the address bar.

I think if one has to rationalize it it comes down to having a clean URL structure that's natural to follow. Certainly an API that is consistent will be easier to learn for a developer to use and easier to work with in the long run. Whether stripping of an .SVC extension helps that cause or whether you use a querystring vs. a path separator is arguable at least in my mind. The biggest concern for an API is consistency - it should be logical, readable and most of all consistent. And frankly query strings are the easiest way to be consistent because they are non-positional unlike path separators which are.

OTOH, the redirection approaches discussed above can also be applied to regular URLs to HTML content (ie. ASPX or even HTM pages) and in that case yes it may make more sense.

Sam
December 23, 2008

# re: Removing the .SVC Extension from WCF REST URLs

@Audi

Obviously you've never been your own boss. You seem to be idolizing working for a large corporation, when the real gold mine is being a guru in your field *and* having enough business savvy to earn a living with your own company.

I'd venture to say that Rick probably has the world right where he wants it.

--Sam

Bart Czernicki
January 12, 2009

# re: Removing the .SVC Extension from WCF REST URLs

I agree...its mostly a nicety. Just like the new book I picked up RESTful .NET, the .svc extension according to the author doesn't really make the service unRESTful (its not like embedding querystring parameters or using a hierarchy when you need to flatten the url out).

However, having said that something just doesn't feel right with having the .svc extension there. The same theme re-occurs that even though you don't need to remove this .svc extension many resources show you how. I remember seeing it during the MySpace guys presentation on REST, RESTful .NET and blogs like yours. So, its probably "almost a best practice" to remove the .svc extension.

Matthew Erwin
February 10, 2009

# re: Removing the .SVC Extension from WCF REST URLs

I would guess the primary desire in getting rid of the ".svc" is so the URL doesn't scream Microsoft.

Good article.

Rick Strahl
February 10, 2009

# re: Removing the .SVC Extension from WCF REST URLs

@Matthew - you can change the extension to something else via script mapping in IIS - that's pretty easy. Leaving it out altogether though requires one of the steps above.

mob
July 20, 2009

# re: Removing the .SVC Extension from WCF REST URLs

The WCF REST Contrib project has an HttpModule that does this too: http://wcfrestcontrib.codeplex.com/

Might save you a couple of keystrokes. :)

m

SeeSharp
December 07, 2009

# Silverlight RESTful POX

I'm working on a small project for a Swedish company. They need their application be available via web, so it's time to put that Silverlight knowledge at work. I decided to use Silverlight for UI technology and have a REST service layer to provide the required data.

Beameup
September 09, 2010

# re: Removing the .SVC Extension from WCF REST URLs

Have conditions improved any with .Net 4.0?

I tried looking at MapPageRoute, but as the name implies it only works for web form pages.

Rick Strahl
September 09, 2010

# re: Removing the .SVC Extension from WCF REST URLs

You can create explicit route providers and register them in Application_Start(). You can map anything to anything.

http://msdn.microsoft.com/en-us/magazine/dd347546.aspx

This is pre-4.0, but the same rules apply except that you don't need to add the routing configuration and assemblies explicitly anymore.

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024