<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:copyright="http://blogs.law.harvard.edu/tech/rss" xmlns:image="http://purl.org/rss/1.0/modules/image/">
    <channel>
        <title>wcf</title>
        <link>http://blog.kellybrownsberger.com/category/15.aspx</link>
        <description>wcf</description>
        <language>en-US</language>
        <copyright>kellyb</copyright>
        <generator>Subtext Version 2.1.0.5</generator>
        <item>
            <title>Testable WCF ServiceHost</title>
            <link>http://blog.kellybrownsberger.com/archive/2009/03/17/43.aspx</link>
            <description>&lt;p&gt;I’m finally getting a chance to sink my teeth into Windows Communication Foundation (WCF).  I’m finding quite a few gaps on the interoperability side of things, and I think it’s overly complex in it’s configuration schemes and extensibility points, but it’s light years beyond what we had previously in ASMX.  From what I can tell, the WCF adoption was just much slower than everyone anticipated.  I’m not sure why that is – perhaps it’s the vastness of it that’s intimidated people.  Perhaps it was the quality of the the .NET version 2.0 release that resulted in a slow adoption of all of version 3.0+.  For whatever reason, this seems to have caused a number of rough edges in the product to sit dormant for a couple of years now.  &lt;/p&gt;  &lt;p&gt;At any rate, WCF is now part of my every day day-job, and I’m trying to find ways to make it more testable.  We have a suite of what I’d call System Tests.  Unit Tests by my definition, test at the object (or component) boundary while System Tests test at a collection of objects (or components).  Our system is highly configurable, and behaviors vary dramatically from one configuration to the next.  We’d like to have the ability to have a repeatable suite of automated test that can test all of our out-of-the-box configurations.&lt;/p&gt;  &lt;p&gt;To date we’ve been executing our tests by .bat file (shelling to MbUnit.Cons.exe) after copying copies of our config files to our hosting IIS project.  This is less than awesome for a few reasons:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;&lt;strong&gt;It’s Slow and Flakey&lt;/strong&gt; – Running test out of process (which is what IIS is) is always slower than in-process.  Keep our test suite blazing fast is highly desirable.  Also, when you’re doing this kind of thing, it’s not uncommon to need to restart IIS between tests (IIS caching certain types of config data, etc.), which can really slow down the party.&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;It’s Heavy and Hard to Setup&lt;/strong&gt; – IIS is required to be installed on any machine that wants to run the tests.&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;It’s Awkward&lt;/strong&gt; – We must have .bat files that copy around our Web.config files that contain our test configuration before executing our tests.  The natural experience of running our tests directly from the IDE is lost.&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Luckily, WCF is highly extensible and customizable in it’s hosting infrastructure.  In the System.ServiceModel of the .NET Framework, they expose everything you need to easily create your own host for your WCF services.  We’ve all seen the MSN samples that hosts your hello-world service with a Console app.  To make our automated tests more awesome, I created a TestableServer service host implementation.&lt;/p&gt;  &lt;h3&gt;The Service&lt;/h3&gt;  &lt;p&gt;Lets say we have a service like this…&lt;/p&gt;  &lt;pre class="csharpcode"&gt;    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// Here's my service implementation&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; SomeService : ISomeService
    {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; DateTime GetCurrentDate()
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; DateTime.Now.Date;
        }
    }

    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// Here's my service contract for my implementation&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    [ServiceContract]
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; ISomeService
    {
        [OperationContract]
        DateTime GetCurrentDate();
    }&lt;/pre&gt;
