Welcome

You have reached the blog of Keith Elder. Thank you for visiting! Feel free to click the twitter icon to the right and follow me on twitter.

Configuring WCF and IIS 7 With HTTP Bindings and Multiple Host Headers

Posted by Keith Elder | Posted in .Net, WCF | Posted on 28-04-2008

If you’ve tried to deploy Windows Communication Foundation (WCF)  in a production environment the odds are you have come across this error at one point or another:

This collection already contains an address with scheme http.  There can be at most one address per scheme in this collection. Parameter name: item

It is one of those lovely errors that should have been gumped down before it made it into production code but for some reason the developer who wrote it thought they’d sound smarter if they obfuscated the problem to confuse everyone.  No fear, I’m hear to clear this up and gump it down to save you endless hours of time. 

The Problem

In multiple shared hosting environments or even in the enterprise where load balancers are used it isn’t uncommon to have a single machine answer to multiple host names.  This is typically the problem that causes the error above since IIS has more than one http binding configured to answer requests for a given web site.  To simulate this I am going to walk you through how to create a fake configuration so your local development machine answers to more than one host name.  Then I’ll walk you through how to configure IIS7 to deploy a WCF service to your local machine using one name, and then break the deployment to simulate the error above.  After that we’ll fix it.

Here is the overall goal of the walk through. 

  1. Configure our machine to answer multiple host names
  2. Setup IIS to support our application
  3. Deploy the sample WCF application
  4. Add the second host name to break the deployment
  5. Apply the fix

Requirements

A few months ago I did a walk through on how to configure WCF with multiple bindings.  We are going to take that example and deploy it into IIS.  I’ll be deploying this solution on Windows Vista SP1 using IIS7.  Even if you are using Windows Server 2008 the same setup should be similar.  If you haven’t read the previous article on multiple bindings please do so.  At the bottom of the article download the sample solution, this is what we’ll be deploying if you want to follow along.

Configuring Extra Host Headers

Edit hosts file to add fake names

More than likely if you are performing this setup on a developer machine for testing you’ll need to create several fake host names for your machine.  To do this, open the following file c:\windows\system32\drivers\etc\hosts and add in a few fake names.  For this example I’m going to add two additional host names for my machine so it answers to the names of “Elderville” and “WordsOfWisdom”.  You can obviously choose what you want.  Here are the two entries I am going to add to my hosts file.

image

Note that you will need to be administrator to add these lines to this file.  The lines added resolve to the localhost IP address which is 127.0.0.1.  After these names are added you should be able to ping these host names and get a response.

image

Locally the computer now responds to two additional host names:  elderville and wordsofwisdom.

Initial IIS7 Configuration

In order to deploy our sample WCF service we need to have a location pre-configured.   Create the following path on your hard drive called C:\WCFTest\wcfservice.  Once created, open Internet Information Services manager as administrator and right click the sites folder to add a new web site.

image

Create a new web site to deploy the WCF service and use the path we just created to deploy the service.  I’m going to configure the service to answer using the host name of elderville.

image

After the site is created, convert the “wcfservice” folder into an application.

image

image

This is as far as we need to go as this moment with IIS.  We’ll come back to IIS7 configuration in a bit so leave it open if you are following along.  Right now we just want to deploy the service and make sure it works.

Deploying Our Sample WCF Service

Unzip the sample solution and open the solution in Visual Studio 2008.  In order to prepare the service for deployment the only change we need to make is to change the address of the endpoints.  There are three endpoints this service exposes: WsPlain, Basic and WsSecured.  The first endpoint of WsPlain doesn’t have an address listed in the endpoint properties.  This means it takes the endpoint address it is deployed within.  Each endpoint must have a different address so to get around this we are going to use relative addresses. 

Open the WCF Configuration Editor by right clicking the web.config file in the project and change the address of the Basic and WsSecured endpoints to the same name.  Here’s what they should look like after you make the change.

image

image

