Working with NHibernate without default constructors

In the previous post we established that the usage of default constructor required by NHibernate is theoretically not required. The fact that NHibernate does use them though has to do with technical limitations of CLR. Turns out in most cases there is a workaround, which is not perfect but was a fun experiment to implement.

The code presented here is just an experiment. It is not of production quality – it is merely a proof of concept so if you use it in production and the world blows up, don’t blame me.

Interceptor

The place that NHibernate lets you plug into to instantiate entities and components as they are pulled from database is in NHibernate’s IInterceptor (not to be confused with Castle DynamicProxy IInerceptor) interface and its instantiate method. NHibernate has also a IObjectsFactory interface but that one is used to instantiate everything including NHibernate’s own infrastructure (like IUserTypes for example) and we want to override only activation of entities and components.

public class ExtensibleInterceptor : EmptyInterceptor
{
	private readonly INHibernateActivator activator;

	public ISessionFactory SessionFactory { get; set; }

	public ExtensibleInterceptor(INHibernateActivator activator)
	{
		this.activator = activator;
	}

	public override object Instantiate(string clazz, EntityMode entityMode, object id)
	{
		if (entityMode == EntityMode.Poco)
		{
			var type = Type.GetType(clazz);
			if (type != null && activator.CanInstantiate(type))
			{
				var instance = activator.Instantiate(type);
				SessionFactory.GetClassMetadata(clazz).SetIdentifier(instance, id, entityMode);
				return instance;
			}
		}
		return base.Instantiate(clazz, entityMode, id);
	}
}

The code here is straightforward. The INHibernateActivator is a custom interface that we’ll discuss in details below. That’s where the actual activation happens. We’re also using ISessionFactory so that we properly set the id of retrieved instance.

Proxy validator

Turns out that is not enough. In the interceptor we activate objects we fully obtain from the database. However big part of NHibernate performance optimisation is to ensure we don’t load more data that we need (a.k.a. lazy loading) and to do it transparently NHibernate uses proxies.

For every persistent type NHibernate uses object called proxy validator to ensure object meets all the requirements it has to be able to properly proxy a type and that work is done by IProxyValidator.

Part of the work of proxy validator is to check for default constructor so we need to override that logic to reassure NHibernate we have things under control.

public class CustomProxyValidator : DynProxyTypeValidator
{
	private const bool iDontCare = true;

	protected override bool HasVisibleDefaultConstructor(Type type)
	{
		return iDontCare;
	}
}

Proxy factory

Now that we told NHibernate we can handle proxying types without default constructor it’s time to write code that actually does it. That’s the task of ProxyFactory which uses Castle DynamicProxy under the cover

public class CustomProxyFactory : AbstractProxyFactory
{
	protected static readonly IInternalLogger log = LoggerProvider.LoggerFor(typeof (CustomProxyFactory));
	private static readonly DefaultProxyBuilder proxyBuilder = new DefaultProxyBuilder();
	private readonly INHibernateActivator activator;

	public CustomProxyFactory(INHibernateActivator activator)
	{
		this.activator = activator;
	}

	public override INHibernateProxy GetProxy(object id, ISessionImplementor session)
	{
		try
		{
			var proxyType = IsClassProxy
				                ? proxyBuilder.CreateClassProxyType(
				                	PersistentClass,
				                	Interfaces,
				                	ProxyGenerationOptions.Default)
				                : proxyBuilder.CreateInterfaceProxyTypeWithoutTarget(
				                	Interfaces[0],
				                	Interfaces,
				                	ProxyGenerationOptions.Default);

			var proxy = activator.Instantiate(proxyType);

			var initializer = new LazyInitializer(EntityName, PersistentClass, id, GetIdentifierMethod, SetIdentifierMethod,
				                                    ComponentIdType, session);
			SetInterceptors(proxy, initializer);
			initializer._constructed = true;
			return (INHibernateProxy) proxy;
		}
		catch (Exception e)
		{
			log.Error("Creating a proxy instance failed", e);
			throw new HibernateException("Creating a proxy instance failed", e);
		}
	}

