Tag Archives: json

Fun with JSON and WCF, Part II

Following the web app I mentioned in Fun with JSON and WCF (Part I), I ran into another issue with WCF hosted in IIS and serving the callers through JSON objects. My application uses integrated windows authentication to authenticate the users and grant / deny access based on the given credentials. Therefore, I have turned off anonymous access for the entire virtual directory the application is running in and turned on integrated windows authentication. Now when invoking the JSON service, I get the following exception.

[NotSupportedException: Security settings for this service require 'Anonymous' Authentication but it is not enabled for the IIS application that hosts this service.]
   System.ServiceModel.Channels.HttpChannelListener.ApplyHostedContext(VirtualPathExtension virtualPathExtension, Boolean isMetadataListener) +11453217
   System.ServiceModel.Activation.VirtualPathExtension.ApplyHostedContext(TransportChannelListener listener, BindingContext context) +75
   System.ServiceModel.Channels.HttpTransportBindingElement.BuildChannelListener(BindingContext context) +119
   System.ServiceModel.Channels.BindingContext.BuildInnerChannelListener() +66
   System.ServiceModel.Channels.MessageEncodingBindingElement.InternalBuildChannelListener(BindingContext context) +67
   System.ServiceModel.Channels.WebMessageEncodingBindingElement.BuildChannelListener(BindingContext context) +47
   System.ServiceModel.Channels.BindingContext.BuildInnerChannelListener() +66
[...]

This indicates that according to the configuration of the service binding, anonymous access is to be allowed however IIS does not allow it. Apart from the fact that I don’t understand in the first place, why the service would care about this (if it was the other way around, I’d understand), fixing it is simple. It again requires changes in the Web.config, like follows.

<configuration>
    <!-- ... -->
    <system.serviceModel>
        <behaviors>
            <!-- ... -->
        </behaviors>
        <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
        <services>
            <service behaviorConfiguration="MyServiceTypeBehavior" name="MyService">
                <endpoint address="" behaviorConfiguration="MyServiceAspNetAjaxBehavior"
                          binding="webHttpBinding" bindingConfiguration="ServiceAuth"
                          contract="MyService" />
            </service>
        </services>
        <bindings>
            <webHttpBinding>
                <binding name="ServiceAuth">
                    <security mode="TransportCredentialOnly">
                        <transport clientCredentialType="Windows"/>
                    </security>
                </binding>
            </webHttpBinding>
        </bindings>
    </system.serviceModel>
</configuration>

The bindingConfiguration attribute on line 11 refers to the new webHttpBinding definition from lines 17 to 21. Client authentication is there specified to be integrated windows authentication.

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.