It’s been a long time since my last post here. Life has been quite busy, I’ve moved house twice, gotten married and on top of all of that there have been various projects (work and personal) that have competed for my attention. Last week was TechEd Africa 2011 and I was lucky enough to attend for the 4th year in a row. As ever it was a fantastic event, there where great speakers, great talks and fantastic exposure to so many new things and people.
At last years TechEd I entered a competition called Dev Idols where you have to give a 10 minute talk on anything development related. I learnt the hard way that 10 minutes is quite a challenging length for a presentation. I chose quite a technical topic and tried to cover way to much for a 10 minute presentation, if memory serves correct I came 4th. I entered the competition again this year, this time with 2 Dev4Devs under my belt and a better idea of what to expect. The result was a much more balanced talk and an overall better performance, which got me 1st place! It did help that the people who came in the top 3 last year either didn’t make it to the finals or weren’t allowed to enter because they where speakers at TechEd. I won free entrance into next years TechEd with the chance to be a speaker, this is both exciting and daunting!
For anyone interested in my presentation the slides and text can be found on my Skydrive at Dev Idols 2011.
I have come across 2 issues with deploying WCF services in a Silverlight solution, admittedly the one is more of a hiccup, and only occurs if you take the easy way out and reference your services through visual studio.
The First Issue
This occurs when you deploy your WFC services to an IIS server. When browse to the services using your web browser, you are greeted with “This collection already contains an address with scheme http. There can be at most one address per scheme in this collection.”. When you make a call to this service from your Silverlight application, you get the extremely helpful “NotFound” error, this error message can be found in the error property of the event arguments on the complete event handler for that call.
As it did with me this will leave most people scratching their head, because the very same services work just fine on the ASP.NET Development Web Server and on my local IIS server. Now I’m no server/hosting/IIS expert so I did a bit of searching when I first encountered this issue. I found out this happens because IIS supports multiple address bindings per protocol (http/https/ftp … etc) per web site, but WCF only supports binding to one address per protocol. This causes a problem when the WCF service is hosted on a site with multiple address bindings, because IIS provides all of the bindings to the host factory when running the service. While this problem occurs mainly on shared hosting solutions, it is not limited to shared hosting, it just seems like all shared hosting providers setup sites on their servers with multiple address bindings.
For interests sake I added functionality to the example project attached to this post to dump the addresses given to the WCF service by IIS into a log file. This was the output on the shared hosting solution I use:
http://mydomain.co.za/Services/TestService.svc
http://www.mydomain.co.za/Services/TestService.svc
http://mydomain-co-za.win13.wadns.net/Services/TestService.svc
http://win13/Services/TestService.svc
As you can see all these addresses are for the http protocol, which is where it all goes wrong for WCF.
Fixes for the First Issue
There are a few ways to get around this. The first being the easiest, target .NET 4! Yes that's right in .NET 4 WCF services support multiple addresses per protocol. This functionality is enabled by an option, which is on by default if you create a new project, you will need to turn on if you are upgrading to .NET 4. To do this set the multipleSiteBindingsEnabled property of the serviceHostingEnviroment tag in the web.config file to true, as shown below:
<system.serviceModel>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
Beware this ONLY works in .NET 4, so if you don’t have a server with .NET 4 installed on that you can deploy to, you will need to employ one of the other work a rounds.
The second option will work for .NET 3.5 & 4. For this option all you need to do is modify the web.config file and add baseAddressPrefixFilters to the serviceHostingEnviroment tag as shown below:
<system.serviceModel>
<serviceHostingEnvironment>
<baseAddressPrefixFilters>
<add prefix="http://www.mydomain.co.za"/>
</baseAddressPrefixFilters>
</serviceHostingEnvironment>
</system.serviceModel>
These will be used to filter the list of base addresses that IIS provides to the host factory. When specifying these prefix filters be sure to specify filters which will only allow 1 result through, otherwise the entire exercise will be pointless. There is however a problem with this work a round, you are only allowed to specify 1 prefix filter per protocol. Which means you can’t add filters for all your environments, this will therefore add to the list of things to do before deploying or switching dev machines.
The third option is the one I currently employ, it will work for .NET 3, 3.5 & 4, although it is not needed for .NET 4. For this option you create a custom host factory which inherits from the ServiceHostFactory class. In the implementation of the ServiceHostFactory you employ logic to figure out which of the base addresses, that are give by IIS, to use when creating the service host. The logic you use to do this is completely up to you, I have seen quite a few solutions that simply statically reference an index from the list of base addresses, this works for most situations but falls short in others. For instance, if the order of the base addresses where to change, it might end up returning an address that only resolves on the servers local network, like the last one in the example I gave at the beginning. Another instance, if a request comes in on a different protocol, like https, you will be creating the service host using an address which is on the incorrect protocol, like http.
To reliably find the correct address to use, I use the address that the service was requested on. To accomplish this I use the HttpContext, which requires the service to operate with AspNetCompatibilityRequirements set on. If for some reason running you services with AspNetCompatibilityRequirements on isn’t an option, you can still use this method, you will just have to come up with your own logic for selecting the correct address.
First you will need to enable AspNetCompatibilityRequirements for your hosting environment, to do this you will need to set it to true in the web.config file as shown below:
<system.serviceModel>
<serviceHostingEnvironment AspNetCompatibilityRequirements="true" />
</system.serviceModel>
You will then need to mark any services that are going to use the custom host factory, to allow AspNetCompatibilityRequirements, as shown below:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class TestService
{
}
Now for the custom host factory, this is where the logic lives that selects the correct address to create service host with. The one i use is shown below:
public class CustomHostFactory : ServiceHostFactory
{
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
//
// Compose a prefix filter based on the requested uri
//
string prefixFilter = HttpContext.Current.Request.Url.Scheme + "://" + HttpContext.Current.Request.Url.DnsSafeHost;
if (!HttpContext.Current.Request.Url.IsDefaultPort)
{
prefixFilter += ":" + HttpContext.Current.Request.Url.Port.ToString() + "/";
}
//
// Find a base address that matches the prefix filter
//
foreach (Uri baseAddress in baseAddresses)
{
if (baseAddress.OriginalString.StartsWith(prefixFilter))
{
return new ServiceHost(serviceType, baseAddress);
}
}
//
// Throw exception if no matching base address was found
//
throw new Exception("Custom Host Factory: No base address matching '" + prefixFilter + "' was found.");
}
}
The most important line in the custom host factory is the one that returns a new service host. This has to return a service host that specifies only one base address per protocol. Since I filter by the address the request came on in, I only need to create the service host with one address, since this address will always be of the correct protocol.
Now you have a custom host factory you have to tell your services to use it. To do this you view the markup of the service by right clicking on it in the solution explorer and choosing “View Markup”.

