As promised at the end of Custom WCF Services in SharePoint 2010 – Part 1 we take a look at another approach to configuring our custom service. This approach also has another benefit that allows us to get around an issue that appears to exist with the Microsoft implementation of the Factories provided in the Microsoft.SharePoint.Client.Services namespace.
Custom Factory Configuration
Rather than using a Feature as described in Part 1, we can derive our own custom factory from the default Microsoft one and perform our configuration there.
Custom Factory
using System;
using System.Diagnostics;
using System.ServiceModel;
using System.ServiceModel.Channels;
using Microsoft.SharePoint.Client.Services;
namespace MyNamespace
{
public class MyFactory : MultipleBaseAddressBasicHttpBindingServiceHostFactory
{
protected override ServiceHost CreateServiceHost(Type serviceType,
Uri[] baseAddresses)
{
ServiceHost host = new MultipleBaseAddressBasicHttpBindingServiceHost(
serviceType, baseAddresses);
if (host != null)
{
host.Opening += new EventHandler(OnHost_Opening);
}
return host;
}
private void OnHost_Opening(object sender, EventArgs e)
{
Debug.Assert(sender != null);
ServiceHost host = sender as ServiceHost;
Debug.Assert(host != null);
// Configure the binding values
if (host.Description != null && host.Description.Endpoints != null)
{
foreach (var endPoint in host.Description.Endpoints)
{
if (endPoint != null && endPoint.Binding != null)
{
BasicHttpBinding basicBinding = endPoint.Binding
as BasicHttpBinding;
if (basicBinding != null)
{
ConfigureBasicHttpBinding(basicBinding);
}
}
}
}
}
private static void ConfigureBasicHttpBinding(BasicHttpBinding basicBinding)
{
Debug.Assert(basicBinding != null);
basicBinding.MaxReceivedMessageSize = Int32.MaxValue;
basicBinding.ReaderQuotas.MaxArrayLength = Int32.MaxValue;
basicBinding.ReaderQuotas.MaxBytesPerRead = Int32.MaxValue;
basicBinding.ReaderQuotas.MaxStringContentLength = Int32.MaxValue;
}
}
}
So as you can see from the code we simply create the appropriate service host, and then hook up to the Opening event so that we can configure the binding settings.
We then adjust our service to call our custom factory rather than the default one:
Adjust Service Host
<%@ ServiceHost Language="C#" Debug="true"
Service="MyNamespace.MyService, $SharePoint.Project.AssemblyFullName$"
CodeBehind="MyService.svc.cs"
Factory="MyNamespace.MyFactory, $SharePoint.Project.AssemblyFullName$"%>
By Design or Bug?!
I mentioned at the beginning that this approach also allows us to sidestep an issue that appears to exist with the default implementation of the Microsoft provided factories in Microsoft.SharePoint.Client.Services namespace.
At this point in time, I’m still trying to determine whether there is a bug in the implementation of these factories, or it’s ‘by design’ and I’m trying to do something terribly evil
However, regardless of the ultimate outcome of the aforementioned, let’s take a look at how we can quickly break your nice shiny custom WCF Service:
Open up IIS Manager for the SharePoint site, and go to Advanced Settings:

By default you probably just have http listed in the Enabled Protocols…so add net.tcp as shown above. You will also need to add a Binding for this protocol:

When you now hit your service, you will get the following error:

The reason for this is that the MultipleBaseAddressBasicHttpBindingServiceHostFactory gets multiple baseAddresses provided in the CreateServiceHost call, and now that we have added net.tcp into the Enabled Protocols, one of those addresses is for net.tcp. However, the actual implementation of MultipleBaseAddressBasicHttpBindingServiceHost is not designed to work with non-http schema’s, and as a result explodes as shown in the above screenshot.
Thanks to using our own factory, we can easily fix this for our service by inserting a quick filter prior to calling the host constructor:
Filter to Http Only
// We only want to deal with http and https...ignore nettcp here...
var result = baseAddresses
.Where(ba => ba.Scheme.Equals(Uri.UriSchemeHttp)
|| ba.Scheme.Equals(Uri.UriSchemeHttps))
.Select(ba => ba);
ServiceHost host = new MultipleBaseAddressBasicHttpBindingServiceHost(
serviceType, result.ToArray());
Conclusion
Whilst things are now back to shiny status for our custom service, one has to wonder what else will be broken on the SharePoint site? Is there some rule out there that states that ‘thou shalt not add non-http protocols to a SharePoint site’? If so, please point me to it! (I have been looking and asking!) If not, that would seem to imply that the Microsoft factories need a little work done to them…
Print | posted on Wednesday, 29 June 2011 11:02 AM