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