Case study: WCF Web Http routes Dollar ($) differently in IIS 8.5
Issue description
Considering below WCF Web HTTP code, which method will request “test.svc/$test” be routed to?
[ServiceContract]
public class DollarSignTestService
{
[WebGet(UriTemplate = "$test")]
public System.IO.Stream Test()
{
…
}
[WebGet(UriTemplate = "{id}")]
public System.IO.Stream GetById(string id)
{
…
}
}
It will be Test() if the application is deployed to early IIS versions, but will be GetById() if IIS 8.5(Windows 8.1)
Troubleshooting
In order to understand the different behaviors, I added Sleep() call to the 2 web methods, so that after sending a request to IIS, I had time to capture a memory dump to the IIS w3wp.exe. .Net memory objects can be found in dump files.
By comparing the .Net objects on the call stacks, I found their requests’ URL path strings were different:
IIS 7.5
/route/test.svc/$test
IIS 8.5
/route/test.svc/%24test
Conclusion
Obviously the path string is URL encoded in IIS 8.
By searching the Internet, I can see IIS 8.5 applies URL encoding in order to be more compatible to the standards.
Solutions
If the application will be deployed to IIS 8.5, the routing attribute should be coded as following
[WebGet(UriTemplate = "%24test")]
Or we can add below configuration in web.config, so that asp.net handles the URL string in a standard compatible way(the IIS 8 way). However this option is only available since .net framework version 4.5.1
<configuration>
<appSettings>
<add key="aspnet:UseLegacyRequestUrlGeneration" value="true" />
</appSettings>
More information
https://msdn.microsoft.com/en-us/library/hh975440.aspx
https://forums.iis.net/t/1203086.aspx
Juntao Zhu from GBSD DSI Team