views:

169

answers:

2

When it comes to creating a new Service running on SharePoint 2010, people seem to usually use the Sharepoint MultipleBaseAddressBasicHttpBindingServiceHostFactory.

However, I would like to use the standard .net/WCF WebScriptServiceHostFactory instead because this gives me JavaScript code by calling the Service URL with /js.

My Service Class itself is still decorated with the required Attributes:

[BasicHttpBindingServiceMetadataExchangeEndpoint]
[AspNetCompatibilityRequirements(RequirementsMode =
         AspNetCompatibilityRequirementsMode.Required)]
[ServiceBehavior(Namespace = "http://mycompany/namespace")]
public class MyService : IMyServiceContract

The whole Service actually works fine, but I just wonder what the real differences are? What would the SharePoint ServiceHostFactory give me?

+1  A: 

What would it give you ... a headache maybe ? :-) Well, it would be the first time SharePoint hasn't given someone a headache :-)) OK just to be safe - check that your code still has full and equal access to SharePoint's objects and that credentials / security context hasn't changed.

ZXX
+3  A: 

This is a great question! My curiosity finally got the better of me, and I started poking around in Reflector. It's not the authoritative final answer, but I think you'll be interested in what I learned.

First off: MultipleBaseAddressBasicHttpBindingServiceHostFactory simply generates MultipleBaseAddressBasicHttpBindingServiceHost objects; WebScriptServiceHostFactory simply generates WebScriptServiceHost objects.

Both hosts inherit System.ServiceModel.ServiceHost, so they have a healthy base of common ground. Lucky for us, this reduces the size of the code footprint we must inspect to get a fair comparison.

Now, though there's not much new code in each class, they quickly branch off in different directions. Take a look at the OnOpening() implementations.

In WebScriptServiceHost we have:

base.OnOpening();
WebServiceHost.AddAutomaticWebHttpBindingEndpoints(
    this,
    base.ImplementedContracts,
    SR2.GetString(SR2.JsonWebScriptServiceHostOneServiceContract, base.ImplementedContracts.Count));
foreach (ServiceEndpoint endpoint in base.Description.Endpoints)
{
    if (endpoint.Binding != null &&
        endpoint.Binding.CreateBindingElements().Find<WebMessageEncodingBindingElement>() != null &&
        endpoint.Behaviors.Find<WebHttpBehavior>() == null)
    {
        endpoint.Behaviors.Add(new WebScriptEnablingBehavior());
    }
}

Unless I am mistaken, the line reading endpoint.Behaviors.Add(new WebScriptEnablingBehavior()); is responsible for the URL behavior (/js) you want.

Now, in MultipleBaseAddressBasicHttpBindingServiceHost, we have (abbreviated):

ClientServiceHost host = ClientServiceHost.CreateServiceHost();
this.CreateEndpoints();
base.OnOpening();
host.OnServiceHostOpeningInternal(this);

The differences between WebServiceHost.AddAutomaticWebHttpBindingEndpoints() and this.CreateEndpoints() were not abundantly clear to me. I got the impression that the SharePoint host contained more automatic configuration support for different authentication models.

ClientServiceHost.CreateServiceHost() is a factory method that creates a ClientServiceHost object based on a type listed in the web.config section microsoft.sharepoint.client/serverRuntime.

The OnServiceHostOpeningInternal() method simply forwards the call to the host's OnServiceHostOpening() method. Looking at the web.config of a default install, we find the assembly qualified name for the service host type, from which we can inspect the method:

<serverRuntime>
  <hostTypes>
    <add type="Microsoft.SharePoint.Client.SPClientServiceHost, Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
  </hostTypes>
</serverRuntime>

Here's where it gets interesting. The OnServiceHostOpening() method looks like this:

[SharePointPermission(SecurityAction.Demand, ObjectModel=true)]
protected override void OnServiceHostOpening(ServiceHost serviceHost)
{
    if (serviceHost != null)
    {
        SPUtility.ConfigServiceHostIfClaimsAuth(serviceHost);
    }
}

Drilling in further, we see a metric boatload of logic surrounding configuring a host for claims-based authentication.

Aha! There is a difference worth noting. Unless I'm mistaken, there's no claims-based authentication support in WebScriptServiceHost.

Conclusion

Perhaps you are not using claims-based authentication. If so, you might find that using WebScriptServiceHost is fine. However, were it me writing the service, I'd create a new host and host factory inheriting the Microsoft types, and see if I could create the /js extension by using endpoint.Behaviors.Add(new WebScriptEnablingBehavior(). The worst thing that could happen is that it wouldn't work. On the other hand, if it does work, you could expect to have a highly-SP-compatible service host factory that supports your endpoint preferences.

I hope this helps.

kbrimington
Thanks a lot, that is a very detailed explanation, especially the WebScriptingBehavior part is really useful!
Michael Stum