Then you add/set the value of the Factory property to the full namespace path of you custom host factory, as shown below.

And that is it done, the service will now use the specified custom host factory.
The Second Issue
As I mentioned earlier this issue is more of a hiccup, but I thought worthy of a mention so I included it. This issue only occurs when you add a service reference to a Silverlight project. Visual Studio will generate a lot of code for you, part of that generated code is the ServiceReferences.ClientConfig file. This file stores the endpoint configuration that is used when accessing your services using the generated proxy classes. Here is what that file looks like:
<configuration>
<system.serviceModel>
<bindings>
<customBinding>
<binding name="CustomBinding_TestService">
<binaryMessageEncoding />
<httpTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" />
</binding>
<binding name="CustomBinding_BrokenService">
<binaryMessageEncoding />
<httpTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" />
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="http://localhost:49347/services/TestService.svc"
binding="customBinding" bindingConfiguration="CustomBinding_TestService"
contract="TestService.TestService" name="CustomBinding_TestService" />
<endpoint address="http://localhost:49347/Services/BrokenService.svc"
binding="customBinding" bindingConfiguration="CustomBinding_BrokenService"
contract="BrokenService.BrokenService" name="CustomBinding_BrokenService" />
</client>
</system.serviceModel>
</configuration>
As you will notice the addresses for the end points are set to the addresses of the services you added the service references from, so unless you are adding the service references from your live services, you will have to change these addresses before you deploy. This is little more than an annoyance really, but it adds to the list of things to do before you can deploy, and if left unchecked that list can get out of control.
Fix for the Second Issue
The way you would usually access a service added this way is to create an instance of the proxy class like so:
BrokenServiceClient proxy = new BrokenServiceClient();
Closer inspection of these generated proxy classes reveals that there are a few overloaded constructors, one of which allows you to specify the end point address to use when creating the proxy. From here all you have to do is come up with some logic that will provide you with the relative path to your services. Since my WCF services are usually hosted in the same project as my Silverlight app I use the class shown below:
public class ServiceProxyHelper
{
/// <summary>
/// Create a broken service proxy
/// </summary>
/// <returns>A broken service proxy</returns>
public static BrokenServiceClient CreateBrokenServiceProxy()
{
Uri address = new Uri(Application.Current.Host.Source, "../Services/BrokenService.svc");
return new BrokenServiceClient("CustomBinding_BrokenService", address.AbsoluteUri);
}
}
Then I will create an instance of the proxy class using my service helper class like so:
BrokenServiceClient proxy = ServiceProxyHelper.CreateBrokenServiceProxy();
The way this works is “Application.Current.Host.Source” will return the URL to the ClientBin folder the Silverlight app is hosted in, the “../Services/BrokenService.svc” is then used as the relative path to the service from the ClientBin folder, combined by the Uri object this gives me the URL to my service. The “CustomBinding_BrokenService” is a reference to the end point configuration in the ServiceReferences.ClientConfig file. Yes this means you still need the ServiceReferences.ClientConfig file. All this is doing is using a different end point address than the one specified in the ServiceReferences.ClientConfig file, all the other settings form the ServiceReferences.ClientConfig file are still used when creating the proxy.
I have uploaded an example project which covers the custom host factory solution from the first issue and everything from the second issue. I included the code to write a list of base addresses to a log file in my implementation of the custom host factory, this is not need for the custom host factory to function and can safely be removed.
Download (WCFServicesDeploymentExample.zip)
Greetings to anyone reading this! This is my first of hopefully many posts. I would like to use this post to introduce myself and to let you know what to expect from this blog in future.
Okay so a bit about myself. In case you missed the name of this blog, my name is Brendon Page! I am a Software Developer from South Africa and work for a small company who’s main focus is producing software for the kitchen cupboard industry, although from time to time we do produce custom solutions for other industries. I work in a small team of 3, including myself, and am fortunate enough to work from home! I have been involved in IT since 1996, which is when I got my first PC, and started working as a junior programmer in 2003.
Outside of work I enjoy playing squash, PC Games and of course LANing with my friends. If I get any free time between all of that I will usually dedicate some of it to a personal project, these are mainly prototypes for an idea I have had or for something that could be useful at work.
I was in 2 minds on whether to include a photo of myself. The reason for this was because while I was looking for a suitable photo to use, it dawned on me how much time I dedicate to pulling funny faces in photos! I also realized how little I shave, which I blame completely on working from home. So after much debate here I am, funny face, beard and all!
Now that you know a bit about me lets move onto what expect from this blog. I work predominantly with Microsoft technologies so most if not all of my posts will be related to something Microsoft. Since most of my job entails Software Development you can expect a lot of posts which will deal with the .NET Framework. I am currently working on a large Silverlight project, so my first few posts will be targeted at in that direction. I will be striving to make the content of my posts as useful as possible from both an explanation and code perspective, I aim to include a working solution for every post, which I will put up on my skydrive for download.
Here is what I have planned for my next few posts:
Where did my session variables go?
Here I will take you through the lessons I learnt the hard way about the ASP.NET session. I am not going to go into to much depth in this post, as there is already a lot of information available on it. I mainly want to cover it in an effort to keep the scope creep of my posts to a minimum, some the solutions I upload will use it and I would like to have a post that I can reference to explain why I am doing something a certain way.
Uploading files through SIlverlight
Again there is a lot of existing information on this topic, so I wont be going into to much depth, but I will be using the solution from this as a base for my next post.
Generating and Displaying DeepZoom images dynamically in Silverlight
Well the title pretty much speaks for it’s self on this one. As I mentioned I will be building off the solution that I create in my ‘Uploading files through Silverlight’ post.
Securing DeepZoom images using a custom implementation of the MultiScaleTileSource
In this post I will look at the privacy issue surrounding the default usage of DeepZoom images in Silverlight and how to overcome it. This makes the use of DeepZoom in privacy conscious applications more viable.
Thanks to anyone who actually read this post! I look forward to producing more which will hopefully be helpful to you.