Skip to content

Instantly share code, notes, and snippets.

@Warrenn
Last active August 29, 2015 14:19
Show Gist options
  • Save Warrenn/15fd3731adbc70a64317 to your computer and use it in GitHub Desktop.
Save Warrenn/15fd3731adbc70a64317 to your computer and use it in GitHub Desktop.
Disposable Channel Factory
using System;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.ServiceModel;
namespace DisposableChannelFactory
{
public class ClientGenerator
{
private const MethodAttributes MethodAttributes =
System.Reflection.MethodAttributes.Public |
System.Reflection.MethodAttributes.HideBySig |
System.Reflection.MethodAttributes.Final |
System.Reflection.MethodAttributes.Virtual |
System.Reflection.MethodAttributes.NewSlot;
private const CallingConventions CallingConventions =
System.Reflection.CallingConventions.HasThis |
System.Reflection.CallingConventions.ExplicitThis;
public class ServiceBase<T> :
ClientBase<T>,
IDisposable where T : class
{
void IDisposable.Dispose()
{
Dispose(true);
}
public void Dispose(bool disposing)
{
if (!disposing) return;
if (State == CommunicationState.Closed) return;
try
{
if (State == CommunicationState.Faulted)
{
Abort();
return;
}
Close();
}
catch (CommunicationException ex)
{
Trace.TraceError(ex.ToString());
if (State == CommunicationState.Closed) return;
Abort();
}
}
~ServiceBase()
{
Dispose(false);
}
}
public static T Proxy<T>() where T : class
{
var type = ProxyType<T>();
return (T)Activator.CreateInstance(type);
}
public static Type ProxyType<T>() where T : class
{
var contractType = typeof(T);
var newTypeName = contractType.Name + "_GeneratedProxy";
var currentDomain = AppDomain.CurrentDomain;
var aname = Assembly.GetAssembly(typeof(ClientGenerator)).GetName();
var asmBuilder = currentDomain.DefineDynamicAssembly(aname, AssemblyBuilderAccess.Run);
var modBuilder = asmBuilder.DefineDynamicModule(newTypeName + "Module");
var tbuilder = modBuilder.DefineType(newTypeName,
TypeAttributes.Class |
TypeAttributes.Public,
typeof(ServiceBase<T>), new[] { typeof(T) });
var getChannelMethod = typeof(ServiceBase<T>)
.GetProperty("Channel", BindingFlags.Instance | BindingFlags.NonPublic)
.GetMethod;
foreach (var methodInfo in contractType.GetMethods())
{
var isVoid = (methodInfo.ReturnType == typeof(void));
var parameterTypes = methodInfo.GetParameters().Select(pi => pi.ParameterType).ToArray();
var parameterTypesParam = (parameterTypes.Any()) ? parameterTypes : null;
var returnType = (isVoid) ? null : methodInfo.ReturnType;
var methodBuilder = tbuilder.DefineMethod(methodInfo.Name, MethodAttributes, CallingConventions,
returnType, parameterTypesParam);
var generator = methodBuilder.GetILGenerator();
methodBuilder.SetImplementationFlags(MethodImplAttributes.Managed);
generator.Emit(OpCodes.Nop);
generator.Emit(OpCodes.Ldarg_0);
generator.EmitCall(OpCodes.Call, getChannelMethod, null);
for (var index = 1; index <= parameterTypes.Length; index++)
{
var opCodeField = typeof (OpCodes).GetField("Ldarg_" + index,
BindingFlags.Public | BindingFlags.Static);
if (opCodeField == null) continue;
var opCode = (OpCode)opCodeField.GetValue(null);
generator.Emit(opCode);
}
generator.EmitCall(OpCodes.Callvirt, methodInfo, null);
if (isVoid) generator.Emit(OpCodes.Nop);
generator.Emit(OpCodes.Ret);
}
return tbuilder.CreateType();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment