using NHibernate; using System; using System.Linq; using System.Reflection; using System.Reflection.Emit; namespace DatabaseSample { public static class ServiceProducer where T: BaseService { private static readonly string generatedSessionFactoryFieldName = "__generated_session_factory"; private static readonly string generatedTypePrefix = "__customType_"; public static T ProduceService(ISessionFactory sessionFactory) { var myType = CompileResultType(); T data = (T)Activator.CreateInstance(myType); myType.GetField(generatedSessionFactoryFieldName, BindingFlags.Instance | BindingFlags.NonPublic).SetValue(data, sessionFactory); return data; } private static Type CompileResultType() { TypeBuilder tb = GetTypeBuilder(); ConstructorBuilder constructor = tb.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName); return tb.CreateType(); } private static TypeBuilder GetTypeBuilder() { var typeSignature = generatedTypePrefix + typeof(T).Name; var an = new AssemblyName(typeSignature); AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run); ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule"); TypeBuilder tb = moduleBuilder.DefineType(typeSignature , TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.AutoClass | TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit | TypeAttributes.AutoLayout , typeof(T)); FieldBuilder fieldBuilder = tb.DefineField(generatedSessionFactoryFieldName, typeof(ISessionFactory), FieldAttributes.Private); typeof(T).GetMethods().ToList().ForEach(m => { MethodBuilder mbM = tb.DefineMethod(m.Name, MethodAttributes.Public | MethodAttributes.ReuseSlot | MethodAttributes.Virtual | MethodAttributes.HideBySig, m.ReturnType, m.GetParameters().ToList().Select(a => a.ParameterType).ToArray()); var il = mbM.GetILGenerator(); il.DeclareLocal(typeof(ISessionFactory)); il.DeclareLocal(typeof(ISession)); il.DeclareLocal(typeof(ITransaction)); il.DeclareLocal(typeof(Exception)); if (!typeof(void).IsAssignableFrom(m.ReturnType)) { il.DeclareLocal(m.ReturnType); } Label transactionNull = il.DefineLabel(); Label exit = il.DefineLabel(); // try { il.BeginExceptionBlock(); // _session = _sessionFactory.OpenSession(); writeLine(il, "GettingSession"); il.Emit(OpCodes.Nop); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, fieldBuilder); il.Emit(OpCodes.Stloc_0); writeLine(il, "Session got!"); il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Call, typeof(ISessionFactory).GetMethod("OpenSession", new Type[0])); il.Emit(OpCodes.Stloc_1); writeLine(il, "Saving session"); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldloc_1); il.Emit(OpCodes.Stfld, typeof(BaseService).GetField("_session", BindingFlags.Instance | BindingFlags.NonPublic)); il.Emit(OpCodes.Nop); // transaction = _session.BeginTransaction() writeLine(il, "Creating Transaction"); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, typeof(BaseService).GetField("_session", BindingFlags.Instance | BindingFlags.NonPublic)); il.Emit(OpCodes.Call, typeof(ISession).GetMethod("BeginTransaction", new Type[0])); il.Emit(OpCodes.Stloc_2); // base.{thismethod}({parameters}) writeLine(il, "Calling parent"); il.Emit(OpCodes.Ldarg_0); UInt16 i = 1; m.GetParameters().ToList().ForEach(a => { il.Emit(OpCodes.Ldarg, i); i++; }); il.EmitCall(OpCodes.Call, m, new Type[0]); if (!typeof(void).IsAssignableFrom(m.ReturnType)) { il.Emit(OpCodes.Stloc, 4); } // transaction.Commit(); writeLine(il, "Commiting Transaction"); il.Emit(OpCodes.Ldloc_2); il.Emit(OpCodes.Call, typeof(ITransaction).GetMethod("Commit")); // } catch (Exception) { il.BeginCatchBlock(typeof(Exception)); il.Emit(OpCodes.Pop); // transaction.Commit(); writeLine(il, "Rolling back Transaction"); il.Emit(OpCodes.Ldloc_2); il.Emit(OpCodes.Brfalse_S, transactionNull); il.Emit(OpCodes.Ldloc_2); il.Emit(OpCodes.Call, typeof(ITransaction).GetMethod("Rollback")); writeLine(il, "Exception got!"); il.MarkLabel(transactionNull); il.Emit(OpCodes.Rethrow); // } finally { il.BeginFinallyBlock(); // _session.Close(); writeLine(il, "Closing session"); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, typeof(BaseService).GetField("_session", BindingFlags.Instance | BindingFlags.NonPublic)); il.Emit(OpCodes.Brfalse_S, exit); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, typeof(BaseService).GetField("_session", BindingFlags.Instance | BindingFlags.NonPublic)); il.Emit(OpCodes.Call, typeof(ISession).GetMethod("Close")); il.Emit(OpCodes.Pop); //} il.EndExceptionBlock(); // return {returndata} if (!typeof(void).IsAssignableFrom(m.ReturnType)) { il.Emit(OpCodes.Ldloc, 4); } il.MarkLabel(exit); il.Emit(OpCodes.Ret); }); return tb; } private static void writeLine(ILGenerator il, string line) { il.Emit(OpCodes.Ldstr, line); il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) })); } } }