/src/LinFu.Proxy/ProxyFactory.cs

http://github.com/philiplaureano/LinFu · C# · 191 lines · 103 code · 38 blank · 50 comment · 20 complexity · f1d49e5a2acbec1b4deb236beb7e794c MD5 · raw file

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Reflection;
  5. using LinFu.AOP.Cecil.Interfaces;
  6. using LinFu.IoC.Configuration;
  7. using LinFu.IoC.Interfaces;
  8. using LinFu.Proxy.Interfaces;
  9. using LinFu.Reflection.Emit;
  10. using Mono.Cecil;
  11. using TypeAttributes = Mono.Cecil.TypeAttributes;
  12. namespace LinFu.Proxy
  13. {
  14. /// <summary>
  15. /// Provides the basic implementation for a proxy factory class.
  16. /// </summary>
  17. [Implements(typeof(IProxyFactory), LifecycleType.OncePerRequest)]
  18. public class ProxyFactory : IProxyFactory, IInitialize
  19. {
  20. /// <summary>
  21. /// Initializes the proxy factory with the default values.
  22. /// </summary>
  23. public ProxyFactory()
  24. {
  25. // Use the forwarding proxy type by default
  26. ProxyBuilder = new SerializableProxyBuilder();
  27. InterfaceExtractor = new InterfaceExtractor();
  28. Cache = new ProxyCache();
  29. }
  30. /// <summary>
  31. /// Gets or sets the <see cref="IExtractInterfaces" /> type that will be
  32. /// responsible for determining which interfaces
  33. /// the proxy type should implement.
  34. /// </summary>
  35. public IExtractInterfaces InterfaceExtractor { get; set; }
  36. /// <summary>
  37. /// The <see cref="IProxyBuilder" /> instance that is
  38. /// responsible for generating the proxy type.
  39. /// </summary>
  40. public IProxyBuilder ProxyBuilder { get; set; }
  41. /// <summary>
  42. /// The <see cref="IVerifier" /> instance that will be used to
  43. /// ensure that the generated assemblies are valid.
  44. /// </summary>
  45. public IVerifier Verifier { get; set; }
  46. /// <summary>
  47. /// Gets or sets a value indicating the <see cref="IProxyCache" />
  48. /// instance that will be used to cache previous proxy generation runs.
  49. /// </summary>
  50. public IProxyCache Cache { get; set; }
  51. /// <summary>
  52. /// Initializes the <see cref="ProxyFactory" /> instance
  53. /// with the <paramref name="source" /> container.
  54. /// </summary>
  55. /// <param name="source">The <see cref="IServiceContainer" /> instance that will hold the ProxyFactory.</param>
  56. public virtual void Initialize(IServiceContainer source)
  57. {
  58. if (source.Contains(typeof(IProxyBuilder), new Type[0]))
  59. ProxyBuilder = (IProxyBuilder) source.GetService(typeof(IProxyBuilder));
  60. if (source.Contains(typeof(IExtractInterfaces), new Type[0]))
  61. InterfaceExtractor = (IExtractInterfaces) source.GetService(typeof(IExtractInterfaces));
  62. //if (source.Contains(typeof(IVerifier)))
  63. // Verifier = source.GetService<IVerifier>();
  64. if (source.Contains(typeof(IProxyCache), new Type[0]))
  65. Cache = (IProxyCache) source.GetService(typeof(IProxyCache));
  66. }
  67. /// <summary>
  68. /// Creates a proxy type using the given
  69. /// <paramref name="baseType" /> as the base class
  70. /// and ensures that the proxy type implements the given
  71. /// interface types.
  72. /// </summary>
  73. /// <param name="baseType">The base class from which the proxy type will be derived.</param>
  74. /// <param name="baseInterfaces">The list of interfaces that the proxy will implement.</param>
  75. /// <returns>A forwarding proxy.</returns>
  76. public Type CreateProxyType(Type baseType, IEnumerable<Type> baseInterfaces)
  77. {
  78. // Reuse the cached results, if possible
  79. var originalInterfaces = baseInterfaces.ToArray();
  80. if (Cache != null && Cache.Contains(baseType, originalInterfaces))
  81. return Cache.Get(baseType, originalInterfaces);
  82. if (!baseType.IsPublic)
  83. throw new ArgumentException("The proxy factory can only generate proxies from public base classes.",
  84. "baseType");
  85. var hasNonPublicInterfaces = (from t in baseInterfaces
  86. where t.IsNotPublic
  87. select t).Count() > 0;
  88. if (hasNonPublicInterfaces)
  89. throw new ArgumentException("The proxy factory cannot generate proxies from non-public interfaces.",
  90. "baseInterfaces");
  91. var actualBaseType = baseType.IsInterface ? typeof(object) : baseType;
  92. var interfaces = new HashSet<Type>(baseInterfaces);
  93. // Move the base type into the list of interfaces
  94. // if the user mistakenly entered
  95. // an interface type as the base type
  96. if (baseType.IsInterface) interfaces.Add(baseType);
  97. if (InterfaceExtractor != null)
  98. {
  99. // Get the interfaces for the base type
  100. InterfaceExtractor.GetInterfaces(actualBaseType, interfaces);
  101. var targetList = interfaces.ToArray();
  102. // Extract the inherited interfaces
  103. foreach (var type in targetList) InterfaceExtractor.GetInterfaces(type, interfaces);
  104. }
  105. var assemblyName = "LinFu.Proxy";
  106. var assembly = AssemblyDefinition.CreateAssembly(
  107. new AssemblyNameDefinition(assemblyName, new Version(1, 0)),
  108. $"anonymousmodule-{Guid.NewGuid().ToString()}", ModuleKind.Dll);
  109. var mainModule = assembly.MainModule;
  110. var importedBaseType = mainModule.Import(actualBaseType);
  111. var attributes = TypeAttributes.AutoClass | TypeAttributes.Class |
  112. TypeAttributes.Public | TypeAttributes.BeforeFieldInit;
  113. var guid = Guid.NewGuid().ToString().Replace("-", "");
  114. var typeName = string.Format("{0}Proxy-{1}", baseType.Name, guid);
  115. var namespaceName = "LinFu.Proxy";
  116. var proxyType = mainModule.DefineClass(typeName, namespaceName,
  117. attributes, importedBaseType);
  118. proxyType.AddDefaultConstructor();
  119. if (ProxyBuilder == null)
  120. throw new NullReferenceException("The 'ProxyBuilder' property cannot be null");
  121. // Add the list of interfaces to the target type
  122. foreach (var interfaceType in interfaces)
  123. {
  124. if (!interfaceType.IsInterface)
  125. continue;
  126. var currentType = mainModule.Import(interfaceType);
  127. proxyType.Interfaces.Add(currentType);
  128. }
  129. // Hand it off to the builder for construction
  130. ProxyBuilder.Construct(actualBaseType, interfaces, mainModule, proxyType);
  131. // Verify the assembly, if possible
  132. if (Verifier != null)
  133. Verifier.Verify(assembly);
  134. var compiledAssembly = assembly.ToAssembly();
  135. IEnumerable<Type> types = null;
  136. try
  137. {
  138. types = compiledAssembly.GetTypes();
  139. }
  140. catch (ReflectionTypeLoadException ex)
  141. {
  142. types = ex.Types;
  143. }
  144. var result = (from t in types
  145. where t != null && t.IsClass
  146. select t).FirstOrDefault();
  147. // Cache the result
  148. if (Cache != null)
  149. Cache.Store(result, baseType, originalInterfaces);
  150. return result;
  151. }
  152. }
  153. }