Using relative addresses appends the string in the address field to the end of our service address therefore making a different address location for each endpoint.  For example.  Since we are deploying our service as http://elderville/wcfservice/service.svc, the basic endpoint address will get converted to http://elderville/wcfservice/service.svc/Basic

This is the only change that is needed to deploy this service.  Now right click the WCF project and click “Publish”.  Set the target location to c:\wcftest\wcfservice as seen below and then click publish.

image

Open Internet Explorer and browse to the following URL:  http://elderville/wcfservice/Service.svc.  You should see your service page.

image

Reconfigure Windows Test App

To test the service, remove the existing service location from the Windows test project included in the solution.  Open the app.config file and remove the existing WCF client information (leave just the configuration xml elements).  Right click on the service reference within the project and paste the new address into the address field then press go.  Once it loads the service, press OK to add the reference to the project.

image

Next launch the Windows Application and click on the binding buttons to see the messages going back and forth with your service. 

image

At this point we’ve just setup IIS7 and deployed a WCF service.  Steps 1-3 are now complete.  Now let’s apply a more real world scenario to see what happens.

Breaking The Deployment

Based on our original goals we are now going to break this deployment. This is the real heart of this problem as this simulates a more real world example. 

To break this deployment we are going to add the second host name to the WCFTest site we created.  This is simulating is a shared hosting environment or an enterprise setup where load balancers are used.  Since I created “wordsofwisdom” as my secondary host name I am going to add that as an additional HTTP binding on the application.  This means my application will now answer to two names.

In the IIS7 configuration manager right click the application and edit the bindings.

image

The site’s configured bindings should only have one binding enabled which is the original host name entered when the site was originally configured.

image

Click add and enter the second host name the computer will answer as.  I entered the secondary host name of “wordsofwisdom”.

image

Press OK and both names should appear within the site bindings list. 

image 

To recap what we just configured, we setup IIS7 to answer requests for both of our host names.  Again this isn’t uncommon to have this type of configuration.

Now open the browser and browse to the previous working service.  You should see the error now.

This collection already contains an address with scheme http.  There can be at most one address per scheme in this collection. Parameter name: item

Since there are two names in the HTTP binding section it doesn’t know which one is the correct name to answer and thus the WCF service throws an exception. 

Fixing the Deployment

Depending on the .Net framework you are using the fix is different.  If you are using .Net 3.0 the only thing you can do to fix this is write a WCF custom ServiceHostFactory.   This work around is a little ugly and not something easy to standardize.  My suggestion is to upgrade to .Net 3.5 and take advantage of a new configuration option added in .Net 3.5 to solve this exact problem. 

The fix for .Net 3.5 uses a  new configuration element called <baseAddressPrefixFilters>

Represents a collection of configuration elements that specify pass through filters, which provide a mechanism to pick the appropriate Internet Information Services (IIS) bindings when hosting the Windows Communication Foundation (WCF) application in IIS.  A prefix filter provides a way for shared hosting providers to specify which URIs are to be used by the service. It enables shared hosts to host multiple applications with different base addresses for the same scheme on the same site.

To apply this fix open the web.config file for the service within Visual Studio and within the <system.serviceModel> tags add the following XML:

<serviceHostingEnvironment>
    <baseAddressPrefixFilters>
        <add prefix="http://elderville/wcfservice"/>
    </baseAddressPrefixFilters>
</serviceHostingEnvironment>

Once these lines are added, redeploy the service and refresh the service in the browser.  The error should be gone!

Conclusion

In this walk through we’ve covered a lot!  We walked through how to configure IIS7 and deploy an existing WCF service.  We also looked at the scenario that causes the error that a lot of developers run into when deploying WCF services in various environments.  The moral of this story is be safe and go ahead and plan on adding the baseAddressPrefixFilters tag into your web.config files from now on since you never really know how administrators will configure their servers. 

