Thursday, July 29, 2010

Dependency Injection using Munq

I'm in the middle of a building a WCF Rest(ful) web service and I want to use some form of DI. I've used Daniel Cazzulino's Funq on a previous project and although it doesn't necessarily provide all the bells and whistles or have the market-share of some of the other frameworks it is extremely fast, easy to set up, and has a simple lambda-based configuration. It also comes with an awesome set of videos documenting the construction process, worth looking at just to see a developer doing some great TDD.

For a WCF or MVC project there are some constraints that would make Funq a bit more interesting to set up. Fortunately there is a derivative of Funq, Matthew Dennis's Munq project (example usage for ASP.NET MVC is available on CodeProject) that is intended for this purpose.

Using Munq for WCF differs from the ASP.NET MVC configuration example and I went through the exercise long enough ago that the only evidence I have is an old project that I've been trawling through to try and figure out how it is all wired together. I do recall following someone else's instructions (Oran Dennison's I think) for implementing a different IOC framework with WCF and modifying it for Munq. This particular blog entry is at least in part to avoid having go through the same head scratching exercise the next time I want to use DI in a WCF service.

My WCF service will be hosted in IIS and I created the initial project using the WCF REST Service Application template. The idea is to allow Munq to serve up instances of the service and Microsoft provides a convenient hook for doing this using the IInstanceProvider interface.

1  public class MunqInstanceProvider : IInstanceProvider
2  {
3
4      private readonly Type serviceType;
5
6      public MunqInstanceProvider(Type serviceType)
7      {
8          this.serviceType = serviceType;
9      }
10
11 #region Implementation of IInstanceProvider
12
13      /// <summary>
14     /// Returns a service object given the specified <see cref="T:System.ServiceModel.InstanceContext"/> object.
15     /// </summary>
16      /// <returns>
17     /// A user-defined service object.
18     /// </returns>
19     /// <param name="instanceContext">The current <see cref="T:System.ServiceModel.InstanceContext"/> object.</param>
20      public object GetInstance(InstanceContext instanceContext)
21     {
22         return GetInstance(instanceContext, null);
23     }
24
25     /// <summary>
26     /// Returns a service object given the specified <see cref="T:System.ServiceModel.InstanceContext"/> object.
27      /// </summary>
28     /// <returns>
29     /// The service object.
30     /// </returns>
31     /// <param name="instanceContext">The current <see cref="T:System.ServiceModel.InstanceContext"/> object.</param><param name="message">The message that triggered the creation of a service object.</param>
32      public object GetInstance(InstanceContext instanceContext, Message message)
33      {
34         var instance = Global.Di.Resolve(serviceType);
35         return instance;
36     }
37
38     /// <summary>
39     /// Called when an <see cref="T:System.ServiceModel.InstanceContext"/> object recycles a service object.
40     /// </summary>
41     /// <param name="instanceContext">The service's instance context.</param><param name="instance">The service object to be recycled.</param>
42      public void ReleaseInstance(InstanceContext instanceContext, object instance)
43     {
44         // container disposes of instance?
45         //if (instance is IDisposable)
46         // ((IDisposable)instance).Dispose();
47      }
48
49     #endregion
50 }

That call to Global.Di.Resolve() is where Munq returns an instance of the service. Global.Di needs to be defined somewhere, I'll get to that in a bit. Having implemented IInstanceProvider I now need to provide a custom serviceBehavior using the IServiceBehavior interface for the service endpoint. The following code creates a new MunqInstanceProvider for each ChannelDispatcher endpoint.

Note ForAll() is an extension method not included in .NET but defined as you might expect. For an explanation as to why it wasn't included in the framework refer to Eric Lippert's blog. For a long time I assiduously used a foreach loop to perform some action on every item in a sequence. Recently I've been reading Effective C# (Covers C# 4.0): 50 Specific Ways to Improve Your C#. Item 8 suggests I should Prefer Query Syntax to Loops and I absolutely do.

1 public class MunqServiceBehavior : IServiceBehavior
2 {
3     #region IServiceBehavior Members
4
5     public void AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters) {}
6
7     public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
8     {
9         var endpoints = from cd in serviceHostBase.ChannelDispatchers.Cast<ChannelDispatcher>()
10                 where cd != null
11                 from endpoint in cd.Endpoints
12                 select endpoint;
13
14         endpoints.ForAll(ep => ep.DispatchRuntime.InstanceProvider = new MunqInstanceProvider(serviceDescription.ServiceType));
15     }
16
17     public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase) {}
18
19     #endregion
20 }