	public override object GetFieldInterceptionProxy()
	{
		var proxyGenerationOptions = new ProxyGenerationOptions();
		var interceptor = new LazyFieldInterceptor();
		proxyGenerationOptions.AddMixinInstance(interceptor);
		var proxyType = proxyBuilder.CreateClassProxyType(PersistentClass, Interfaces, proxyGenerationOptions);
		var proxy = activator.Instantiate(proxyType);
		SetInterceptors(proxy, interceptor);
		SetMixin(proxy, interceptor);

		return proxy;
	}

	private void SetInterceptors(object proxy, params IInterceptor[] interceptors)
	{
		var field = proxy.GetType().GetField("__interceptors");
		field.SetValue(proxy, interceptors);
	}

	private void SetMixin(object proxy, LazyFieldInterceptor interceptor)
	{
		var fields = proxy.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance);
		var mixin = fields.Where(f => f.Name.StartsWith("__mixin")).Single();
		mixin.SetValue(proxy, interceptor);
	}
}

It is pretty standard and not very interesting. We’re again using the INHibernateActivator, we’ve yet to discuss, to create instances. Also since we’re not calling any constructors to do it, we have to set the proxy dependencies that would otherwise by provided via constructor inline. For that we’re using some internal knowledge about how DynamicProxy lays out its proxy types.

Good news is – we’re almost there. Actually we might want to also override NHibernate reflection optimizer. As its name implies replaces some actions that are performed via reflection with faster, compiled versions. The default one works with assumption that default constructor is available and may fail otherwise but we can disable that feature for our simple proof of concept application.

Proxy factory factory

There’s one more step actually – we need to attach out proxy factory and proxy validator to session factory and we do that via ridiculously named IProxyFactoryFactory

public class CustomProxyFactoryFactory : IProxyFactoryFactory
{
	public IProxyFactory BuildProxyFactory()
	{
		return new CustomProxyFactory(new NHibernateActivator());
	}

	public bool IsInstrumented(Type entityClass)
	{
		return true;
	}

	public bool IsProxy(object entity)
	{
		return (entity is INHibernateProxy);
	}

	public IProxyValidator ProxyValidator
	{
		get { return new CustomProxyValidator(); }
	}
}

Putting it all together

Now that we have all these pieces let’s see how we put them together (with some help from FluentNHibernate)

var config = Fluently.Configure()
	.Mappings(c => c.FluentMappings.AddFromAssemblyOf<Program>())
	.Database(MsSqlConfiguration.MsSql2008
				.ConnectionString(s => s.Database("NHExperiment").Server(".").TrustedConnection())
				.ProxyFactoryFactory<CustomProxyFactoryFactory>())
	.BuildConfiguration();
var interceptor = new ExtensibleInterceptor(new NHibernateActivator());
config.Interceptor = interceptor;
NHibernate.Cfg.Environment.UseReflectionOptimizer = false;
var factory = config.BuildSessionFactory();
interceptor.SessionFactory = factory;

We set up our standard stuff – mapping and connection string. Then we need to tell NHibernate to use our custom ProxyFactoryFactory. Then we build configuration object and set our custom interceptor to it. Having done that we can build session factory and give the interceptor reference to the session factory. Certainly not the smoothest ride but gets the job done. Oh – and as I mentioned we disable reflection optimizer so that we don’t have to override yet another class (two actually).

That is all it takes to be able to get rid of all the seemingly superfluous constructors and have a much simpler model.

Well not quite – what about the activator

Right – the activator. How do we make that happen? Here’s all the code in this class.

public class NHibernateActivator : INHibernateActivator
{
	public bool CanInstantiate(Type type)
	{
		return true;
	}

	public object Instantiate(Type type)
	{
		return FormatterServices.GetUninitializedObject(type);
	}
}

Remember how I said that NHibernate can be viewed as fancy serializer? Here we make it obvious by using System.Runtime.Serialization.FormatterServices class to give us an uninitialized instance of given type. Uninitialized means that all the fields will be null or 0 and no code will be ran. This however is precisely what we want for the reasons outlined in previous post. We then throw the object to NHibernate machinery to perform all the necessary initialization for us, so that when the object is returned from the session it is fully created and usable. We could also implement a mechanism similar to one of the options that standard .NET serialization provides to allow the object to initialize its volatile state.

Final words

