- Source.zip
- _ReSharper.ServiceProxy
- BuildScriptCache
- .crc
- .version
- 7
- 4ddde403.dat
- DecompilerCache
- ModuleIds.xml
- NamedArguments
- .crc
- .version
- 7
- 4ddde403.dat
- PdbInfo
- ProjectModel
- ProjectModel.dat
- Resources
- .crc
- .version
- SymbolCache.bin
- TagPrefixes
- .crc
- .version
- TodoCache
- .crc
- .version
- 7
- 4ddde403.dat
- WebsiteFileReferences
- .crc
- .version
- WordIndex
- .crc
- .version
- 7
- 4ddde403.dat
- Article.htm
- Local.testsettings
- ServiceProxy.5.1.ReSharper.user
- ServiceProxy.DemoApplication
- ServiceProxy.SampleServices
- ServiceProxy.sln
- ServiceProxy.Tests
- ServiceProxy.vsmdi
- ServiceProxy
- TestResults
- bernhard.richter_VRBERICLT01 2011-09-06 20_46_37.trx
- bernhard.richter_VRBERICLT01 2011-09-06 20_50_18.trx
- bernhard.richter_VRBERICLT01 2011-09-06 20_54_30.trx
- bernhard.richter_VRBERICLT01 2011-09-06 20_54_30
- In
- VRBERICLT01
- data.coverage
- Out
- ServiceProxy.dll
- ServiceProxy.SampleServices.dll
- serviceproxy.tests.dll
- bernhard.richter_VRBERICLT01 2011-09-06 20_54_49.trx
- bernhard.richter_VRBERICLT01 2011-09-06 20_54_49
- In
- VRBERICLT01
- data.coverage
- Out
- ServiceProxy.dll
- ServiceProxy.SampleServices.dll
- serviceproxy.tests.dll
- TraceAndTestImpact.testsettings
|
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
namespace ServiceProxy
{
/// <summary>
/// A factory class that creates proxy types that will have their target created when the proxy type is instantiated.
/// </summary>
public class ServiceProxyFactory
{
private readonly ConcurrentDictionary<Type, Type> _proxyCache = new ConcurrentDictionary<Type, Type>();
/// <summary>
/// Creates a proxy type that creates the actual target using the given <paramref name="targetFactory"/>.
/// </summary>
/// <param name="serviceContractType">The service contract for which to create a proxy type.</param>
/// <param name="targetFactory">The function delegate that will be used to create the invocation target.</param>
/// <returns></returns>
public Type GetProxyType(Type serviceContractType, Func<object> targetFactory)
{
if (!serviceContractType.IsInterface)
throw new ArgumentOutOfRangeException("serviceContractType","The service type must be an interface");
return _proxyCache.GetOrAdd(serviceContractType, s => CreateProxyType(serviceContractType, targetFactory));
}
private static Type CreateProxyType(Type serviceType, Func<object> targetFactory)
{
TypeBuilder typeBuilder = GetTypeBuilder(serviceType);
FieldBuilder targetFactoryField = DefineTargetFactoryField(typeBuilder);
FieldBuilder targetField = DefineTargetField(serviceType, typeBuilder);
ImplementParameterlessConstructor(serviceType, typeBuilder, targetFactoryField, targetField);
ImplementMethods(serviceType, typeBuilder, targetField);
Type proxyType = typeBuilder.CreateType();
AssignTargetFactory(proxyType, targetFactory);
return proxyType;
}
private static void AssignTargetFactory(Type proxyType, Func<object> targetFactory)
{
proxyType.InvokeMember("TargetFactory", BindingFlags.Public | BindingFlags.Static | BindingFlags.SetField, null, null,
new object[] { targetFactory });
}
private static FieldBuilder DefineTargetField(Type serviceContractType, TypeBuilder typeBuilder)
{
return typeBuilder.DefineField("_target", serviceContractType, FieldAttributes.InitOnly | FieldAttributes.Private);
}
private static void ImplementParameterlessConstructor(Type serviceType, TypeBuilder typeBuilder, FieldBuilder targetFactoryField, FieldBuilder targetField)
{
var constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.Standard, Type.EmptyTypes);
ILGenerator ilGenerator = constructorBuilder.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldsfld, targetFactoryField);
ilGenerator.Emit(OpCodes.Callvirt, typeof(Func<object>).GetMethod("Invoke"));
ilGenerator.Emit(OpCodes.Castclass, serviceType);
ilGenerator.Emit(OpCodes.Stfld, targetField);
ilGenerator.Emit(OpCodes.Ret);
}
private static FieldBuilder DefineTargetFactoryField(TypeBuilder typeBuilder)
{
return typeBuilder.DefineField("TargetFactory", typeof(Func<object>),
FieldAttributes.Public | FieldAttributes.Static);
}
private static void ImplementMethods(Type serviceContractType, TypeBuilder typeBuilder, FieldBuilder targetField)
{
foreach (MethodInfo targetMethod in GetTargetMethods(serviceContractType))
{
MethodBuilder methodBuilder = GetMethodBuilder(typeBuilder, targetMethod);
ILGenerator ilGenerator = methodBuilder.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldfld, targetField);
for (int i = 1; i <= targetMethod.GetParameters().Length; ++i)
ilGenerator.Emit(OpCodes.Ldarg, i);
ilGenerator.Emit(OpCodes.Callvirt, targetMethod);
ilGenerator.Emit(OpCodes.Ret);
}
}
private static MethodBuilder GetMethodBuilder(TypeBuilder typeBuilder, MethodInfo targetMethod)
{
return typeBuilder.DefineMethod(targetMethod.Name, targetMethod.Attributes ^ MethodAttributes.Abstract,
targetMethod.ReturnType,
targetMethod.GetParameters().Select(p => p.ParameterType).ToArray());
}
private static TypeBuilder GetTypeBuilder(Type baseType)
{
return GetModuleBuilder().DefineType(baseType.Name + Guid.NewGuid(), TypeAttributes.Public | TypeAttributes.Class, null, new[] { baseType });
}
private static ModuleBuilder GetModuleBuilder()
{
AssemblyBuilder assemblybuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName(Guid.NewGuid().ToString()), AssemblyBuilderAccess.Run);
return assemblybuilder.DefineDynamicModule(Guid.NewGuid().ToString());
}
private static IEnumerable<MethodInfo> GetTargetMethods(Type serviceType)
{
return serviceType.GetMethods();
}
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
I'm a 39 year old software developer living in Norway.
I'm currently working for a software company making software for the retail industry.