&lt;style type="text/css"&gt;&lt;![CDATA[
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h3&gt;The Test&lt;/h3&gt;

&lt;p&gt;With the TestableServer, I can write a tidy little test like so…&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    [TestFixture]
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; SomeServiceFixture
    {
        [Test]
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Can_We_Invoke_GetCurrentDate()
        {
            &lt;span class="kwrd"&gt;using&lt;/span&gt; (TestableServer&amp;lt;SomeService, ISomeService&amp;gt; server = &lt;span class="kwrd"&gt;new&lt;/span&gt; TestableServer&amp;lt;SomeService, ISomeService&amp;gt;(&lt;span class="kwrd"&gt;new&lt;/span&gt; BasicHttpBinding()))
            {
                ISomeService proxy = server.CreateProxy();

                DateTime actual = proxy.GetCurrentDate();

                Assert.AreEqual(DateTime.Now.Date, actual.Date);
            }
        }
    }&lt;/pre&gt;
&lt;style type="text/css"&gt;&lt;![CDATA[
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;By passing a few generics, it has all the information it needs to host my service in-memory and I can execute tests against it directly.  Notice in the TestableServer constructor, I’m passing in the binding I’d like to use.  Here I can specify netTcpBinding, msmqBinding, or any of they other support bindings.  Here I’m using vanilla HTTP.&lt;/p&gt;

&lt;h3&gt;The Code&lt;/h3&gt;

&lt;p&gt;There’s not much to it at all, but here’s the code behind TestableServer…&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; TestableServer&amp;lt;TServiceImp, TServiceInt&amp;gt; : IDisposable &lt;span class="kwrd"&gt;where&lt;/span&gt; TServiceImp : &lt;span class="kwrd"&gt;class&lt;/span&gt;
    {
        &lt;span class="kwrd"&gt;private&lt;/span&gt; ServiceHost _host;
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; Type _serviceImplType = &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(TServiceImp);
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; Type _serviceIntType = &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(TServiceInt);
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; _url;
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; Binding _binding;
        &lt;span class="kwrd"&gt;private&lt;/span&gt; ChannelFactory&amp;lt;TServiceInt&amp;gt; _factory;
        &lt;span class="kwrd"&gt;private&lt;/span&gt; TServiceInt _channel;

        &lt;span class="kwrd"&gt;public&lt;/span&gt; TestableServer() : &lt;span class="kwrd"&gt;this&lt;/span&gt;(&lt;span class="kwrd"&gt;new&lt;/span&gt; NetTcpBinding()) { }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; TestableServer(Binding binding)
        {
            _host = &lt;span class="kwrd"&gt;new&lt;/span&gt; ServiceHost(_serviceImplType);
            _binding = binding;

            _url = &lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(&lt;span class="str"&gt;"{0}://localhost/{1}"&lt;/span&gt;, _binding.Scheme, Guid.NewGuid());
            _host.AddServiceEndpoint(_serviceIntType, _binding,  _url);

            &lt;span class="kwrd"&gt;try&lt;/span&gt;
            {
                _host.Open();
                
            }
            &lt;span class="kwrd"&gt;catch&lt;/span&gt; (TimeoutException timeoutEx)
            {
                Console.WriteLine(&lt;span class="str"&gt;"Failed to close the service host - Exception: "&lt;/span&gt; + timeoutEx.Message);
                &lt;span class="kwrd"&gt;throw&lt;/span&gt;;
            }
            &lt;span class="kwrd"&gt;catch&lt;/span&gt; (CommunicationException communicationEx)
            {
                Console.WriteLine(&lt;span class="str"&gt;"Failed to close the service host - Exception: "&lt;/span&gt; + communicationEx.Message);
                &lt;span class="kwrd"&gt;throw&lt;/span&gt;;
            }
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; TServiceInt CreateProxy()
        {
            _factory = &lt;span class="kwrd"&gt;new&lt;/span&gt; ChannelFactory&amp;lt;TServiceInt&amp;gt;(_binding);
            _channel = _factory.CreateChannel(&lt;span class="kwrd"&gt;new&lt;/span&gt; EndpointAddress(_url));
            
            &lt;span class="kwrd"&gt;return&lt;/span&gt; _channel;
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Dispose()
        {
            &lt;span class="kwrd"&gt;if&lt;/span&gt; ( _factory != &lt;span class="kwrd"&gt;null&lt;/span&gt; )
            {
                _factory.Close();
                _factory = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
            }

            TearDown();
        }

        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; TearDown()
        {
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (_host != &lt;span class="kwrd"&gt;null&lt;/span&gt;)
            {
                &lt;span class="kwrd"&gt;try&lt;/span&gt;
                {
                    &lt;span class="kwrd"&gt;if&lt;/span&gt; ( _host.State == CommunicationState.Opened || _host.State ==CommunicationState.Opening)
                    {
                        _host.Close();
                    }
                }
                &lt;span class="kwrd"&gt;catch&lt;/span&gt; (TimeoutException timeoutEx)
                {
                    Console.WriteLine(&lt;span class="str"&gt;"Failed to close the service host - Exception: "&lt;/span&gt; + timeoutEx.Message);
                }
                &lt;span class="kwrd"&gt;catch&lt;/span&gt; (CommunicationException communicationEx)
                {
                    Console.WriteLine(&lt;span class="str"&gt;"Failed to close the service host - Exception: "&lt;/span&gt; + communicationEx.Message);
                }
                &lt;span class="kwrd"&gt;finally&lt;/span&gt;
                {
                    _host = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
                }
            }
        }
    }&lt;/pre&gt;
&lt;style type="text/css"&gt;&lt;![CDATA[
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;

&lt;h3&gt;The Ultimate Goal&lt;/h3&gt;

&lt;p&gt;So, I haven’t actually achieved my ultimate goal yet, which is to be able to programmatically configure the server/service for each of our supported configurations and execute our test suites against those configurations.  That’s what I’m going to work on next, and without IIS between my test fixture and my service implementation, achieving that goal should be relatively simple.&lt;/p&gt;&lt;img src="http://blog.kellybrownsberger.com/aggbug/43.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>kellyb</dc:creator>
            <guid>http://blog.kellybrownsberger.com/archive/2009/03/17/43.aspx</guid>
            <pubDate>Wed, 18 Mar 2009 04:50:00 GMT</pubDate>
            <wfw:comment>http://blog.kellybrownsberger.com/comments/43.aspx</wfw:comment>
            <comments>http://blog.kellybrownsberger.com/archive/2009/03/17/43.aspx#feedback</comments>
            <slash:comments>1</slash:comments>
            <wfw:commentRss>http://blog.kellybrownsberger.com/comments/commentRss/43.aspx</wfw:commentRss>
        </item>
    </channel>
</rss>