13

I'm using WCF 4 on IIS 7.5 and want to eliminate the default .svc extension from the URL of all my RESTful services. I've seen the approaches documented using the Url Rewrite Module and an IHttpModule but I don't want to take those approaches.

I am vaguely familiar with the concept of Routes introduced in ASP.NET MVC and as I understand they are now abstracted out of MVC in Net 4 as System.Web.Routing. But in looking at the docs it appears I need to add a Global.asax file to my project which I'm not really keen on. Is there any other way to handle this?

I've also seen the Configuration-Based activation feature, but that only seems to eliminate the .svc file, but still requires I use .svc in the url of my service.

Can anyone summarize my options here for not needing .svc in my urls?

BrettRobi
  • 3,793
  • 7
  • 40
  • 64

3 Answers3

10

Sure, no problem: first off, read all about the new WCF 4 features in A Developer's Introduction to Windows Communication Foundation 4.

What you're looking for is called file-less service activation. It's a new setting in your <system.serviceModel> that looks something like this:

<serviceHostingEnvironment> 
    <serviceActivations>
        <add factory="System.ServiceModel.Activation.ServiceHostFactory" 
             relativeAddress="[subfolder/]filename.svc" or "~/[subfolder/]filename.svc" 
             service="SomeNamespace.YourService"/>
    </serviceActivations>
</serviceHostingEnvironment>

Basically, all the information you'd have in the *.svc file (path, service to call) is in this config section now.

You should be able to call this service at

http://yourserver/virtualdirectory/YourService

now - no more *.svc, no messy URL rewriting etc. - it just plain works!

Update: it doesn't seem to work that well, unless you go in and add a *.svc extension to your relative path - kind defeats the whole purpose!

If you want to register using an ASP.NET route, check out the MSDN docs on that topic. You'd have to have something like this in your application startup, in a web app that would be global.asax.cs:

void Application_Start(object sender, EventArgs e)
{
    RegisterRoutes(RouteTable.Routes);
}

private void RegisterRoutes(RouteCollection routes)
{
    routes.Add(new ServiceRoute("YourService", 
               new WebServiceHostFactory(), typeof(SomeNamespace.YourService))); 
}

Hopefully, with that, you'll be able to get your service up and running without any *.svc file extensions!

antonio
  • 548
  • 8
  • 16
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
  • It looks like you're talking about using Configuration-Based Activation (http://msdn.microsoft.com/en-us/library/ee358764.aspx) rather than System.Web.Routing. The problem is that it appears relativeAddress must use a WCF supported extension (such as .svc). I can't get your example to work, I just get the error: 'The registered relativeAddress 'YourService' under section 'system.serviceModel/serviceHostingEnvironment/serviceActivations' in configuration file does not have an extension' – BrettRobi Jul 20 '10 at 20:33
  • @BrettRobi: funny - that MSDN article contradicts itself.... and this is contrary to all the presentations and talks I've seen/heard so far on file-less activation..... I've updated my answer anyway – marc_s Jul 20 '10 at 21:17
  • 2
    Yeah I was hopeful it would do the trick but it really looks like a simple way to eliminate the .svc file itself but not the need for .svc in the url. Thanks for the help though... – BrettRobi Jul 20 '10 at 21:20
  • 1
    **Relative path without file extension causes this error**: _The registered relativeAddress 'RestTestService' under section 'system.serviceModel/serviceHostingEnvironment/serviceActivations' in configuration file does not have an extension._ **[MSDN](http://msdn.microsoft.com/en-us/library/ee358764.aspx) says:** The `relativeAddress` attribute must be set to a relative address such as “`/service.svc`” or “`~/ – mmdemirbas Mar 12 '12 at 15:49
  • @marc_s how to come up with payload restriction and Timeout scenarios if registered using an ASP.NET route – joshua Aug 01 '13 at 06:55
  • This works, but all the other asp.net routing routing fails. The links created with @Html.EditorFor etc all now maps to the web service. – Sriwantha Attanayake Aug 24 '13 at 15:38
  • First, see here why you should use just use just ServiceHostFactory, http://stackoverflow.com/questions/2921802/serviceroute-webservicehostfactory-kills-wsdl-generation-how-to-create-extens Second, Are you using the same directory for you site links as the service routing? perhaps you need to use a subdirectory. – Luiz Felipe Oct 14 '13 at 15:35
  • 1
    @LuizFelipe: sorry, this is not correct. If you want to use the **REST** style, you **have to** use `WebServiceHostFactory`, and not being able to create a wsdl from that code is moot - since a REST service never **HAS** a WSDL file anyway, in the first place.... – marc_s Oct 14 '13 at 16:19
  • Yes, you was correct, silly me. I haven't payed attention to the REST part, Using ServiceHostFactory correct things, but only on soap WS, on rest you must use URL routing and that's why there was people above saying that it didn't work. – Luiz Felipe Dec 19 '13 at 21:42
  • Sorry, but neither the first answer nor the second "Edit" answer works for serviceActivations. See, one of the main reasons that serviceActivations exists is so that the hosting project (the one running the Global.asax.cs, doesn't have a reference to the dll holding the WCF service. So your second solution requires that the hosting project have this reference. – Rhyous Nov 29 '16 at 16:12
5

Just to wrap up the answer and add one more point there. You'll need the same ASP.NET route registration as above:

void Application_Start(object sender, EventArgs e)
{
    RegisterRoutes(RouteTable.Routes);
}

private void RegisterRoutes(RouteCollection routes)
{
    routes.Add(new ServiceRoute("YourService", 
               new WebServiceHostFactory(), typeof(SomeNamespace.YourService))); 
}

In order to get this working you need however to add some more things to web.config. The service hosting should be configured to be ASP.NET compatible. This can be done by adding aspNetCompatibiliyEnabled="true" to serviceHostingEnvironment element:

 <serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true" />

Hope this clarifies and gives an easier to find solution.

tomij
  • 51
  • 1
  • 3
  • 1
    See here why you should not use WebServiceHostFactory, use just ServiceHostFactory http://stackoverflow.com/questions/2921802/serviceroute-webservicehostfactory-kills-wsdl-generation-how-to-create-extens – Luiz Felipe Oct 14 '13 at 15:33
  • @LuizFelipe, the question you are referring to is for a SOAP service, not a REST (WebHttp) service. This question is for a REST service. WebServiceHostFactory IS correct factory in this case. – Mark Good Dec 19 '13 at 14:00
  • Yes, changing it to use ServiceHostFactory solves the routing problem, but then you get an SOAP service, you are right. I was wrong, if the solution above does not work, just use URL routing. – Luiz Felipe Dec 19 '13 at 21:45
1

Important clarification for IIS 7.5 and Framework 4.0:

For the Web routing module to work, it requires the application pool set to "Integrated Mode", it doesn't works in "Classic Mode"

One additional problem I've found after switching is that when in "Integrated Mode" the application crashed on startup because I had modules included in the <system.Web> section.

I fixed it by moving the modules to the <system.webServer> configuration section that is new for IIS 7

Hector Salazar
  • 141
  • 1
  • 6