That is all it takes to make the model a bit more persistence ignorant. Like I said this approach won’t work always. It requires full trust environment and probably if you have complex volatile state the solution will be too simplistic. I would be interested to hear what do you think about the approach in general. Can you spot any severe shortcomings or flaws? Do you like it? Would you use it?

Comments

Nik_Govorov says:

Hi.
I had suggested this way of avoiding of having default constructor.
http://groups.google.com/group/nhusers/browse_thread/thread/7ced65db7bcb1625/1abacbea8e0b0301?lnk=gst&q=FormatterServices#1abacbea8e0b0301
But as I remember, castle dynamic proxy did not work in this case in that time.

Nik_Govorov says:

I could be wrong about castle dp, maybe there were another reasons why I watched on spring and linfu only.

I’d be happy to see what the difference was

Nik_Govorov says:

Hello Krzysztof.
I’ve created simple project. You can download it from: http://cid-fa0e8c1333e3d256.office.live.com/self.aspx/Public/NHibernateDefConstructor.zip
It demonstrates subject(all libs are included in project):
NH 2.1 NHibernate.ByteCode.Castle Castle.DynamicProxy2(2.1.0.0) – does not work without default constructors;
NH 2.1 NHibernate.ByteCode.LinFu LinFu.DynamicProxy(1.0.3.14911) – works without default constructors;
NH 3.1 NHibernate.ByteCode.Castle Castle.Core(2.5.2.0) – does not work without default constructors;
NH 3.1 NHibernate.ByteCode.LinFu LinFu.DynamicProxy(1.0.4.18998) NHibernate.ByteCode.LinFu – works without default constructors;
NH 3.1 NHibernate.ByteCode.Castle/YourImplementation Castle.Core(2.5.2.0) – works without default constructors, but should be optimized and requires additional efforts;

Just in case: NH 3.2 has own proxies based on linfu – works without default constructors.

Thanks Nik. That’s interesting. I’ll check out how the other frameworks do it although IIRC LinFu is based on Cecil which allows it to add a constructor to the type when it’s not present. That is obviously much more powerful solution than SRE based one DP uses

Nik.

I’ve had a look at how the proxying works in NHibernate 3.2 included in your zip. Basically NHibernate proxy factory always will generate default constructor for proxy type even is the proxied class does not have default accessible constructor. This works (as in – compiles and doesn’t throw when you run it in most cases). However it generates unverifiable code. If you were to run PeVerify on generated assembly you’d get verification error similar to following:

Castle.DynamicProxy.Tests.BasicClassProxyTestCase: 1 code

Microsoft (R) .NET Framework PE Verifier. Version 4.0.30319.1
Copyright (c) Microsoft Corporation. All rights reserved.

[IL]: Error: [E:OSS.CodeCastle.CoresrcCastle.Core.TestsbinNET40-DebugCastleDynProxy2.dll : Castle.Proxies.ClassWithConstructorsProxy::.ctor][mdToken=0x6000008][offset 0x00000022][found ref (‘this’ ptr) ‘Castle.Proxies.ClassWithConstructorsProxy’] Call to .ctor only allowed to initialize this pointer from within a .ctor. Try newobj.
1 Error(s) Verifying E:OSS.CodeCastle.CoresrcCastle.Core.TestsbinNET40-DebugCastleDynProxy2.dll

As generating verifiable code is one of DynamicProxy’s core guidelines I don’t think Castle DP will support this approach.

Anyway – that was interesting experiment, thanks for bringing this to my attention. Cheers.

Scooletz says:

As I mentioned under your previous post, I do use the same Interceptor construction, but I tend to add these protected default constructors. As Nik_Govorov wrote, I remember that using dynamic proxy without default constructor was not possible (and was experimentally added in some branch). How is it handled now?

Krzysztof Kozmic says:

Like I showed in the post

Scooletz says:

I meant, in the dynamic proxy code, not the NHibernate proxy factory. There is one think, which is not possible with this solution – having dependencies injected via your objects’ constructors. Some people discourage this use of constructor but I, as well as Ayende, used it a few times. What do you think about it?

The proxy factory, and the rest of the code beside the INHibernateActivator is a default byte code for NH with Castle as its core, isn’t it?