How To Consume WCF in a Web Part Without Touching The Web.config File

Posted: Jon | Comments: 3 | January 10th, 2011
Jan 10

You don’t need me to tell you all about how the Windows Communication Foundation is the bees knees. But I’m totally going to anyway. The clean, interface-based code practically writes itself, and its powerful configurability allows that same code to straddle nearly any imaginable digital boundary like a .NET Babel fish. Beast—as the kids say—for development of loosely coupled system components.

But we are the SharePoint developers, and we are the builders of ships in bottles.

Sorry, that wasn’t quite as catchy as the Gene Wilder in my head made it sound. Maybe next time I’ll just toot my little tin pipe.

Where’s Your Endpoint Now?

On a recent project, your humble narrator found himself needing to harvest some data from a WCF service for display in that most common of SharePoint development scenarios, the custom Web Part. It quickly dawned upon my tiny intellect, however, that in a Web Part project, there is no config file in which to define the bindings and endpoints required by a Service Reference. What, then, was an enterprising young Web Part developer cum WCF consumer to do?

The kneejerk riposte from the usual gang of portal warriors is to just add the necessary bindings to the web.config of the target site when you deploy.

You know, like an animal.

Some of us, however, could very likely find ourselves in a Continuous Integration-type scenario in which the deployment process must be a fully automated one, and performing repeated trauma surgery on config files across multiple environments is not an option.

Here is the relevant extensible markup typically generated by Visual Studio when adding a reference to a WCF Service:

<system.serviceModel>
    <bindings>
        <basicHttpBinding>
            <binding name="BasicHttpBinding_IAmAService" closeTimeout="00:01:00"
                openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
                maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
                messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
                useDefaultWebProxy="true">
                <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                    maxBytesPerRead="4096" maxNameTableCharCount="16384" />
            </binding>
        </basicHttpBinding>
    </bindings>
    <client>
        <endpoint address="http://url.to/a/wcfService.svc"
            binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IAmAService"
            contract="AServiceReference.IAmAService" name="BasicHttpBinding_IAmAService" />
    </client>
</system.serviceModel>

But how can we represent these parameters, sans markup, to our Web Part-bound WCF code?

One option is to employ the SPWebConfigModification API, programmatically adding the entries to the site’s web.config, probably via feature event receiver. However, this approach requires that a horror show of a string literal splatter its way across your beautiful code in an unsubtle manner:

var webConfigMod = new SPWebConfigModification();
webConfigMod.Path = "configuration/system.serviceModel";
webConfigMod.Sequence = 0;
webConfigMod.Owner = System.Threading.Thread.CurrentPrincipal.Identity.Name;
webConfigMod.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
webConfigMod.Value = @"<bindings><basicHttpBinding><binding name=&quot;BasicHttpBinding_IAmAService&quot; closeTimeout=&quot;00:01:00&quot; openTimeout=&quot;00:01:00&quot; receiveTimeout=&quot;00:10:00&quot; sendTimeout=&quot;00:01:00&quot; allowCookies=&quot;false&quot; bypassProxyOnLocal=&quot;false&quot; hostNameComparisonMode=&quot;StrongWildcard&quot; maxBufferSize=&quot;65536&quot; maxBufferPoolSize=&quot;524288&quot; maxReceivedMessageSize=&quot;65536&quot; messageEncoding=&quot;Text&quot; textEncoding=&quot;utf-8&quot; transferMode=&quot;Buffered&quot; useDefaultWebProxy=&quot;true&quot;><readerQuotas maxDepth=&quot;32&quot; maxStringContentLength=&quot;8192&quot; maxArrayLength=&quot;16384&quot; maxBytesPerRead=&quot;4096&quot; maxNameTableCharCount=&quot;16384&quot; /></binding></basicHttpBinding></bindings><client><endpoint address=&quot;http://url.to/a/wcfService.svc&quot; binding=&quot;basicHttpBinding&quot; bindingConfiguration=&quot;BasicHttpBinding_IAmAService&quot; contract=&quot;AServiceReference.IAmAService&quot; name=&quot;BasicHttpBinding_IAmAService&quot; /></client>";

SPWebService service = SPWebService.ContentService;
service.WebConfigModifications.Add(webConfigMod);
service.Update();
service.ApplyWebConfigModifications();

And it’s not just the pulchritude of your bits that will suffer with this approach. If you should need to alter this configuration, you are stuck pecking through a haystack of monochrome text. Remember developing in monochrome text?

It’s okay, you can stop sucking your thumb now. There’s another way, and it does include syntax highlighting.

We may not have access to a config file that will be deployed willingly to our SharePoint server. But we do have access to .NET code, which is what the traditional WCF XML translates to under the hood anyway.

You see where I’m going with this.

using System;
using System.ServiceModel;
using System.Xml;

namespace Aptera.BlogSamples.WCFWebPart
{
    /// <summary>
    /// A code-based configuration for a WCF Service for use in Web Part code, 
    /// which isn't gangsta enough to have access to a .config file.
    /// </summary>
    public class AServiceConfiguration
    {
        /// <summary>
        /// Gets a configured binding for the service.
        /// </summary>
        public static BasicHttpBinding Binding
        {
            get
            {
                BasicHttpBinding _binding = new BasicHttpBinding()
                {
                    Name = "BasicHttpBinding_IAmAService",
                    CloseTimeout = new TimeSpan(0, 1, 0),
                    OpenTimeout = new TimeSpan(0, 1, 0),
                    ReceiveTimeout = new TimeSpan(0, 10, 0),
                    SendTimeout = new TimeSpan(0, 1, 0),
                    AllowCookies = false,
                    BypassProxyOnLocal = false,
                    HostNameComparisonMode = HostNameComparisonMode.StrongWildcard,
                    MaxBufferSize = 65536,
                    MaxBufferPoolSize = 524288,
                    MaxReceivedMessageSize = 65536,
                    MessageEncoding = WSMessageEncoding.Text,
                    TextEncoding = System.Text.Encoding.UTF8,
                    TransferMode = TransferMode.Buffered,
                    UseDefaultWebProxy = true,
                    ReaderQuotas = new XmlDictionaryReaderQuotas()
                    {
                        MaxDepth = 32,
                        MaxStringContentLength = 8192,
                        MaxArrayLength = 16384,
                        MaxBytesPerRead = 4096,
                        MaxNameTableCharCount = 16384
                    }
                };

                return _binding;
            }
        }

        /// <summary>
        /// Gets the endpoint for the service.
        /// </summary>
        public static EndpointAddress Endpoint
        {
            get { return new EndpointAddress("http://url.to/a/wcfService.svc"); }
        }
    }
}

The above listing is simply a C# translation of the binding and endpoint data contained in the XML. Far easier on the eyes, and way less wear-and-tear on the horizontal scrollbar.

To use this code-based configuration, we simply instantiate our client with the constructor overload that allows us to pass in our BasicHttpBinding and EndpointAddress objects:

var client = new AServiceClient(
    AServiceConfiguration.Binding, AServiceConfiguration.Endpoint);
var omgResult = client.SuperAwesomeMethodCall("best parameter ever");
3 comments
  1. Tweets that mention How To Consume WCF in a Web Part Without Touching The Web.config File - SharePoint Development -- Topsy.com says:

    [...] This post was mentioned on Twitter by Aptera Software. Aptera Software said: New on our SharePoint Blog! How To Consume WCF in a Web Part Without Touching The Web.config File http://bit.ly/gPAfkY [...]

  2. Aleem says:

    This is clean and cool. Thanks.

  3. SvenG says:

    Thanks for sharing!

Leave a Comment