WCF Multiple Binding / Multiple Hosts
Explorations In Code Series July 4th, 2008Consider this, you are a hosting company hosting many different customer websites. Your customers pay anywhere between $50.00 to $100.00 a month to have a shared server host there asp.net applications. You business model depends on easily providing the exact same level of support and features to your clients that they could otherwise get if they did it themselves, you can do so at a reduced rate because you cookie-cut their commonly requested features. The key is that you provide “the exact same” level of support and features.
The inability for you to provide something to them means you lose a piece of your market share and credibility. With hosting companies on razor thin profit margins, you rely on lots of low to mid-range consumers, and I mean lots of them. You’re effectively a wal-mart relying on the poor masses to accumulate large revenue through low over-head.
Now throw in a rather large WCF limitation…..
This collection already contains an address with scheme http. There can be at most one address per scheme in this collection.
Parameter name: item
Exception Details:
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
Source Error:
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.
Stack Trace:
[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) +4564833
System.Collections.Generic.SynchronizedCollection`1.Add(T item) +56
System.ServiceModel.UriSchemeKeyedCollection..ctor(Uri[] addresses) +120
System.ServiceModel.ServiceHost..ctor(Type serviceType, Uri[] baseAddresses) +145
System.ServiceModel.Activation.ServiceHostFactory.CreateServiceHost(Type serviceType, Uri[] baseAddresses) +28
System.ServiceModel.Activation.ServiceHostFactory.CreateServiceHost(String constructorString, Uri[] baseAddresses) +323
System.ServiceModel.HostingManager.CreateService(String normalizedVirtualPath) +516
System.ServiceModel.HostingManager.ActivateService(String normalizedVirtualPath) +31
System.ServiceModel.HostingManager.EnsureServiceAvailable(String normalizedVirtualPath) +498
Hosting multiple sites in Windows 2000-2008 Server typically means that your using IIS to host multiple sites on the same IP Address using host header filters or at worst port level filters.Now enter the above WCF “feature” (aka bug). The simple ability for you to host multiple WCF services for different hosted addresses in IIS is defunct. What does this mean to you? Well if your on a hosted environment (either internal cooperate network, or a classic joe’s hosting company) and you use IIS you are going to have to follow Rob Zelt instructions and it requires a code change!
Workaround #1: Customize your .svc file and use a custom WCF factory.
< %@ServiceHost language=c# Debug="true" Service="Microsoft.ServiceModel.Samples.CalculatorService" Factory="Microsoft.ServiceModel.Samples.CustomHostFactory" %>
class CustomHostFactory : ServiceHostFactory
{
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
CustomHost customServiceHost =
new CustomHost(serviceType, baseAddresses[1]);
return customServiceHost;
}
}
class CustomHost : ServiceHost
{
public CustomHost(Type serviceType, params Uri[] baseAddresses)
: base(serviceType, baseAddresses)
{ }
protected override void ApplyConfiguration()
{
base.ApplyConfiguration();
}
}
The reason for this mess is that ServiceHost uses the protocol (string value “http”, “https”) as the key for the BaseAddresses collection. This likely looks something like this inside the core .NET library.
IDictionary<string , string[]> _protocols = new Dictionary</string><string , string[]>();
private void RegisterProtocol(string protocol, string[] addresses) {
// whoops, we forgot to check if _protocols already had the key "protocol".... shucks...
_protocols.Add(protocol, addresses);
}
Somebody had reported that this has been fixed in what was “Orcas” but last I checked it hasn’t.
There is one other workaround (care-of: Jon Flander’s Blog) which involves changing the way you actually host your sites. Albeir this is not something feasible for a hosting provider.
Workaround #2: A way to solve this problem is to setup multiple web sites in IIS (rather than having one site that has multiple Host entries) - and point all the websites to the same directory.
This is, all in all, a great annoyance which will hopefully be fixed in later releases of .NET.
Recent Comments