I hope you enjoyed this walk through.

  • During the podcast we also talk about what’s expected in BizTalk Server 2009 and why Microsoft chose to move forward with the release rather than opt for the much anticipated “Oslo”. 

     

  • Anonymous

    Have to upgrade IIS.

  • Maia Combs

    If and when necessary, BizTalk Development   can send XML messages again as a text files (Flat Files) by using another pipeline in the send ports, which will be responsible for transforming the XML into its equivalent the Flat File

  • I am happy when reading your blog with updated information! thanks alot
    and hope that you will post more site that are related to this site.

  • I follow above the steps to install multiple hosting in my server.Most of the people prefer to like this kind of valuable tips.

  • Jordi Montana

    Hi Keith!

    Nice article!

    Regarding the “Fixing the Deployment” section I’ve to tell you that MS really improved multiple site binding on .NET .4.0 . Please, feel free to review this article showing you how to emulate this approach on .NET 4.0.

    Greetings from Barcelona!

    Jordi

  • Cmr

    Good Article.  Your sidebar is one of the most annoying I’ve come across on the internet though.

  • Anonymous

    I don’t have specifed any host headers in IIS7, but i have two bindings: http 80, http 81.
    Not sure what to type in the filter, can anyone help ?

  • Anonymous

    Thaks

  • I’m a bit late to the conversation, but thanks for documenting this as it just saved my toosh.

    -Max

  • Anonymous

    Excellent article, scratching my head for a while with this one. Used , problem solved. Thank you.

  • Thank you so much. I have tried a lot today but there was a light at the end of the day being your website. I have solved my problem and is very happy. Made you some money :-))

  • Anonymous

    Everything worked OK except at the end when running client project it would come up with error : Could not find a base address that matches scheme http for the endpoint with binding WSHttpBinding. Registered base address schemes are []. Any idea why?

  • Anonymous

    This might not be a good place to ask but can you answer the following thread:

    social.msdn.microsoft.com/…/c1c30540-5b59-42e…

  • Anonymous

    Hello Keith
    http://elderville/wcfservice/service.svc would be accessible from different machine as well?

  • You just saved my sanity!
    I did an upgrade to 2003/installed 3.0 & 3.5
    used the
    and have managed to host my service!

    Thank YOU@!

  • @graffic

    You are looking to solve a completely different problem than what is outlined in this article.

    Calm down, take deep breaths, it will be ok.

    Having a wcf service answer with multiple host names is a problem, currrently I do not have a solution but am working on one.

  • Solution? A solution fixes a problem, not shows you the problem again.

    Let me explain this. The problem is that we cannot use a service from different host names. Your solution doesn’t solve this problem. Still we cannot use the service from different host names.

    You propose to live with that restriction, and what you call solution is just a way to execute the service through one of the hosts.

    But that’s not a solution to the problem.

  • Anonymous

    Thanks. I found other solutions but yours was very thorough. And thanks to Chris for the BaseAddressPrefixFilters tip, that is what we’ll use.

  • @Shweta

    Absolutely not. WCF cannot be used with anything but IIS6 and specifically should be used with IIS7 as IIS6 is limited in which WCF bindings it can support.

  • Anonymous

    If I want to do the same thing on IIS 5.1, then how can I do it ?

  • Anonymous

    Why in this video learn.iis.net/page.aspx/372/serving-new-content/
    the guy just bind the name to the site inside IIS 7 and instead form me it didn’t work till I’ve edited the host file as you said? I’m a bit confused…

  • Anonymous

    What I really cannot understand about this is:

    WHY can there not be multiple bindings per service?

    I thought WCF was supposed to make our lives easier, etc., etc.?

    I actually want my service to be able to respond on different hosts. It seems I’m unable to do this, even with this baseAddressPrefixFilters. Or am I massively missing something?

  • if you need all bindings to work and not simply pick one, here’s a post that describes how you can accomplish that (with some limitations):
    http://ranamauro.blogspot.com/2008/07/hosting-wcf-service-on-iis-site-with_25.html

  • Anonymous
  • Hi Keith,

    I took the ServiceHostFactory approach with a WCF service I wrote last year and deployed to IIS6 on Server 2003. The big problem was not being able to bind to specific host names on HTTPS. Does the baseAddressPrefixFilters element solve the problem for SSL too?

    Regards,