Web.config is used to wire this all together but in order to reference the custom behavior a Munq-specific BehaviorExtensionElement is required.

1  public class MunqInstanceProviderExtensionElement : BehaviorExtensionElement
2  {
3      public override Type BehaviorType
4      {
5          get { return typeof (MunqServiceBehavior); }
6      }
7
8      protected override object CreateBehavior()
9      {
10          return new MunqServiceBehavior();
11     }
12 }

The relevant section of Web.config is provided below and replaces the system.serviceModel section. Getting each element correct is important but the stumbling block for me was getting the service name correct and I couldn't figure out why none of my Munq classes were being hit.

1  <system.serviceModel>
2      <serviceHostingEnvironment aspNetCompatibilityEnabled="true"
3                   multipleSiteBindingsEnabled="true" />
4       <services>
5           <service name="StillPearlingService.StillPearling" behaviorConfiguration="MunqServiceBehavior"></service>
6       </services>
7       <behaviors>
8          <serviceBehaviors>
9              <behavior name="MunqServiceBehavior">
10                  <MunqInstanceProvider />
11            </behavior>
12            <behavior name="">
13                <serviceMetadata httpGetEnabled="true" />
14                <serviceDebug includeExceptionDetailInFaults="false" />
15            </behavior>
16        </serviceBehaviors>
17     </behaviors>
18      <extensions>
19          <behaviorExtensions>
20              <add name="MunqInstanceProvider" type="StillPearling.IOC.MunqInstanceProviderExtensionElement, StillPearling, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
21          </behaviorExtensions>
22      </extensions>
23      <standardEndpoints>
24          <webHttpEndpoint>
25      <!--
26         Configure the WCF REST service base address via the global.asax.cs file and the default endpoint
27         via the attributes on the <standardEndpoint> element below
28     -->
29              <standardEndpoint name="" helpEnabled="true" automaticFormatSelectionEnabled="true" />
30          </webHttpEndpoint>
31      </standardEndpoints>
32 </system.serviceModel>


So having completed the majority of the wiring there is still the small matter of declaring and instantiating the Munq DI container. This happens in Global.asax, along with registering other objects I want to wire into the container. In this case I have a Model class that I use for accessing a database. Within my service I declare a Model property with a public setter that is used as a hook for Munq to inject the correct Model object.

1  public class Global : HttpApplication
2  {
3      private static Logger logger = LogManager.GetCurrentClassLogger();
4      public static Container Di { get; private set; }
5
6      void Application_Start(object sender, EventArgs e)
7      {
8           logger.Info(() => "Application_Start");
9           Di = new Container();
10         RegisterInterfaces();
11         RegisterRoutes();
12     }
13
14     private static void RegisterInterfaces()
15     {
16         logger.Debug(() => "RegisterInterfaces");
17         Di.Register<IStillPearlingModel>(di => new Model());
18         Di.Register(di => new StillPearling { Model = di.Resolve<IStillPearlingModel>(), });
19     }
20
21     private static void RegisterRoutes()
22     {
23         // Edit the base address of Service1 by replacing the "Service1" string below
24         RouteTable.Routes.Add(new ServiceRoute("StillPearlingService", new WebServiceHostFactory(), typeof(StillPearling)));
25     }
26 }
27

