June 08, 2013

Knockout custom binding to filter multiple mouse clicks

Knockout custom bindings offer a useful extension point for interacting with the DOM, without compromising the testability of View Models. Here is a binding handler to filter unwanted double/triple/multiple mouse clicks, using debounce - an Underscore.js function.

(If you don't want to include Underscore.js in your project, just lift out the debounce function which is only about 15 lines of Javascript and isn't dependent on any Underscore library internals).

December 19, 2012

'Hello World' of the NHibernate world

This is the simplest "'Hello World' for NHibernate" example I could come up with. There are different approaches to configuring NHibernate and performing mappings, but this is a code-first approach which has many advantages - not the least of which is simplicity.

1. Start with an entity that you want to persist to a database

public class Customer
{
  public virtual Guid Id { get; set; }
  public virtual string Name { get; set; }
}

2. Next, configure NHibernate for your database (Microsoft SQL Server 2008 in this example, although many others are supported)

var configuration = new Configuration();
 
configuration.SessionFactory()
    .Integrate.Using<MsSql2008Dialect>()
    .Connected.Using(...your connection string...);

3. Create a mapping for the Customer entity

The mapping tells NHibernate how to map entity properties to database table columns.

var mapper = new ModelMapper();
 
mapper.Class<Customer>(rc =>
{
    rc.Id(x => x.Id, m => m.Generator(Generators.Guid));
    rc.Property(x => x.Name);
});

There are a number of other ways to map an entity (e.g. XML, Fluent NHibernate), but here we use 'by code' mapping which is a convention-based approach. This expects an underlying database table called Customer, with columns 'Id' and 'Name', to exist. If required, NHibernate can even create this schema for you. See the GIST associated with this post.

4. Add the mapping to the NHibernate configuration

var mapping = mapper.CompileMappingForAllExplicitlyAddedEntities();
 
configuration.AddMapping(mapping);

All the hard work is done. Time to sit back and let NHibernate take care of the rest. For example, to persist a new Customer entity:

using (var sessionFactory = configuration.BuildSessionFactory())
{
    using (var session = sessionFactory.OpenSession())
    {
        var customer = new Customer { Name = "Aristotle" };
        session.SaveOrUpdate(customer);
        session.Flush();
    }
}

You should be able to have this up and running in Visual Studio in a matter of minutes. Here is a GitHub GIST to get you started.

October 25, 2011

NHibernate 3.3 XML Identity Mapping

Better late than never, a minor improvement requested in 2007 (!) is implemented in the upcoming NHibernate 3.3 release. It will finally be possible to map an identity generator using a small shortcut:

Instead of:

   1:  <class name="Customer">
   2:   <id>
   3:    <generator class="identity" />
   4:   </id>
   5:   <property name="Name" />
   6:  </class>

In 3.3:

   1:  <class name="Customer">
   2:   <id generator="identity" />
   3:   <property name="Name" />
   4:  </class>

This shortcut can only be used for generators that don't require parameters, or where the generator's parameter defaults are acceptable.

While we are on the subject of mappings, why not consider by-code mappings - new in 3.3:

   1:  mapper.Class<customer>(rc =>
   2:  {
   3:   rc.Id(x => x.Id, m => m.Generator(Generators.Identity));
   4:   rc.Property(x => x.Name);
   5:  });

More on by-code mappings can be found here, here and here.

March 14, 2009

TIP: Blogger OpenID Not Working?

If you are have trouble using your Blogger account as an OpenID provider (e.g. 'No OpenId endpoint found'), make sure the following tag is on your page in the <head> section:

<link href='http://www.blogger.com/openid-server.g' rel='openid.server' />

(This tag may be missing if you manually edit your page template like I do)

January 11, 2009

Avoiding Multiple IOC Container Instances in WCF

I've recently been looking for the best way to use WCF, Unity and NHibernate together. Fortunately there are already some really good posts on integrating WCF with IOC containers:

The UnityContainer, and NHibernate ISessionFactory, should only be created once per application - we want them to have 'global' scope. In the past, the ASP.NET Global Application_Start event handler could be used to do this, but it isn't a good idea to rely on host-specific features for a WCF implementation - in the future we may want to re-host the services outside of ASP.NET where these features are not available (other hosting options include WAS, a Windows Service or self-hosted).

The solutions I've seen so far use a custom ServiceHostFactory to create the IOC container, but because WCF creates a new factory for each service, the factory needs to take care not to create new instances of the IOC container each time.

My solution: 1) Create the IOC container in a static constructor of the custom ServiceHostFactory. This ensures that it is created only once for the application, and in a thread-safe manner. 2) Create and configure any other services (eg. NHibernate, log4net) that require 'per-application' instantiation and register them with the IOC. 3) Pass the IOC container into the custom ServiceHost, and return it from the factory as normal.

Here is the code:

   1:  public class MyServiceHost : ServiceHost
   2:  {
   3:      private IUnityContainer _ioc;
   4:   
   5:      public IUnityContainer IoC
   6:      {
   7:          get { return _ioc; }
   8:      }
   9:   
  10:      public MyServiceHost(IUnityContainer ioc, Type serviceType, Uri[] baseAddresses)
  11:          : base(serviceType, baseAddresses)
  12:      {
  13:          _ioc = ioc;
  14:      }
  15:  }

   1:  public class MyServiceHostFactory : ServiceHostFactory
   2:  {
   3:      private static UnityContainer _ioc;
   4:   
   5:      static MyServiceHostFactory()
   6:      {
   7:          _ioc = InitializeUnity();
   8:   
   9:          InitializeAndRegisterNHibernate();
  10:          InitializeAndRegisterLog4Net();
  11:      }
  12:   
  13:      protected override ServiceHost CreateServiceHost(
  14:          Type serviceType, Uri[] baseAddresses)
  15:      {
  16:          return new MyServiceHost(_ioc, serviceType, baseAddresses);
  17:      }
  18:   
  19:      private static UnityContainer InitializeUnity()
  20:      {
  21:          UnityContainer container = new UnityContainer();
  22:          UnityConfigurationSection config = 
  23:              ConfigurationManager.GetSection("unity") as UnityConfigurationSection;
  24:          config.Containers.Default.Configure(container);
  25:          return container;
  26:      }
  27:   
  28:      private static void InitializeAndRegisterNHibernate()
  29:      {
  30:          NHibernate.Cfg.Configuration config = new NHibernate.Cfg.Configuration();
  31:          config.Configure();
  32:   
  33:          _ioc.RegisterInstance(config.BuildSessionFactory());
  34:      }
  35:   
  36:      private static void InitializeAndRegisterLog4Net()
  37:      {
  38:          log4net.Config.XmlConfigurator.Configure();
  39:   
  40:          _ioc.RegisterInstance(LogManager.GetLogger("Application"));
  41:      }
  42:  }