SharePoint 2010 – Have to Extend to have Multiple URLs

I think this was a best practice in SharePoint 2007, but was one that you could get away with.  You have internal and external URLs that will be used to access the same web application.   Internally for historical or vanity reasons this is set as something like http://companyname, externally you provide access, often via a proxy like ISA Server, via https://extranet.companyname.com – and you do SSL termination at the ISA server as well.

You create the web application using the internal name,  get everything setup and then do the following to provide external access

This scenario would work well,  you would cut down on the web.configs to be maintained – assuming you didn’t use features to do this for you, and you would have a slightly lower overhead on the server – which was often needed in the 32bit setups.

Problems in 2010  (and for some in 2007)

With the introduction of the client API, and a few other services, Microsoft is now making use of the WCF for its web services.   These offer lots and lots of advantages,  but have one limitation (at least in 3.5) that makes the above scenario fail. 

You cannot have multiple bindings on any IIS website

If you do set your environment up this way and you are using the client API you will hit problems.  Assuming you have coded you client requests with a fail delegate (like this code snippet)

  1: var lists;
  2: var context;
  3:
  4: function sample() {
  5:     context = new SP.ClientContext.get_current();
  6:
  7:     this.site = context.get_web();
  8:
  9:     context.load(this.site);
 10:
 11:     lists = site.get_lists();
 12:     context.load(lists);
 13:
 14:     context.executeQueryAsync(onPass, onFail);
 15: }
 16:
 17: function onFail(sender, args) {
 18:     alert("Fail:" + args.get_message() + '\n' + args.get_stackTrace());
 19: }
 20:
 21: function onPass(sender, args) {
 22:     onPass(lists.getByTitle('List'));
 23: }

when the async mehtod is called it will fail and the onFail method will show a 500 error.  One of the best things is the logging in 2010 has been improved so a quick look on the server and you should see something like the following in the event log:

Log Name:      Application
Source:        System.ServiceModel 3.0.0.0
Date:          31/12/2009 16:22:06
Event ID:      3
Task Category: WebHost
Level:         Error
Keywords:      Classic
User:          domain\sp-admin
Computer:      computername
Description:
WebHost failed to process a request.
 Sender Information: System.ServiceModel.ServiceHostingEnvironment+HostingManager/2389992
 Exception: System.ServiceModel.ServiceActivationException: The service '/_vti_bin/client.svc'
cannot be activated due to an exception during compilation.
The exception message is: 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.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
   at System.ServiceModel.UriSchemeKeyedCollection.InsertItem(Int32 index, Uri item)
   at System.Collections.Generic.SynchronizedCollection`1.Add(T item)
   at System.ServiceModel.UriSchemeKeyedCollection..ctor(Uri[] addresses)
   at System.ServiceModel.ServiceHost..ctor(Type serviceType, Uri[] baseAddresses)
   at System.ServiceModel.Activation.ServiceHostFactory.CreateServiceHost(Type
serviceType, Uri[] baseAddresses)
   at System.ServiceModel.Activation.ServiceHostFactory.CreateServiceHost(
String constructorString, Uri[] baseAddresses)
   at System.ServiceModel.ServiceHostingEnvironment.HostingManager.CreateService(
String normalizedVirtualPath)
   at System.ServiceModel.ServiceHostingEnvironment.HostingManager.ActivateService(
String normalizedVirtualPath)
   at System.ServiceModel.ServiceHostingEnvironment.HostingManager.EnsureServiceAvailable(
String normalizedVirtualPath)
   --- End of inner exception stack trace ---
   at System.ServiceModel.ServiceHostingEnvironment.HostingManager.EnsureServiceAvailable(
String normalizedVirtualPath)
   at System.ServiceModel.ServiceHostingEnvironment.EnsureServiceAvailableFast(String relativeVirtualPath)
 Process Name: w3wp
 Process ID: 3924
Event Xml:
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
  <System>
    <Provider Name="System.ServiceModel 3.0.0.0" />
    <EventID Qualifiers="49154">3</EventID>
    <Level>2</Level>
    <Task>5</Task>
    <Keywords>0x80000000000000</Keywords>
    <TimeCreated SystemTime="2009-12-31T16:22:06.000000000Z" />
    <EventRecordID>99264</EventRecordID>
    <Channel>Application</Channel>
    <Computer>computername</Computer>
    <Security UserID="S-1-5-21-2646386180-1731120971-3670236442-1114" />
  </System>
  <EventData>
    <Data>System.ServiceModel.ServiceHostingEnvironment+HostingManager/2389992</Data>
    <Data>System.ServiceModel.ServiceActivationException: The service '/_vti_bin/client.svc'
cannot be activated due to an exception during compilation.
The exception message is: This collection already contains an address with scheme http.
There can be at most one address per scheme in this collection.
Parameter name: item. ---&gt; System.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
   at System.ServiceModel.UriSchemeKeyedCollection.InsertItem(Int32 index, Uri item)
   at System.Collections.Generic.SynchronizedCollection`1.Add(T item)
   at System.ServiceModel.UriSchemeKeyedCollection..ctor(Uri[] addresses)
   at System.ServiceModel.ServiceHost..ctor(Type serviceType, Uri[] baseAddresses)
   at System.ServiceModel.Activation.ServiceHostFactory.CreateServiceHost(Type serviceType,
Uri[] baseAddresses)
   at System.ServiceModel.Activation.ServiceHostFactory.CreateServiceHost(String constructorString,
Uri[] baseAddresses)
   at System.ServiceModel.ServiceHostingEnvironment.HostingManager.CreateService(String normalizedVirtualPath)
   at System.ServiceModel.ServiceHostingEnvironment.HostingManager.ActivateService(String normalizedVirtualPath)
   at System.ServiceModel.ServiceHostingEnvironment.HostingManager.EnsureServiceAvailable(
String normalizedVirtualPath)
   --- End of inner exception stack trace ---
   at System.ServiceModel.ServiceHostingEnvironment.HostingManager.EnsureServiceAvailable(
String normalizedVirtualPath)
   at System.ServiceModel.ServiceHostingEnvironment.EnsureServiceAvailableFast(
String relativeVirtualPath)</Data>
    <Data>w3wp</Data>
    <Data>3924</Data>
  </EventData>
</Event>

 

The problem, although not obvious from the error message is related to the WCF framework not being able to work with multiple names on the same schema (where schema means HTTP).

Solution

The solution to this is to Extend the web application to another IIS web site.  It will make use of the same application pool but is likely to add a small overhear to the server.  The biggest challenge is to ensure that you get your deployments automated so that SharePoint can keep the web.config’s inline.   And with the introduction of the Sandboxed solution the other issues with artifacts deployed to the 80 (inetpub) folder will likely go away over time.

This entry was posted in SharePoint and tagged , , . Bookmark the permalink.
  • http://twitter.com/ssummone Steven Summone

    Thanks for the explanation Andrew very useful insight into the issue ;-)