Note this was all done using Munq 1.0 and Munq 2.0 has recently been released. I don't expect any issues transitioning to version 2.0 but I'll try to provide an update if there are any potholes to be avoided. If you've read this far I appreciate it and I would further appreciate feedback on what I'm doing wrong. Finally I apologise for any formatting issues with the code above - I'm still looking for a good encoding tool that works with blogger.

Thursday, July 22, 2010

First things first?

Clearly if I want to play with F# & ASP.NET MVC I should get the Visual Studio 2010 project template from Tomas Petricek. Then after installing in Visual Studio I get a new option to create a F# MVC Web Application. Mostly it just works but the reference in WebApplication.Core to the WebApplication.Data project needs to be updated for it to build. BTW, if you're looking for a quickstart C# MVC project check out Rob Conery's Tekpub MVC 2.0 Starter, it has an associated starter video available free from Tekpub. This is not that.

So what about MSpec? The latest release is available from TeamCity. I'm using ReSharper 5.1 so installing MSpec is just a matter of unblocking zip file (aargh), unzipping, pathing to unzipped location and running the appropriate batch file - & '.\InstallResharperRunner.5.1 - VS2010.bat'  (why are we still using batch files).

Now I have the pieces of the puzzle but I'm not entirely sure how I'm supposed to assemble them. Using a post from Elegant Code as a starting point I added a test project to my solution and copied Jan's sample into UnitTest1.cs. Visual Studio doesn't know what is [Subject("Making a customer preferred")] which is resolved by first creating a "libs" folder in my solution folder and adding Machine.Specifications.dll to it, then adding a reference to that dll to my test project. Then in the interests of seeing some actual output I need to flesh out the sample code with sufficient code to allow the test to compile:

1 [Subject("Making a customer preferred")]
2 public class when_a_regular_customer_is_made_preferred
3 {
4     Establish context = () =>
5     {
6        _order = new Order(new[] { new OrderItem(12),
7            new OrderItem(16) });
8        _totalAmountWithoutDiscount = _order.TotalAmount;
9
10         SUT = new Customer(new[] { _order });
11    };
12
13 Because of = () =>
14     SUT.MakePreferred();
15
16 It should_mark_the_customer_as_preferred = () =>
17     SUT.IsPreferred.ShouldBeTrue();
18
19 It should_apply_a_ten_percent_discount_to_all_outstanding_orders = () =>
20     _order.TotalAmount.ShouldEqual(_totalAmountWithoutDiscount * 0.9);
21
22     private static Customer SUT;
23
24     private static Order _order;
25     private static Double _totalAmountWithoutDiscount;
26 }
27
28 //
29 // Subject under test
30 //
31 public class Customer
32 {
33     private readonly List<Order> _orders;
34     public Boolean IsPreferred { get; private set; }
35
36    public Customer(IEnumerable<Order> orders)
37     {
38         _orders = new List<Order>(orders);
39     }
40
41 public void MakePreferred()
42 {
43     if (IsPreferred)
44         return;
45
46    IsPreferred = true;
47     _orders.ForEach(order => order.ApplyDiscount(10));
48 }
49 }
50
51 public class Order
52 {
53     private OrderItem[] orderItems;
54
55     public Order(OrderItem[] orderItems)
56     {
57         // TODO: Complete member initialization
58         this.orderItems = orderItems;
59     }
60     public double TotalAmount { get; set; }
61     public double ApplyDiscount(int percentDiscount)
62     {
63         return TotalAmount*(100 - percentDiscount)/100;
64     }
65
66 }
67
68 public class OrderItem
69 {
70     private int p;
71
72     public OrderItem(int p)
73     {
74         // TODO: Complete member initialization
75         this.p = p;
76     }
77 }

Now I can run the unit test using ReSharper and sure enough I get the correct output:
Making a customer preferred, when a regular customer is made preferred
    » should mark the customer as preferred
    » should apply a ten percent discount to all outstanding orders
Obviously this is a contrived example but I have established that I can run MSpec tests in my solution. If at some point it no longer works I know it's my bad.

Wednesday, July 21, 2010

Exploring the ecosystem

