21

I'm trying to use extension-less / .svc-less WCF services. Can anyone else confirm or deny the issue I'm experiencing?

I use routing in code, and do this in Application_Start of global.asax.cs:

RouteTable.Routes.Add(new ServiceRoute("Data", new WebServiceHostFactory(), typeof(DataDips)));

I have tested in both IIS 6 and IIS 7.5 and I can use the service just fine (ie my extension-less wildcard mapping handler config is correctly pointed at ASP.NET). However, metadata generation is totally screwed up. I can hit my /mex endpoint with the WCF Test Client (and I presume svcutil.exe) -- but the ?wsdl generation you typically get with .svc is toast. I can't hit it with a browser (get 400 bad request), I can't hit it with wsdl.exe, etc. Metadata generation is configured correctly in web.config.

This is a problem of course, because the service is exposed as basicHttpBinding so that an old style ASMX client can get to it. But of course, the client can't generate the proxy without a WSDL description.

If I instead use serviceActivation routing in config like this, rather than registering a route in code:

<serviceHostingEnvironment aspNetCompatibilityEnabled="true">
  <serviceActivations>
    <add relativeAddress="Data.svc" service="DataDips" />
  </serviceActivations>
</serviceHostingEnvironment>

Then voila... it works.

But then I don't have a clean extensionless url. If I change relativeAddress from Data.svc to Data, then I get a configuration exception as this is not supported by config. (Must use an extension registered to WCF).

I've also attempted to use this code in conjunction with the above config:

RouteTable.Routes.MapPageRoute("","Data/{*data}","~/Data.svc/{*data}",false);

My thinking is that I can just point the extensionless url at the configured .svc url. This doesn't work -- the /Data.svc continues to work, but /Data returns a 404.

I did find a work-around if using urlMappings in config like this, in conjunction with serviceActivation above:

<urlMappings>
   <add url="~/Data" mappedUrl="Data.svc"/>
</urlMappings>

The problem with this is twofold - 1. It seems convoluted 2. In the generated WSDL, the operation endpoints still refer to Data.svc/, rather than Data/ -- therefore theres dependency on Data.svc actually existing / responding.

This is not really what I want, even if it kinda / sorta solves the problem.

Is there a proper way of getting extension-less WCF service urls to generate WSDL correctly?

Martin Konecny
  • 57,827
  • 19
  • 139
  • 159
Ethan J. Brown
  • 2,308
  • 3
  • 20
  • 27

2 Answers2

36

Wow, do I feel dumb.

I should have been hosting my service with ServiceHostFactory, NOT WebServiceHostFactory.

As soon as I moved back to code from config... and swapped to this line of code:

RouteTable.Routes.Add(new ServiceRoute("Data", new ServiceHostFactory(), typeof(DataDips)));

I was in business with an extensionless URL serving up WSDL and help pages.

It's too bad I wasted so much time on this. It was an accident that I was using WebServiceHostFactory, but there's no disclaimer on the factory page in MSDN about the reduced functionality. (I would argue that removing WSDL makes sense, but removing the Help pages does not as they could simply provide an attribute in config to rename the 'Help' page should there be a REST operation with that name... sigh).

There is a note in the WebServiceHost docs http://msdn.microsoft.com/en-us/library/system.servicemodel.web.webservicehost.aspx

Ethan J. Brown
  • 2,308
  • 3
  • 20
  • 27
  • 1
    Still a valid question. I just did this exact same thing, and found the answer here waiting for me. Thanks! – Samuel Meacham Jun 17 '10 at 05:01
  • Yes, a valid question. I wanted to do the same thing and this worked a treat. – JTew Jul 06 '10 at 11:00
  • 6
    My advice now... ditch WCF! It's just way too complicated with landmines like this all over the place. I finally abandoned it given all the unnecessary pain it caused me over the years, and couldn't be any happier with what I use now. I'm 100% behind ServiceStack having used it for at least a year now - its great, its clean, makes sense when you revisit old code, supports multiple serialization formats out of the box, has IoC supported baked in, hosts easily inside / outside IIS (including Mono), doesn't throw you into config hell, and is updated frequently. – Ethan J. Brown Feb 03 '12 at 16:33
  • I just started a WCF service...been having isuses with multiple rest/ws endpoints...does ServiceStack run well with Windows azure? – Patrick Magee Jun 07 '13 at 14:13
  • you're not dumb, it's that you are new to it and missed it. I missed it too. – PositiveGuy Oct 14 '13 at 17:08
  • 2
    For the uninitiated... ServiceStack is now a pay product and the license is... well... not nice. – GoClimbColorado Mar 25 '14 at 18:34
0

I have a the same issue. Your solution works on my code. I just changed the Global.asax like this:

<%@ Application Language="C#" %>
<%@ Import Namespace="System.Web.Routing" %>
<%@ Import Namespace="System.ServiceModel.Activation" %>
<%@ Import Namespace="System.ServiceModel.Web " %>

<script RunAt="server">
    void Application_Start(object sender, EventArgs e)
    {
        RegisterRoutes(RouteTable.Routes);
    }

    private void RegisterRoutes(RouteCollection routes)
    {
        routes.Add(new ServiceRoute("URLWithoutSVC", new WebServiceHostFactory(), typeof(Service))); 
   }
</script>

To

<%@ Application Language="C#" %>
<%@ Import Namespace="System.Web.Routing" %>
<%@ Import Namespace="System.ServiceModel.Activation" %>
<%@ Import Namespace="System.ServiceModel.Web " %>

<script RunAt="server">
    void Application_Start(object sender, EventArgs e)
    {
        RegisterRoutes(RouteTable.Routes);
    }

    private void RegisterRoutes(RouteCollection routes)
    {
        routes.Add(new ServiceRoute("URLWithoutSVC", new ServiceHostFactory(), typeof(Service))); 
   }
</script>