Fun with JSON and WCF

One of the projects I am working on at home is something like a media player web application which I use to listen to my favorite music from anywhere. It has a backend database which keeps the music files in a way which allows fast search on information about the files from the tags in the files. The files are then played in a handcrafted media player written in Silverlight 2.0. This being a fancy web 2.0 application, I use AJAX to search the database and return the results as JSON objects. Luckily enough, WCF supports you with this since .net 3.5. All you basically need to do is create a WCF service for your web project in Visual Studio 2008 (SP1). Then you even have IntellliSense support for the client side wrapper of the service, which of course gets generated automatically. On top of this, you do not have to care too much about inter-browser compatibility: The generated scripts with the base libraries work fine with both IE and Firefox.

If on the other hand, you are running the application on a virtual site in IIS which supports multiple host headers (let’s say: foo.bar.com and www.foo.bar.com) you’re likely to run into an exception like the following.

[ArgumentException: This collection already contains an address with scheme http. There can be at most one address per scheme in this collection.
Parameter name: item]
   System.ServiceModel.UriSchemeKeyedCollection.InsertItem(Int32 index, Uri item) +11520590
   System.Collections.Generic.SynchronizedCollection`1.Add(T item) +67
   System.ServiceModel.UriSchemeKeyedCollection..ctor(Uri[] addresses) +49
   System.ServiceModel.ServiceHost..ctor(Type serviceType, Uri[] baseAddresses) +129
   System.ServiceModel.Activation.ServiceHostFactory.CreateServiceHost(Type serviceType, Uri[] baseAddresses) +28
   System.ServiceModel.Activation.ServiceHostFactory.CreateServiceHost(String constructorString, Uri[] baseAddresses) +331
   System.ServiceModel.HostingManager.CreateService(String normalizedVirtualPath) +11659932
   System.ServiceModel.HostingManager.ActivateService(String normalizedVirtualPath) +42
   System.ServiceModel.HostingManager.EnsureServiceAvailable(String normalizedVirtualPath) +479

This indicates that a binding address which starts with http is already in use, when trying to automatically add the second address. The solution to this is as simple as updating your Web.Config file like shown here. Please take a look at line #9:

<configuration>
    <!-- ... -->
    <system.serviceModel>
        <behaviors>
            <!-- ... -->
        </behaviors>
        <serviceHostingEnvironment aspNetCompatibilityEnabled="true">
            <baseAddressPrefixFilters>
                <add prefix="http://foo.bar.com" />
            </baseAddressPrefixFilters>
        </serviceHostingEnvironment>
        <services>
            <!-- ... -->
        </services>
        <bindings>
            <!-- ... -->
        </bindings>
    </system.serviceModel>
</configuration>

Addendum from Feb 6: Apparently I was not entirely correct about using the service on a site with multiple host headers. While the above changes to Web.config fix the initial problem, they introduce a new problem. You’ll realize that this will work only for the requests using one of the host headers. The request to the service using the other host headers will throw a 404. This is a reported bug and will hopefully be fixed soon.