There are a number of things on my todo list, including F#, ASP.NET MVC, MSpec, Munq, Moq and maybe an alternative markup engine such as StringTemplate. My other todo list includes HTML5, PhoneGap, and iPhone development. My Amazon order showed up a couple of weeks ago including Douglas Crockford's excellent JavaScript: The Good Parts, Building iPhone Apps with HTML, CSS, and JavaScript, and Expert F# 2.0.

I will admit to being a long time fan of JavaScript and it's nice to see it finally getting mind-share. Crockford's book is dense and contains a lot of good stuff and as a consequence I'm still working my way through it. I'm also still not entirely comfortable with the idea of modifying the prototypes of the predefined objects such as Object, String, etc, guess I'll reserve judgment until I'm finished reading.

As part of getting back up to date with JavaScript I've also started using QUnit to unit test a module I'm writing for accessing Safari's SQLite database. There are some excellent links here, and here (blog comments are particularly useful) re using QUnit for testing asynchronous calls. Calls to SQLite are all based on callbacks so being able to unit test asynchronously is essential.

Below is a very early example of the database access code I'm working on. Clearly I've got a long way to go but it's a start and demonstrates the module pattern I use to hide the internals. I plan to replace the database version update code so I can seamlessly update the database when upgrading the application version. I'm still trying to get my head around the K&R indenting which is now the most common indenting style in JavaScript. Having coded C++ for many years and subsequently C# I'm pretty committed to the Allman style indenting. But some of the reasons for using Allman style are no longer relevant and with LINQ in particular it is difficult (impossible?) to use Allman style consistently. In JavaScript there is at least one situation where using Allman style will result in code breaking. Douglas Crockford mentions this in his book:

I always use K&R style, putting the { at the end of a line instead of the front, because it avoids a horrible design blunder in JavaScript's return statement.
To really nail my Allman addiction I read a tweet recently from I think one of either Rob Conery or Dave Ward to the effect that JavaScript written using Allman was not to be trusted (hmm maybe it was Gruber, can't find the reference). So I guess my first job is to reformat using the new hotness and once again feel like I am worthy.

BTW, if anyone knows a good code formatter for Blogger I would be grateful, the one I used to produce the code below is not quite there.

1 var db = function ()
2 {
3 /**
4 * private
5 */
6 var CURRENT_VERSION = 1.01;
7 var shortName = 'rtt';
8 var version;
9 var displayName = 'Red Tomato Timesheet';
10 var maxSize = 65536; // bytes
11 var database;
12
13 var init = function(transaction) { console.info("Updating database to version 1"); };
14
15 var success = function(){ console.info("success");};
16 var failure = function(error){ console.info("fail: " + error);};
17
18 var up101 = function(t)
19 {
20     var sql = "\
21         CREATE TABLE projects (\
22             id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,\
23             name TEXT NOT NULL,\
24             description TEXT NOT NULL);";
25      console.info("sql:" + sql);
26      t.executeSql( sql, [], function(){ console.info("version 1.0 -> 1.01 success");});
27 };
28
29 var updateVersion = function()
30 {
31     console.info("Updating database to current version " + CURRENT_VERSION);
32     try
33      {
34         switch(version)
35         {
36             case '' : database.changeVersion('', '1', init, failure, success);
37             case "1" : database.changeVersion("1", "1.01", up101, failure, success);
38         }
39     }
40     catch (e)
41     {
42         console.error("database.changeVersion failed " + e.message);
43      }
44 };
45
46 return {
47
48     /**
49     * open database
50     */
51     open: function()
52     {
53          database = openDatabase(shortName, "", displayName, maxSize);
54         version = database.version;
55         console.info("database: " + displayName + " " + version);
56         if (version != CURRENT_VERSION)
57         {
58             updateVersion();
59         }
60     },
61
62      /**
63     * isOpen
64     */
65     isOpen: function()
66     {
67         return null != database;
68     },
69
70     /**
71     * version
72     */
73     version: function()
74     {
75         return version;
76     },
77 }
78
79 } ();
80