diff --git a/src/AsyncGenerator.yml b/src/AsyncGenerator.yml index 15df51734d0..69aa2886b58 100644 --- a/src/AsyncGenerator.yml +++ b/src/AsyncGenerator.yml @@ -196,6 +196,8 @@ name: LinqReadonlyTestsContext - conversion: Ignore name: MultiThreadRunner + - conversion: Ignore + name: PeVerifier - conversion: Ignore hasAttributeName: IgnoreAttribute - conversion: NewType diff --git a/src/NHibernate.Test/Async/DynamicEntity/Interceptor/InterceptorDynamicEntity.cs b/src/NHibernate.Test/Async/DynamicEntity/Interceptor/InterceptorDynamicEntity.cs index 41e1492f4e7..2987f3817f1 100644 --- a/src/NHibernate.Test/Async/DynamicEntity/Interceptor/InterceptorDynamicEntity.cs +++ b/src/NHibernate.Test/Async/DynamicEntity/Interceptor/InterceptorDynamicEntity.cs @@ -8,6 +8,7 @@ //------------------------------------------------------------------------------ +using System; using System.Collections; using NHibernate.Cfg; using NUnit.Framework; @@ -16,6 +17,7 @@ namespace NHibernate.Test.DynamicEntity.Interceptor { using System.Threading.Tasks; [TestFixture] + [Obsolete("Require dynamic proxies")] public class InterceptorDynamicEntityAsync : TestCase { protected override string MappingsAssembly @@ -100,4 +102,4 @@ public async Task ItAsync() session.Close(); } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/Async/DynamicEntity/Tuplizer/TuplizerDynamicEntity.cs b/src/NHibernate.Test/Async/DynamicEntity/Tuplizer/TuplizerDynamicEntity.cs index fc14a4e362d..66e93fb41d5 100644 --- a/src/NHibernate.Test/Async/DynamicEntity/Tuplizer/TuplizerDynamicEntity.cs +++ b/src/NHibernate.Test/Async/DynamicEntity/Tuplizer/TuplizerDynamicEntity.cs @@ -8,6 +8,7 @@ //------------------------------------------------------------------------------ +using System; using System.Collections; using System.Collections.Generic; using NHibernate.Cfg; @@ -17,6 +18,7 @@ namespace NHibernate.Test.DynamicEntity.Tuplizer { using System.Threading.Tasks; [TestFixture] + [Obsolete("Require dynamic proxies")] public class TuplizerDynamicEntityAsync : TestCase { protected override string MappingsAssembly @@ -116,4 +118,4 @@ public async Task ItAsync() session.Close(); } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/Async/DynamicProxyTests/PeVerifier.cs b/src/NHibernate.Test/Async/DynamicProxyTests/PeVerifier.cs deleted file mode 100644 index 4ade0606804..00000000000 --- a/src/NHibernate.Test/Async/DynamicProxyTests/PeVerifier.cs +++ /dev/null @@ -1,46 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by AsyncGenerator. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - - -using System; -using System.Diagnostics; -using System.IO; -using NUnit.Framework; - -namespace NHibernate.Test.DynamicProxyTests -{ - using System.Threading.Tasks; - public partial class PeVerifier - { - - public async Task AssertIsValidAsync() - { - var process = new Process - { - StartInfo = - { - FileName = _peVerifyPath, - RedirectStandardOutput = true, - UseShellExecute = false, - Arguments = "\"" + _assemlyLocation + "\" /VERBOSE", - CreateNoWindow = true - } - }; - - process.Start(); - var processOutput = await (process.StandardOutput.ReadToEndAsync()); - process.WaitForExit(); - - var result = process.ExitCode + " code "; - - if (process.ExitCode != 0) - Assert.Fail("PeVerify reported error(s): " + Environment.NewLine + processOutput, result); - } - } -} diff --git a/src/NHibernate.Test/Async/DynamicProxyTests/PeVerifyFixture.cs b/src/NHibernate.Test/Async/DynamicProxyTests/PeVerifyFixture.cs deleted file mode 100644 index eaaead249a5..00000000000 --- a/src/NHibernate.Test/Async/DynamicProxyTests/PeVerifyFixture.cs +++ /dev/null @@ -1,133 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by AsyncGenerator. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - - -using System; -using System.IO; -using System.Reflection; -using System.Reflection.Emit; -using NUnit.Framework; -using NHibernate.Proxy.DynamicProxy; - -namespace NHibernate.Test.DynamicProxyTests -{ - using System.Threading.Tasks; - [TestFixture] - public class PeVerifyFixtureAsync - { - private static bool wasCalled; - - private const string assemblyName = "peVerifyAssembly"; - private const string assemblyFileName = "peVerifyAssembly.dll"; - - [Test] - public Task VerifyClassWithPublicConstructorAsync() - { - try - { - var factory = new ProxyFactory(new SavingProxyAssemblyBuilder(assemblyName)); - var proxyType = factory.CreateProxyType(typeof(ClassWithPublicDefaultConstructor), null); - - wasCalled = false; - Activator.CreateInstance(proxyType); - - Assert.That(wasCalled); - return new PeVerifier(assemblyFileName).AssertIsValidAsync(); - } - catch (Exception ex) - { - return Task.FromException(ex); - } - } - - [Test] - public Task VerifyClassWithProtectedConstructorAsync() - { - try - { - var factory = new ProxyFactory(new SavingProxyAssemblyBuilder(assemblyName)); - var proxyType = factory.CreateProxyType(typeof(ClassWithProtectedDefaultConstructor), null); - - wasCalled = false; - Activator.CreateInstance(proxyType); - - Assert.That(wasCalled); - return new PeVerifier(assemblyFileName).AssertIsValidAsync(); - } - catch (Exception ex) - { - return Task.FromException(ex); - } - } - - #region PeVerifyTypes - - public class ClassWithPublicDefaultConstructor - { - public ClassWithPublicDefaultConstructor() { InitG(1); } - public ClassWithPublicDefaultConstructor(int unused) { } - public virtual int Prop1 { get; set; } - public virtual void InitG(T value) { Init((int)(object)value); } - public virtual void Init(int value) { Prop1 = value; if (Prop1 == 1) wasCalled = true; } - } - - public class ClassWithProtectedDefaultConstructor - { - protected ClassWithProtectedDefaultConstructor() { wasCalled = true; } - } - - public class ClassWithPrivateDefaultConstructor - { - private ClassWithPrivateDefaultConstructor() { wasCalled = true; } - } - - public class ClassWithNoDefaultConstructor - { - public ClassWithNoDefaultConstructor(int unused) { wasCalled = true; } - public ClassWithNoDefaultConstructor(string unused) { wasCalled = true; } - } - - public class ClassWithInternalConstructor - { - internal ClassWithInternalConstructor() { wasCalled = true; } - } - - #endregion - - #region ProxyFactory.IProxyAssemblyBuilder - - public class SavingProxyAssemblyBuilder : IProxyAssemblyBuilder - { - private string assemblyName; - - public SavingProxyAssemblyBuilder(string assemblyName) - { - this.assemblyName = assemblyName; - } - - public AssemblyBuilder DefineDynamicAssembly(AppDomain appDomain, AssemblyName name) - { - AssemblyBuilderAccess access = AssemblyBuilderAccess.RunAndSave; - return appDomain.DefineDynamicAssembly(new AssemblyName(assemblyName), access, TestContext.CurrentContext.TestDirectory); - } - - public ModuleBuilder DefineDynamicModule(AssemblyBuilder assemblyBuilder, string moduleName) - { - return assemblyBuilder.DefineDynamicModule(moduleName, string.Format("{0}.mod", assemblyName), true); - } - - public void Save(AssemblyBuilder assemblyBuilder) - { - assemblyBuilder.Save(assemblyName + ".dll"); - } - } - - #endregion - } -} diff --git a/src/NHibernate.Test/CfgTest/Loquacious/ConfigurationFixture.cs b/src/NHibernate.Test/CfgTest/Loquacious/ConfigurationFixture.cs index d9b94d355de..a3444ad1f37 100644 --- a/src/NHibernate.Test/CfgTest/Loquacious/ConfigurationFixture.cs +++ b/src/NHibernate.Test/CfgTest/Loquacious/ConfigurationFixture.cs @@ -9,7 +9,6 @@ using NHibernate.Driver; using NHibernate.Exceptions; using NHibernate.Hql.Ast.ANTLR; -using NHibernate.Linq; using NHibernate.Type; using NUnit.Framework; @@ -37,7 +36,7 @@ public void CompleteConfiguration() .Through() .Proxy .DisableValidation() - .Through() + .Through() .ParsingHqlThrough() .Mapping .UsingDefaultCatalog("MyCatalog") @@ -75,7 +74,7 @@ public void CompleteConfiguration() Assert.That(cfg.Properties[Environment.CacheDefaultExpiration], Is.EqualTo("15")); Assert.That(cfg.Properties[Environment.CollectionTypeFactoryClass], Is.EqualTo(typeof(DefaultCollectionTypeFactory).AssemblyQualifiedName)); Assert.That(cfg.Properties[Environment.UseProxyValidator], Is.EqualTo("false")); - Assert.That(cfg.Properties[Environment.ProxyFactoryFactoryClass], Is.EqualTo(typeof(DefaultProxyFactoryFactory).AssemblyQualifiedName)); + Assert.That(cfg.Properties[Environment.ProxyFactoryFactoryClass], Is.EqualTo(typeof(StaticProxyFactoryFactory).AssemblyQualifiedName)); Assert.That(cfg.Properties[Environment.QueryTranslator], Is.EqualTo(typeof(ASTQueryTranslatorFactory).AssemblyQualifiedName)); Assert.That(cfg.Properties[Environment.DefaultCatalog], Is.EqualTo("MyCatalog")); Assert.That(cfg.Properties[Environment.DefaultSchema], Is.EqualTo("MySche")); @@ -108,13 +107,13 @@ public void UseDbConfigurationStringBuilder() // The place where put default properties values is the Dialect itself. var cfg = new Configuration(); cfg.SessionFactory() - .Proxy.Through() + .Proxy.Through() .Integrate .Using() .Connected .Using(new SqlConnectionStringBuilder { DataSource = "(local)", InitialCatalog = "nhibernate", IntegratedSecurity = true }); - Assert.That(cfg.Properties[Environment.ProxyFactoryFactoryClass], Is.EqualTo(typeof(DefaultProxyFactoryFactory).AssemblyQualifiedName)); + Assert.That(cfg.Properties[Environment.ProxyFactoryFactoryClass], Is.EqualTo(typeof(StaticProxyFactoryFactory).AssemblyQualifiedName)); Assert.That(cfg.Properties[Environment.Dialect], Is.EqualTo(typeof(MsSql2005Dialect).AssemblyQualifiedName)); Assert.That(cfg.Properties[Environment.ConnectionString], Is.EqualTo("Data Source=(local);Initial Catalog=nhibernate;Integrated Security=True")); } diff --git a/src/NHibernate.Test/CfgTest/Loquacious/LambdaConfigurationFixture.cs b/src/NHibernate.Test/CfgTest/Loquacious/LambdaConfigurationFixture.cs index f422035fd85..209f6e061d2 100644 --- a/src/NHibernate.Test/CfgTest/Loquacious/LambdaConfigurationFixture.cs +++ b/src/NHibernate.Test/CfgTest/Loquacious/LambdaConfigurationFixture.cs @@ -35,7 +35,7 @@ public void FullConfiguration() configure.Proxy(p => { p.Validation = false; - p.ProxyFactoryFactory(); + p.ProxyFactoryFactory(); }); configure.Mappings(m=> { @@ -76,7 +76,7 @@ public void FullConfiguration() Is.EqualTo(typeof(DefaultCollectionTypeFactory).AssemblyQualifiedName)); Assert.That(configure.Properties[Environment.UseProxyValidator], Is.EqualTo("false")); Assert.That(configure.Properties[Environment.ProxyFactoryFactoryClass], - Is.EqualTo(typeof(DefaultProxyFactoryFactory).AssemblyQualifiedName)); + Is.EqualTo(typeof(StaticProxyFactoryFactory).AssemblyQualifiedName)); Assert.That(configure.Properties[Environment.QueryTranslator], Is.EqualTo(typeof(ASTQueryTranslatorFactory).AssemblyQualifiedName)); Assert.That(configure.Properties[Environment.DefaultCatalog], Is.EqualTo("MyCatalog")); diff --git a/src/NHibernate.Test/DynamicEntity/DataProxyHandler.cs b/src/NHibernate.Test/DynamicEntity/DataProxyHandler.cs index 9ba4ffef3c8..bce91d9424b 100644 --- a/src/NHibernate.Test/DynamicEntity/DataProxyHandler.cs +++ b/src/NHibernate.Test/DynamicEntity/DataProxyHandler.cs @@ -1,8 +1,10 @@ +using System; using System.Collections; using NHibernate.Proxy.DynamicProxy; namespace NHibernate.Test.DynamicEntity { + [Obsolete("Require dynamic proxies")] public sealed class DataProxyHandler : Proxy.DynamicProxy.IInterceptor { private readonly Hashtable data = new Hashtable(); @@ -56,4 +58,4 @@ public object Intercept(InvocationInfo info) #endregion } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/DynamicEntity/IProxyMarker.cs b/src/NHibernate.Test/DynamicEntity/IProxyMarker.cs index 0b6e1f35b1b..7d420fd1df9 100644 --- a/src/NHibernate.Test/DynamicEntity/IProxyMarker.cs +++ b/src/NHibernate.Test/DynamicEntity/IProxyMarker.cs @@ -1,7 +1,10 @@ +using System; + namespace NHibernate.Test.DynamicEntity { + [Obsolete("Require dynamic proxies")] public interface IProxyMarker { DataProxyHandler DataHandler { get;} } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/DynamicEntity/Interceptor/InterceptorDynamicEntity.cs b/src/NHibernate.Test/DynamicEntity/Interceptor/InterceptorDynamicEntity.cs index b1ef935d3b9..cf432b6614f 100644 --- a/src/NHibernate.Test/DynamicEntity/Interceptor/InterceptorDynamicEntity.cs +++ b/src/NHibernate.Test/DynamicEntity/Interceptor/InterceptorDynamicEntity.cs @@ -1,3 +1,4 @@ +using System; using System.Collections; using NHibernate.Cfg; using NUnit.Framework; @@ -5,6 +6,7 @@ namespace NHibernate.Test.DynamicEntity.Interceptor { [TestFixture] + [Obsolete("Require dynamic proxies")] public class InterceptorDynamicEntity : TestCase { protected override string MappingsAssembly @@ -89,4 +91,4 @@ public void It() session.Close(); } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/DynamicEntity/Interceptor/ProxyInterceptor.cs b/src/NHibernate.Test/DynamicEntity/Interceptor/ProxyInterceptor.cs index 3fc1b3bba45..b83c968b8e5 100644 --- a/src/NHibernate.Test/DynamicEntity/Interceptor/ProxyInterceptor.cs +++ b/src/NHibernate.Test/DynamicEntity/Interceptor/ProxyInterceptor.cs @@ -1,5 +1,8 @@ +using System; + namespace NHibernate.Test.DynamicEntity.Interceptor { + [Obsolete("Require dynamic proxies")] public class ProxyInterceptor : EmptyInterceptor { public override string GetEntityName(object entity) @@ -21,4 +24,4 @@ public override object Instantiate(string entityName, object id) return base.Instantiate(entityName, id); } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/DynamicEntity/ProxyHelper.cs b/src/NHibernate.Test/DynamicEntity/ProxyHelper.cs index a93378e23d4..30f891e9417 100644 --- a/src/NHibernate.Test/DynamicEntity/ProxyHelper.cs +++ b/src/NHibernate.Test/DynamicEntity/ProxyHelper.cs @@ -1,7 +1,9 @@ +using System; using NHibernate.Proxy.DynamicProxy; namespace NHibernate.Test.DynamicEntity { + [Obsolete("Require dynamic proxies")] public class ProxyHelper { private static readonly ProxyFactory proxyGenerator = new ProxyFactory(); @@ -67,4 +69,4 @@ public static string ExtractEntityName(object obj) return null; } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/DynamicEntity/Tuplizer/EntityNameInterceptor.cs b/src/NHibernate.Test/DynamicEntity/Tuplizer/EntityNameInterceptor.cs index 60981b7cbbd..253619b37fd 100644 --- a/src/NHibernate.Test/DynamicEntity/Tuplizer/EntityNameInterceptor.cs +++ b/src/NHibernate.Test/DynamicEntity/Tuplizer/EntityNameInterceptor.cs @@ -1,5 +1,8 @@ +using System; + namespace NHibernate.Test.DynamicEntity.Tuplizer { + [Obsolete("Require dynamic proxies")] public class EntityNameInterceptor : EmptyInterceptor { public override string GetEntityName(object entity) @@ -8,4 +11,4 @@ public override string GetEntityName(object entity) return entityName; } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/DynamicEntity/Tuplizer/MyEntityInstantiator.cs b/src/NHibernate.Test/DynamicEntity/Tuplizer/MyEntityInstantiator.cs index f4c31e9d160..1a966901f52 100644 --- a/src/NHibernate.Test/DynamicEntity/Tuplizer/MyEntityInstantiator.cs +++ b/src/NHibernate.Test/DynamicEntity/Tuplizer/MyEntityInstantiator.cs @@ -3,6 +3,7 @@ namespace NHibernate.Test.DynamicEntity.Tuplizer { + [Obsolete("Require dynamic proxies")] public class MyEntityInstantiator : IInstantiator { private readonly System.Type entityType; @@ -53,4 +54,4 @@ public bool IsInstance(object obj) } } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/DynamicEntity/Tuplizer/MyEntityTuplizer.cs b/src/NHibernate.Test/DynamicEntity/Tuplizer/MyEntityTuplizer.cs index 6a2151db897..b31d59b55d8 100644 --- a/src/NHibernate.Test/DynamicEntity/Tuplizer/MyEntityTuplizer.cs +++ b/src/NHibernate.Test/DynamicEntity/Tuplizer/MyEntityTuplizer.cs @@ -1,8 +1,10 @@ +using System; using NHibernate.Mapping; using NHibernate.Tuple.Entity; namespace NHibernate.Test.DynamicEntity.Tuplizer { + [Obsolete("Require dynamic proxies")] public class MyEntityTuplizer : PocoEntityTuplizer { public MyEntityTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity) : base(entityMetamodel, mappedEntity) {} @@ -21,4 +23,4 @@ protected override Proxy.IProxyFactory BuildProxyFactory(PersistentClass persist return base.BuildProxyFactory(persistentClass, idGetter, idSetter); } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/DynamicEntity/Tuplizer/TuplizerDynamicEntity.cs b/src/NHibernate.Test/DynamicEntity/Tuplizer/TuplizerDynamicEntity.cs index 1db77de4399..7ce1fa9925e 100644 --- a/src/NHibernate.Test/DynamicEntity/Tuplizer/TuplizerDynamicEntity.cs +++ b/src/NHibernate.Test/DynamicEntity/Tuplizer/TuplizerDynamicEntity.cs @@ -1,3 +1,4 @@ +using System; using System.Collections; using System.Collections.Generic; using NHibernate.Cfg; @@ -6,6 +7,7 @@ namespace NHibernate.Test.DynamicEntity.Tuplizer { [TestFixture] + [Obsolete("Require dynamic proxies")] public class TuplizerDynamicEntity : TestCase { protected override string MappingsAssembly @@ -105,4 +107,4 @@ public void It() session.Close(); } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/DynamicProxyTests/GenericMethodsTests/GenericMethodShouldBeProxied.cs b/src/NHibernate.Test/DynamicProxyTests/GenericMethodsTests/GenericMethodShouldBeProxied.cs index 562e5fa0a16..4da9bb2030f 100644 --- a/src/NHibernate.Test/DynamicProxyTests/GenericMethodsTests/GenericMethodShouldBeProxied.cs +++ b/src/NHibernate.Test/DynamicProxyTests/GenericMethodsTests/GenericMethodShouldBeProxied.cs @@ -1,9 +1,11 @@ +using System; using NHibernate.Proxy.DynamicProxy; using NUnit.Framework; namespace NHibernate.Test.DynamicProxyTests.GenericMethodsTests { [TestFixture] + [Obsolete] public class GenericMethodShouldBeProxied { [Test] @@ -244,4 +246,4 @@ public void GenericInterfaceConstraint() class MyDerivedClass : MyClass, IMyInterface { } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/DynamicProxyTests/InterfaceWithEqualsGethashcodeTests.cs b/src/NHibernate.Test/DynamicProxyTests/InterfaceWithEqualsGethashcodeTests.cs index 6cefe2a2073..1fd5d83be61 100644 --- a/src/NHibernate.Test/DynamicProxyTests/InterfaceWithEqualsGethashcodeTests.cs +++ b/src/NHibernate.Test/DynamicProxyTests/InterfaceWithEqualsGethashcodeTests.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using NHibernate.Proxy.DynamicProxy; using NUnit.Framework; @@ -5,6 +6,7 @@ namespace NHibernate.Test.DynamicProxyTests { [TestFixture] + [Obsolete] public class InterfaceWithEqualsGethashcodeTests { public interface IMyBaseObject diff --git a/src/NHibernate.Test/DynamicProxyTests/LazyFieldInterceptorTests.cs b/src/NHibernate.Test/DynamicProxyTests/LazyFieldInterceptorTests.cs index c8e96b42b9a..a6fe4ecd1ee 100644 --- a/src/NHibernate.Test/DynamicProxyTests/LazyFieldInterceptorTests.cs +++ b/src/NHibernate.Test/DynamicProxyTests/LazyFieldInterceptorTests.cs @@ -6,6 +6,7 @@ namespace NHibernate.Test.DynamicProxyTests { + [Obsolete] public class LazyFieldInterceptorTests { [Serializable] diff --git a/src/NHibernate.Test/DynamicProxyTests/PassThroughInterceptor.cs b/src/NHibernate.Test/DynamicProxyTests/PassThroughInterceptor.cs index 440795670f2..1797a882b99 100644 --- a/src/NHibernate.Test/DynamicProxyTests/PassThroughInterceptor.cs +++ b/src/NHibernate.Test/DynamicProxyTests/PassThroughInterceptor.cs @@ -3,6 +3,7 @@ namespace NHibernate.Test.DynamicProxyTests { + [Obsolete] public class PassThroughInterceptor : NHibernate.Proxy.DynamicProxy.IInterceptor { private readonly object targetInstance; @@ -17,4 +18,4 @@ public object Intercept(InvocationInfo info) return info.TargetMethod.Invoke(targetInstance, info.Arguments); } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/DynamicProxyTests/PeVerifyFixture.cs b/src/NHibernate.Test/DynamicProxyTests/PeVerifyFixture.cs index 6ffe80215e5..2ab4be3524b 100644 --- a/src/NHibernate.Test/DynamicProxyTests/PeVerifyFixture.cs +++ b/src/NHibernate.Test/DynamicProxyTests/PeVerifyFixture.cs @@ -1,13 +1,14 @@ using System; -using System.IO; using System.Reflection; using System.Reflection.Emit; using NUnit.Framework; using NHibernate.Proxy.DynamicProxy; +using NHibernate.Test.ProxyTest; namespace NHibernate.Test.DynamicProxyTests { [TestFixture] + [Obsolete] public class PeVerifyFixture { private static bool wasCalled; diff --git a/src/NHibernate.Test/DynamicProxyTests/ProxiedMembers/Fixture.cs b/src/NHibernate.Test/DynamicProxyTests/ProxiedMembers/Fixture.cs index 14cffb2cbee..08861d00598 100644 --- a/src/NHibernate.Test/DynamicProxyTests/ProxiedMembers/Fixture.cs +++ b/src/NHibernate.Test/DynamicProxyTests/ProxiedMembers/Fixture.cs @@ -1,3 +1,4 @@ +using System; using NHibernate.Proxy.DynamicProxy; using NUnit.Framework; @@ -27,6 +28,7 @@ public virtual void Method4(ref int? y) } [TestFixture] + [Obsolete] public class Fixture { [Test] diff --git a/src/NHibernate.Test/DynamicProxyTests/ProxiedMembers/MetodWithRefDictionaryTest.cs b/src/NHibernate.Test/DynamicProxyTests/ProxiedMembers/MetodWithRefDictionaryTest.cs index 280e1bc8b43..3e0853bf8b0 100644 --- a/src/NHibernate.Test/DynamicProxyTests/ProxiedMembers/MetodWithRefDictionaryTest.cs +++ b/src/NHibernate.Test/DynamicProxyTests/ProxiedMembers/MetodWithRefDictionaryTest.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using NHibernate.Proxy.DynamicProxy; using NUnit.Framework; @@ -5,6 +6,7 @@ namespace NHibernate.Test.DynamicProxyTests.ProxiedMembers { [TestFixture] + [Obsolete] public class MetodWithRefDictionaryTest { public class MyClass diff --git a/src/NHibernate.Test/NHSpecificTest/NH3954/EqualsFixture.cs b/src/NHibernate.Test/NHSpecificTest/NH3954/EqualsFixture.cs index 5d55e7c0a1f..107705889f2 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH3954/EqualsFixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH3954/EqualsFixture.cs @@ -2,7 +2,6 @@ using System.Reflection; using System.Runtime.Serialization; using NHibernate.Proxy; -using NHibernate.Proxy.DynamicProxy; using NHibernate.Type; using NUnit.Framework; diff --git a/src/NHibernate.Test/NHSpecificTest/NH3954/ProxyCacheFixture.cs b/src/NHibernate.Test/NHSpecificTest/NH3954/ProxyCacheFixture.cs index 0583f96a0b1..43023a92ff0 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH3954/ProxyCacheFixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH3954/ProxyCacheFixture.cs @@ -5,6 +5,9 @@ using NHibernate.Proxy; using NHibernate.Proxy.DynamicProxy; using NUnit.Framework; +#pragma warning disable 618 +using ProxyCacheEntry = NHibernate.Proxy.DynamicProxy.ProxyCacheEntry; +#pragma warning restore 618 namespace NHibernate.Test.NHSpecificTest.NH3954 { diff --git a/src/NHibernate.Test/DynamicProxyTests/PeVerifier.cs b/src/NHibernate.Test/ProxyTest/PeVerifier.cs similarity index 96% rename from src/NHibernate.Test/DynamicProxyTests/PeVerifier.cs rename to src/NHibernate.Test/ProxyTest/PeVerifier.cs index c9a70534d46..f5f4d027221 100644 --- a/src/NHibernate.Test/DynamicProxyTests/PeVerifier.cs +++ b/src/NHibernate.Test/ProxyTest/PeVerifier.cs @@ -3,11 +3,11 @@ using System.IO; using NUnit.Framework; -namespace NHibernate.Test.DynamicProxyTests +namespace NHibernate.Test.ProxyTest { // utility class to run PEVerify.exe against a saved-to-disk assembly, similar to: // http://stackoverflow.com/questions/7290893/is-there-an-api-for-verifying-the-msil-of-a-dynamic-assembly-at-runtime - public partial class PeVerifier + public class PeVerifier { private string _assemlyLocation; private string _peVerifyPath; diff --git a/src/NHibernate.Test/StaticProxyTest/StaticProxyFactoryFixture.cs b/src/NHibernate.Test/StaticProxyTest/StaticProxyFactoryFixture.cs index 72a1937ae20..4dae9a5b8a2 100644 --- a/src/NHibernate.Test/StaticProxyTest/StaticProxyFactoryFixture.cs +++ b/src/NHibernate.Test/StaticProxyTest/StaticProxyFactoryFixture.cs @@ -1,28 +1,267 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; +using System.Security; using NHibernate.Proxy; using NUnit.Framework; +#if NETFX +using System.Reflection; +using NHibernate.Test.ProxyTest; +#else +using System.Globalization; +using NHibernate.Test.Legacy; +using NHibernate.Util; +#endif + namespace NHibernate.Test.StaticProxyTest { public class StaticProxyFactoryFixture { - internal interface ISomething + internal interface IInternal + { + int Id { get; } + } + + [Serializable] + public class InternalInterfaceTestClass : IInternal + { + public virtual int Id { get; set; } + } + + public interface IPublic { int Id { get; } } - public class TestClass : ISomething + [Serializable] + public class PublicInterfaceTestClass : IPublic { public virtual int Id { get; set; } } + [Serializable] + public class CustomSerializationClass : ISerializable + { + public virtual int Id { get; set; } + + public CustomSerializationClass() + { + } + + protected CustomSerializationClass(SerializationInfo info, StreamingContext context) + { + Id = info.GetInt32(nameof(Id)); + } + + [SecurityCritical] + public virtual void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue(nameof(Id), Id); + } + } + + [Serializable] + public class CustomExplicitSerializationClass : ISerializable + { + public virtual int Id { get; set; } + + public CustomExplicitSerializationClass() + { + } + + protected CustomExplicitSerializationClass(SerializationInfo info, StreamingContext context) + { + Id = info.GetInt32(nameof(Id)); + } + + [SecurityCritical] + void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) + { + GetObjectData(info, context); + } + + protected virtual void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue(nameof(Id), Id); + } + } + + [Test] + public void VerifyProxyForClassWithInternalInterface() + { + var factory = new StaticProxyFactory(); + factory.PostInstantiate(typeof(InternalInterfaceTestClass).FullName, typeof(InternalInterfaceTestClass), new HashSet {typeof(INHibernateProxy)}, null, null, null); + +#if NETFX + VerifyGeneratedAssembly( + () => + { +#endif + var proxy = factory.GetProxy(1, null); + Assert.That(proxy, Is.Not.Null); +#if NETFX + }); +#endif + } + + [Test] + public void CanSerializeFieldInterceptorProxy() + { + var factory = new StaticProxyFactory(); + factory.PostInstantiate(typeof(PublicInterfaceTestClass).FullName, typeof(PublicInterfaceTestClass), new HashSet {typeof(INHibernateProxy)}, null, null, null); + var proxy = (PublicInterfaceTestClass) factory.GetFieldInterceptionProxy(new PublicInterfaceTestClass()); + proxy.Id = 1; + + var serializer = GetFormatter(); + using (var memoryStream = new MemoryStream()) + { + serializer.Serialize(memoryStream, proxy); + memoryStream.Seek(0L, SeekOrigin.Begin); + proxy = (PublicInterfaceTestClass) serializer.Deserialize(memoryStream); + Assert.That(proxy.Id, Is.EqualTo(1)); + } + } + + [Test] + public void CanSerializeFieldInterceptorProxyWithISerializableEntity() + { + var factory = new StaticProxyFactory(); + factory.PostInstantiate(typeof(CustomSerializationClass).FullName, typeof(CustomSerializationClass), new HashSet {typeof(INHibernateProxy)}, null, null, null); + var proxy = (CustomSerializationClass) factory.GetFieldInterceptionProxy(new CustomSerializationClass()); + proxy.Id = 2; + + var serializer = GetFormatter(); + using (var memoryStream = new MemoryStream()) + { + serializer.Serialize(memoryStream, proxy); + memoryStream.Seek(0L, SeekOrigin.Begin); + proxy = (CustomSerializationClass) serializer.Deserialize(memoryStream); + Assert.That(proxy.Id, Is.EqualTo(2)); + } + } + [Test] - public void CanCreateProxyForClassWithInternalInterface() + public void CanSerializeFieldInterceptorProxyWithExplicitISerializableEntity() { var factory = new StaticProxyFactory(); - factory.PostInstantiate(typeof(TestClass).FullName, typeof(TestClass), new HashSet {typeof(INHibernateProxy)}, null, null, null); - var proxy = factory.GetProxy(1, null); - Assert.That(proxy, Is.Not.Null); + factory.PostInstantiate(typeof(CustomExplicitSerializationClass).FullName, typeof(CustomExplicitSerializationClass), new HashSet {typeof(INHibernateProxy)}, null, null, null); + var proxy = (CustomExplicitSerializationClass) factory.GetFieldInterceptionProxy(new CustomExplicitSerializationClass()); + proxy.Id = 2; + + var serializer = GetFormatter(); + using (var memoryStream = new MemoryStream()) + { + serializer.Serialize(memoryStream, proxy); + memoryStream.Seek(0L, SeekOrigin.Begin); + proxy = (CustomExplicitSerializationClass) serializer.Deserialize(memoryStream); + Assert.That(proxy.Id, Is.EqualTo(2)); + } + } + + [Test] + public void VerifyFieldInterceptorProxy() + { + var factory = new StaticProxyFactory(); + factory.PostInstantiate(typeof(InternalInterfaceTestClass).FullName, typeof(InternalInterfaceTestClass), new HashSet {typeof(INHibernateProxy)}, null, null, null); +#if NETFX + VerifyGeneratedAssembly( + () => + { +#endif + var fieldProxy = factory.GetFieldInterceptionProxy(new InternalInterfaceTestClass()); + Assert.That(fieldProxy, Is.InstanceOf()); +#if NETFX + }); +#endif + } + + [Test] + public void VerifyFieldInterceptorProxyWithISerializableEntity() + { + var factory = new StaticProxyFactory(); + factory.PostInstantiate(typeof(CustomSerializationClass).FullName, typeof(CustomSerializationClass), new HashSet {typeof(INHibernateProxy)}, null, null, null); +#if NETFX + VerifyGeneratedAssembly( + () => + { +#endif + var fieldProxy = factory.GetFieldInterceptionProxy(new CustomSerializationClass()); + Assert.That(fieldProxy, Is.InstanceOf()); +#if NETFX + }); +#endif + } + + [Test] + public void VerifyFieldInterceptorProxyWithAdditionalInterface() + { + var factory = new StaticProxyFactory(); + factory.PostInstantiate( + typeof(PublicInterfaceTestClass).FullName, + typeof(PublicInterfaceTestClass), + // By way of the "proxy" attribute on the "class" mapping, an interface to use for the + // lazy entity load proxy instead of the persistentClass can be specified. This is "translated" into + // having an additional interface in the interface list, instead of just having INHibernateProxy. + // (Quite a loosy semantic...) + // The field interceptor proxy ignores this setting, as it does not delegate its implementation + // to an instance of the persistentClass, and so cannot implement interface methods if it does not + // inherit the persitentClass. + new HashSet {typeof(INHibernateProxy), typeof(IPublic)}, + null, null, null); +#if NETFX + VerifyGeneratedAssembly( + () => + { +#endif + var fieldProxy = factory.GetFieldInterceptionProxy(new PublicInterfaceTestClass()); + Assert.That(fieldProxy, Is.InstanceOf()); +#if NETFX + }); +#endif + } + + private static BinaryFormatter GetFormatter() + { +#if NETFX + return new BinaryFormatter(); +#else + var selector = new SurrogateSelector(); + selector.AddSurrogate( + typeof(CultureInfo), + new StreamingContext(StreamingContextStates.All), + new CultureInfoSerializationSurrogate()); + selector.ChainSelector(new SerializationHelper.SurrogateSelector()); + return new BinaryFormatter + { + SurrogateSelector = selector + }; +#endif + } + +#if NETFX + private static void VerifyGeneratedAssembly(System.Action assemblyGenerator) + { + var proxyBuilderHelperType = typeof(StaticProxyFactory).Assembly.GetType("NHibernate.Proxy.ProxyBuilderHelper", true); + var enableSave = proxyBuilderHelperType.GetMethod("EnableDynamicAssemblySaving", BindingFlags.NonPublic | BindingFlags.Static); + Assert.That(enableSave, Is.Not.Null, "Failed to find method EnableDynamicAssemblySaving"); + + const string assemblyName = "VerifyFieldInterceptorProxy.dll"; + var assemblyPath = Path.Combine(TestContext.CurrentContext.TestDirectory, assemblyName); + enableSave.Invoke(null, new object[] { true, assemblyPath }); + try + { + assemblyGenerator(); + } + finally + { + enableSave.Invoke(null, new object[] { false, null }); + } + + new PeVerifier(assemblyName).AssertIsValid(); } +#endif } } diff --git a/src/NHibernate/Bytecode/DefaultProxyFactoryFactory.cs b/src/NHibernate/Bytecode/DefaultProxyFactoryFactory.cs index b4321326ab2..fa4c9b5dd27 100644 --- a/src/NHibernate/Bytecode/DefaultProxyFactoryFactory.cs +++ b/src/NHibernate/Bytecode/DefaultProxyFactoryFactory.cs @@ -1,7 +1,10 @@ +using System; using NHibernate.Proxy; namespace NHibernate.Bytecode { + // Since v5.2 + [Obsolete("Use StaticProxyFactoryFactory instead")] public class DefaultProxyFactoryFactory : IProxyFactoryFactory { #region IProxyFactoryFactory Members @@ -28,4 +31,4 @@ public bool IsProxy(object entity) #endregion } -} \ No newline at end of file +} diff --git a/src/NHibernate/Intercept/DefaultDynamicLazyFieldInterceptor.cs b/src/NHibernate/Intercept/DefaultDynamicLazyFieldInterceptor.cs index 5e4ec4bdcbc..345f28656d5 100644 --- a/src/NHibernate/Intercept/DefaultDynamicLazyFieldInterceptor.cs +++ b/src/NHibernate/Intercept/DefaultDynamicLazyFieldInterceptor.cs @@ -6,6 +6,8 @@ namespace NHibernate.Intercept { [Serializable] + // Since v5.2 + [Obsolete("Dynamic proxy has been obsoleted, use static proxies instead (see StaticProxyFactory)")] public class DefaultDynamicLazyFieldInterceptor : IFieldInterceptorAccessor, Proxy.DynamicProxy.IInterceptor { public IFieldInterceptor FieldInterceptor { get; set; } diff --git a/src/NHibernate/Proxy/DefaultLazyInitializer.cs b/src/NHibernate/Proxy/DefaultLazyInitializer.cs index 60266476e76..d3a5bcf38cb 100644 --- a/src/NHibernate/Proxy/DefaultLazyInitializer.cs +++ b/src/NHibernate/Proxy/DefaultLazyInitializer.cs @@ -9,6 +9,8 @@ namespace NHibernate.Proxy { [Serializable] + // Since v5.2 + [Obsolete("Dynamic proxy has been obsoleted, use static proxies instead (see StaticProxyFactory)")] public class DefaultLazyInitializer : BasicLazyInitializer, DynamicProxy.IInterceptor { public DefaultLazyInitializer(string entityName, System.Type persistentClass, object id, MethodInfo getIdentifierMethod, @@ -39,4 +41,4 @@ public object Intercept(InvocationInfo info) return returnValue; } } -} \ No newline at end of file +} diff --git a/src/NHibernate/Proxy/DefaultProxyFactory.cs b/src/NHibernate/Proxy/DefaultProxyFactory.cs index 71655dd5860..5feccd2f6c6 100644 --- a/src/NHibernate/Proxy/DefaultProxyFactory.cs +++ b/src/NHibernate/Proxy/DefaultProxyFactory.cs @@ -5,6 +5,8 @@ namespace NHibernate.Proxy { + // Since v5.2 + [Obsolete("Use StaticProxyFactory instead")] public class DefaultProxyFactory : AbstractProxyFactory { private readonly ProxyFactory factory = new ProxyFactory(); @@ -35,4 +37,4 @@ public override object GetFieldInterceptionProxy(object instanceToWrap) return factory.CreateProxy(PersistentClass, interceptor, new[] { typeof(IFieldInterceptorAccessor) }); } } -} \ No newline at end of file +} diff --git a/src/NHibernate/Proxy/DynamicProxy/DefaultArgumentHandler.cs b/src/NHibernate/Proxy/DynamicProxy/DefaultArgumentHandler.cs index 40a7f9e3b00..bef95250ca6 100644 --- a/src/NHibernate/Proxy/DynamicProxy/DefaultArgumentHandler.cs +++ b/src/NHibernate/Proxy/DynamicProxy/DefaultArgumentHandler.cs @@ -12,6 +12,8 @@ namespace NHibernate.Proxy.DynamicProxy { + // Since v5.2 + [Obsolete("DynamicProxy namespace has been obsoleted, use static proxies instead (see StaticProxyFactory)")] internal class DefaultArgumentHandler : IArgumentHandler { #region IArgumentHandler Members diff --git a/src/NHibernate/Proxy/DynamicProxy/DefaultMethodEmitter.cs b/src/NHibernate/Proxy/DynamicProxy/DefaultMethodEmitter.cs index 7433f00072c..1562b6f4306 100644 --- a/src/NHibernate/Proxy/DynamicProxy/DefaultMethodEmitter.cs +++ b/src/NHibernate/Proxy/DynamicProxy/DefaultMethodEmitter.cs @@ -14,6 +14,8 @@ namespace NHibernate.Proxy.DynamicProxy { + // Since v5.2 + [Obsolete("DynamicProxy namespace has been obsoleted, use static proxies instead (see StaticProxyFactory)")] internal class DefaultMethodEmitter : IMethodBodyEmitter { private static readonly MethodInfo handlerMethod = ReflectHelper.GetMethod( diff --git a/src/NHibernate/Proxy/DynamicProxy/DefaultProxyAssemblyBuilder.cs b/src/NHibernate/Proxy/DynamicProxy/DefaultProxyAssemblyBuilder.cs index 541e06a61ea..b4efd1dea0c 100644 --- a/src/NHibernate/Proxy/DynamicProxy/DefaultProxyAssemblyBuilder.cs +++ b/src/NHibernate/Proxy/DynamicProxy/DefaultProxyAssemblyBuilder.cs @@ -4,6 +4,8 @@ namespace NHibernate.Proxy.DynamicProxy { + // Since v5.2 + [Obsolete("DynamicProxy namespace has been obsoleted, use static proxies instead (see StaticProxyFactory)")] public class DefaultProxyAssemblyBuilder : IProxyAssemblyBuilder { public AssemblyBuilder DefineDynamicAssembly(AppDomain appDomain, AssemblyName name) diff --git a/src/NHibernate/Proxy/DynamicProxy/DefaultProxyMethodBuilder.cs b/src/NHibernate/Proxy/DynamicProxy/DefaultProxyMethodBuilder.cs index 0e8249d2466..1925af241ff 100644 --- a/src/NHibernate/Proxy/DynamicProxy/DefaultProxyMethodBuilder.cs +++ b/src/NHibernate/Proxy/DynamicProxy/DefaultProxyMethodBuilder.cs @@ -7,14 +7,13 @@ #endregion using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; using System.Reflection; using System.Reflection.Emit; namespace NHibernate.Proxy.DynamicProxy { + // Since v5.2 + [Obsolete("DynamicProxy namespace has been obsoleted, use static proxies instead (see StaticProxyFactory)")] internal class DefaultyProxyMethodBuilder : IProxyMethodBuilder { public DefaultyProxyMethodBuilder() : this(new DefaultMethodEmitter()) { } @@ -30,119 +29,14 @@ public DefaultyProxyMethodBuilder(IMethodBodyEmitter emitter) public IMethodBodyEmitter MethodBodyEmitter { get; private set; } - internal static MethodBuilder GenerateMethodSignature(string name, MethodInfo method, TypeBuilder typeBuilder) - { - //TODO: Should we use attributes of base method? - var methodAttributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual; - - if (method.IsSpecialName) - methodAttributes |= MethodAttributes.SpecialName; - - ParameterInfo[] parameters = method.GetParameters(); - - MethodBuilder methodBuilder = typeBuilder.DefineMethod(name, - methodAttributes, - CallingConventions.HasThis, - method.ReturnType, - parameters.Select(param => param.ParameterType).ToArray()); - - System.Type[] typeArgs = method.GetGenericArguments(); - - if (typeArgs.Length > 0) - { - var typeNames = GenerateTypeNames(typeArgs.Length); - var typeArgBuilders = methodBuilder.DefineGenericParameters(typeNames); - - for (int index = 0; index < typeArgs.Length; index++) - { - // Copy generic parameter attributes (Covariant, Contravariant, ReferenceTypeConstraint, - // NotNullableValueTypeConstraint, DefaultConstructorConstraint). - var typeArgBuilder = typeArgBuilders[index]; - var typeArg = typeArgs[index]; - - typeArgBuilder.SetGenericParameterAttributes(typeArg.GenericParameterAttributes); - - // Copy generic parameter constraints (class and interfaces). - var typeConstraints = typeArg.GetGenericParameterConstraints() - .Select(x => ResolveTypeConstraint(method, x)) - .ToArray(); - - var baseTypeConstraint = typeConstraints.SingleOrDefault(x => x.IsClass); - typeArgBuilder.SetBaseTypeConstraint(baseTypeConstraint); - - var interfaceTypeConstraints = typeConstraints.Where(x => !x.IsClass).ToArray(); - typeArgBuilder.SetInterfaceConstraints(interfaceTypeConstraints); - } - } - return methodBuilder; - } - - private static System.Type ResolveTypeConstraint(MethodInfo method, System.Type typeConstraint) - { - if (typeConstraint != null && typeConstraint.IsGenericType) - { - var declaringType = method.DeclaringType; - if (declaringType != null && declaringType.IsGenericType) - { - return BuildTypeConstraint(typeConstraint, declaringType); - } - } - - return typeConstraint; - } - - private static System.Type BuildTypeConstraint(System.Type typeConstraint, System.Type declaringType) - { - var constraintGenericArguments = typeConstraint.GetGenericArguments(); - var declaringTypeGenericArguments = declaringType.GetGenericArguments(); - - var parametersMap = declaringType - .GetGenericTypeDefinition() - .GetGenericArguments() - .ToDictionary(x => x, x => declaringTypeGenericArguments[x.GenericParameterPosition]); - - var args = new System.Type[constraintGenericArguments.Length]; - var make = false; - for (int index = 0; index < constraintGenericArguments.Length; index++) - { - var genericArgument = constraintGenericArguments[index]; - System.Type result; - if (parametersMap.TryGetValue(genericArgument, out result)) - { - make = true; - } - else - { - result = genericArgument; - } - args[index] = result; - } - if (make) - { - return typeConstraint.GetGenericTypeDefinition().MakeGenericType(args); - } - - return typeConstraint; - } - - private static string[] GenerateTypeNames(int count) - { - var result = new string[count]; - for (int index = 0; index < count; index++) - { - result[index] = string.Format("T{0}", index); - } - return result; - } - public void CreateProxiedMethod(FieldInfo field, MethodInfo method, TypeBuilder typeBuilder) { - var callbackMethod = GenerateMethodSignature(method.Name + "_callback", method, typeBuilder); - var proxyMethod = GenerateMethodSignature(method.Name, method, typeBuilder); + var callbackMethod = ProxyBuilderHelper.GenerateMethodSignature(method.Name + "_callback", method, typeBuilder); + var proxyMethod = ProxyBuilderHelper.GenerateMethodSignature(method.Name, method, typeBuilder); MethodBodyEmitter.EmitMethodBody(proxyMethod, callbackMethod, method, field); typeBuilder.DefineMethodOverride(proxyMethod, method); } } -} \ No newline at end of file +} diff --git a/src/NHibernate/Proxy/DynamicProxy/IArgumentHandler.cs b/src/NHibernate/Proxy/DynamicProxy/IArgumentHandler.cs index 6dbfb8fedf9..7e2b9fea630 100644 --- a/src/NHibernate/Proxy/DynamicProxy/IArgumentHandler.cs +++ b/src/NHibernate/Proxy/DynamicProxy/IArgumentHandler.cs @@ -6,13 +6,16 @@ #endregion +using System; using System.Reflection; using System.Reflection.Emit; namespace NHibernate.Proxy.DynamicProxy { + // Since v5.2 + [Obsolete("DynamicProxy namespace has been obsoleted, use static proxies instead (see StaticProxyFactory)")] public interface IArgumentHandler { void PushArguments(ParameterInfo[] parameters, ILGenerator IL, bool isStatic); } -} \ No newline at end of file +} diff --git a/src/NHibernate/Proxy/DynamicProxy/IInterceptor.cs b/src/NHibernate/Proxy/DynamicProxy/IInterceptor.cs index 3e842bd3554..0f02f95279c 100644 --- a/src/NHibernate/Proxy/DynamicProxy/IInterceptor.cs +++ b/src/NHibernate/Proxy/DynamicProxy/IInterceptor.cs @@ -6,10 +6,14 @@ #endregion +using System; + namespace NHibernate.Proxy.DynamicProxy { + // Since v5.2 + [Obsolete("DynamicProxy namespace has been obsoleted, use static proxies instead (see StaticProxyFactory)")] public interface IInterceptor { object Intercept(InvocationInfo info); } -} \ No newline at end of file +} diff --git a/src/NHibernate/Proxy/DynamicProxy/IMethodBodyEmitter.cs b/src/NHibernate/Proxy/DynamicProxy/IMethodBodyEmitter.cs index 82691c0c7e7..9dfc34bcbc6 100644 --- a/src/NHibernate/Proxy/DynamicProxy/IMethodBodyEmitter.cs +++ b/src/NHibernate/Proxy/DynamicProxy/IMethodBodyEmitter.cs @@ -6,13 +6,16 @@ #endregion +using System; using System.Reflection; using System.Reflection.Emit; namespace NHibernate.Proxy.DynamicProxy { + // Since v5.2 + [Obsolete("DynamicProxy namespace has been obsoleted, use static proxies instead (see StaticProxyFactory)")] public interface IMethodBodyEmitter { void EmitMethodBody(MethodBuilder proxyMethod, MethodBuilder callbackMethod, MethodInfo method, FieldInfo field); } -} \ No newline at end of file +} diff --git a/src/NHibernate/Proxy/DynamicProxy/IProxy.cs b/src/NHibernate/Proxy/DynamicProxy/IProxy.cs index d288013bcb9..10fd7d0c36a 100644 --- a/src/NHibernate/Proxy/DynamicProxy/IProxy.cs +++ b/src/NHibernate/Proxy/DynamicProxy/IProxy.cs @@ -6,10 +6,14 @@ #endregion +using System; + namespace NHibernate.Proxy.DynamicProxy { + // Since v5.2 + [Obsolete("DynamicProxy namespace has been obsoleted, use static proxies instead (see StaticProxyFactory)")] public interface IProxy { IInterceptor Interceptor { get; set; } } -} \ No newline at end of file +} diff --git a/src/NHibernate/Proxy/DynamicProxy/IProxyAssemblyBuilder.cs b/src/NHibernate/Proxy/DynamicProxy/IProxyAssemblyBuilder.cs index 92e458b727b..add23264abe 100644 --- a/src/NHibernate/Proxy/DynamicProxy/IProxyAssemblyBuilder.cs +++ b/src/NHibernate/Proxy/DynamicProxy/IProxyAssemblyBuilder.cs @@ -4,6 +4,8 @@ namespace NHibernate.Proxy.DynamicProxy { + // Since v5.2 + [Obsolete("DynamicProxy namespace has been obsoleted, use static proxies instead (see StaticProxyFactory)")] public interface IProxyAssemblyBuilder { AssemblyBuilder DefineDynamicAssembly(AppDomain appDomain, AssemblyName name); diff --git a/src/NHibernate/Proxy/DynamicProxy/IProxyMethodBuilder.cs b/src/NHibernate/Proxy/DynamicProxy/IProxyMethodBuilder.cs index 9b26abec4f3..472b79bba74 100644 --- a/src/NHibernate/Proxy/DynamicProxy/IProxyMethodBuilder.cs +++ b/src/NHibernate/Proxy/DynamicProxy/IProxyMethodBuilder.cs @@ -6,13 +6,16 @@ #endregion +using System; using System.Reflection; using System.Reflection.Emit; namespace NHibernate.Proxy.DynamicProxy { + // Since v5.2 + [Obsolete("DynamicProxy namespace has been obsoleted, use static proxies instead (see StaticProxyFactory)")] public interface IProxyMethodBuilder { void CreateProxiedMethod(FieldInfo field, MethodInfo method, TypeBuilder typeBuilder); } -} \ No newline at end of file +} diff --git a/src/NHibernate/Proxy/DynamicProxy/InterceptorHandler.cs b/src/NHibernate/Proxy/DynamicProxy/InterceptorHandler.cs index 2eb16b71f69..51b0d92e07c 100644 --- a/src/NHibernate/Proxy/DynamicProxy/InterceptorHandler.cs +++ b/src/NHibernate/Proxy/DynamicProxy/InterceptorHandler.cs @@ -12,6 +12,8 @@ namespace NHibernate.Proxy.DynamicProxy { + // Since v5.2 + [Obsolete("DynamicProxy namespace has been obsoleted, use static proxies instead (see StaticProxyFactory)")] public delegate object InterceptorHandler(object proxy, MethodInfo targetMethod, StackTrace trace, System.Type[] genericTypeArgs, object[] args); -} \ No newline at end of file +} diff --git a/src/NHibernate/Proxy/DynamicProxy/InvocationHandler.cs b/src/NHibernate/Proxy/DynamicProxy/InvocationHandler.cs index 707f4e4449e..0e5807ecd23 100644 --- a/src/NHibernate/Proxy/DynamicProxy/InvocationHandler.cs +++ b/src/NHibernate/Proxy/DynamicProxy/InvocationHandler.cs @@ -6,7 +6,11 @@ #endregion +using System; + namespace NHibernate.Proxy.DynamicProxy { + // Since v5.2 + [Obsolete("DynamicProxy namespace has been obsoleted, use static proxies instead (see StaticProxyFactory)")] public delegate object InvocationHandler(InvocationInfo info); -} \ No newline at end of file +} diff --git a/src/NHibernate/Proxy/DynamicProxy/InvocationInfo.cs b/src/NHibernate/Proxy/DynamicProxy/InvocationInfo.cs index 771f74ba998..94b45e021de 100644 --- a/src/NHibernate/Proxy/DynamicProxy/InvocationInfo.cs +++ b/src/NHibernate/Proxy/DynamicProxy/InvocationInfo.cs @@ -6,6 +6,7 @@ #endregion +using System; using System.Diagnostics; using System.Reflection; using System.Text; @@ -13,6 +14,8 @@ namespace NHibernate.Proxy.DynamicProxy { + // Since v5.2 + [Obsolete("DynamicProxy namespace has been obsoleted, use static proxies instead (see StaticProxyFactory)")] public class InvocationInfo { private readonly object[] args; diff --git a/src/NHibernate/Proxy/DynamicProxy/OpCodesMap.cs b/src/NHibernate/Proxy/DynamicProxy/OpCodesMap.cs index f160570192b..a19ef42e401 100644 --- a/src/NHibernate/Proxy/DynamicProxy/OpCodesMap.cs +++ b/src/NHibernate/Proxy/DynamicProxy/OpCodesMap.cs @@ -4,6 +4,8 @@ namespace NHibernate.Proxy.DynamicProxy { + // Since v5.2 + [Obsolete("DynamicProxy namespace has been obsoleted, use static proxies instead (see StaticProxyFactory)")] public static class OpCodesMap { private static readonly Dictionary LdindMap = new Dictionary @@ -47,4 +49,4 @@ public static bool TryGetStindOpCode(System.Type valueType, out OpCode opCode) return StindMap.TryGetValue(valueType, out opCode); } } -} \ No newline at end of file +} diff --git a/src/NHibernate/Proxy/DynamicProxy/ProxyDummy.cs b/src/NHibernate/Proxy/DynamicProxy/ProxyDummy.cs index c6999264d51..027b07d1f21 100644 --- a/src/NHibernate/Proxy/DynamicProxy/ProxyDummy.cs +++ b/src/NHibernate/Proxy/DynamicProxy/ProxyDummy.cs @@ -6,10 +6,14 @@ #endregion +using System; + namespace NHibernate.Proxy.DynamicProxy { + // Since v5.2 + [Obsolete("DynamicProxy namespace has been obsoleted, use static proxies instead (see StaticProxyFactory)")] public class ProxyDummy { /* No Implementation */ } -} \ No newline at end of file +} diff --git a/src/NHibernate/Proxy/DynamicProxy/ProxyFactory.cs b/src/NHibernate/Proxy/DynamicProxy/ProxyFactory.cs index 4df3f5bf588..ad0a79a60c3 100644 --- a/src/NHibernate/Proxy/DynamicProxy/ProxyFactory.cs +++ b/src/NHibernate/Proxy/DynamicProxy/ProxyFactory.cs @@ -17,6 +17,8 @@ namespace NHibernate.Proxy.DynamicProxy { + // Since v5.2 + [Obsolete("DynamicProxy namespace has been obsoleted, use static proxies instead (see StaticProxyFactory)")] public sealed class ProxyFactory { internal static readonly ConcurrentDictionary _cache = new ConcurrentDictionary(); @@ -116,7 +118,7 @@ private TypeInfo CreateUncachedProxyType(System.Type baseType, IReadOnlyCollecti // Provide a custom implementation of ISerializable // instead of redirecting it back to the interceptor - foreach (MethodInfo method in GetProxiableMethods(baseType, interfaces).Where(method => method.DeclaringType != typeof(ISerializable))) + foreach (MethodInfo method in ProxyBuilderHelper.GetProxiableMethods(baseType, interfaces).Where(method => method.DeclaringType != typeof(ISerializable))) { ProxyMethodBuilder.CreateProxiedMethod(interceptorField, method, typeBuilder); } @@ -129,16 +131,6 @@ private TypeInfo CreateUncachedProxyType(System.Type baseType, IReadOnlyCollecti return proxyType; } - internal static IEnumerable GetProxiableMethods(System.Type type, IEnumerable interfaces) - { - const BindingFlags candidateMethodsBindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; - return - type.GetMethods(candidateMethodsBindingFlags) - .Where(method => method.IsProxiable()) - .Concat(interfaces.SelectMany(interfaceType => interfaceType.GetMethods())) - .Distinct(); - } - private static ConstructorBuilder DefineConstructor(TypeBuilder typeBuilder, System.Type parentType) { const MethodAttributes constructorAttributes = MethodAttributes.Public | diff --git a/src/NHibernate/Proxy/DynamicProxy/ProxyImplementor.cs b/src/NHibernate/Proxy/DynamicProxy/ProxyImplementor.cs index bc486aee83d..42913cb50f6 100644 --- a/src/NHibernate/Proxy/DynamicProxy/ProxyImplementor.cs +++ b/src/NHibernate/Proxy/DynamicProxy/ProxyImplementor.cs @@ -12,6 +12,8 @@ namespace NHibernate.Proxy.DynamicProxy { + // Since v5.2 + [Obsolete("DynamicProxy namespace has been obsoleted, use static proxies instead (see StaticProxyFactory)")] internal class ProxyImplementor { private const MethodAttributes InterceptorMethodsAttributes = MethodAttributes.Public | MethodAttributes.HideBySig | diff --git a/src/NHibernate/Proxy/DynamicProxy/ProxyObjectReference.cs b/src/NHibernate/Proxy/DynamicProxy/ProxyObjectReference.cs index 4b6f99d2f30..f5cf367be5d 100644 --- a/src/NHibernate/Proxy/DynamicProxy/ProxyObjectReference.cs +++ b/src/NHibernate/Proxy/DynamicProxy/ProxyObjectReference.cs @@ -14,6 +14,8 @@ namespace NHibernate.Proxy.DynamicProxy { [Serializable] + // Since v5.2 + [Obsolete("DynamicProxy namespace has been obsoleted, use static proxies instead (see StaticProxyFactory)")] public class ProxyObjectReference : IObjectReference, ISerializable { private readonly System.Type _baseType; diff --git a/src/NHibernate/Proxy/FieldInterceptorObjectReference.cs b/src/NHibernate/Proxy/FieldInterceptorObjectReference.cs new file mode 100644 index 00000000000..5c8c464cd95 --- /dev/null +++ b/src/NHibernate/Proxy/FieldInterceptorObjectReference.cs @@ -0,0 +1,132 @@ +using System; +using System.Reflection; +using System.Runtime.Serialization; +using System.Security; +using NHibernate.Intercept; +using NHibernate.Util; + +namespace NHibernate.Proxy +{ + [Serializable] + public sealed class FieldInterceptorObjectReference : IObjectReference, ISerializable + { + private readonly NHibernateProxyFactoryInfo _proxyFactoryInfo; + private readonly IFieldInterceptor _fieldInterceptor; + + [NonSerialized] + private readonly object _deserializedProxy; + + private const string HasAdditionalDataName = "proxy$hasAdditionalData"; + private const string AdditionalMemberName = "proxy$additionalMembers"; + + public FieldInterceptorObjectReference(NHibernateProxyFactoryInfo proxyFactoryInfo, IFieldInterceptor fieldInterceptorField) + { + _proxyFactoryInfo = proxyFactoryInfo; + _fieldInterceptor = fieldInterceptorField; + } + + private FieldInterceptorObjectReference(SerializationInfo info, StreamingContext context) + { + _proxyFactoryInfo = info.GetValue(nameof(_proxyFactoryInfo)); + _fieldInterceptor = info.GetValue(nameof(_fieldInterceptor)); + + if (info.GetBoolean(HasAdditionalDataName)) + { + _deserializedProxy = _proxyFactoryInfo.CreateProxyFactory().GetFieldInterceptionProxy(null); + + var additionalMembers = info.GetValue(AdditionalMemberName); + if (additionalMembers == null) + return; + + foreach (var member in additionalMembers) + { + switch (member) + { + case FieldInfo field: + field.SetValue( + _deserializedProxy, + info.GetValue(GetAdditionalMemberName(field), field.FieldType)); + break; + case PropertyInfo property: + property.SetValue( + _deserializedProxy, + info.GetValue(GetAdditionalMemberName(property), property.PropertyType)); + break; + default: + throw new NotSupportedException( + $"Deserializing a member of type {member.GetType()} is not supported."); + } + } + } + else + { + // Base type has a custom serialization, we need to call the proxy deserialization for deserializing + // base type members too. + var proxyType = _proxyFactoryInfo.CreateProxyFactory().GetFieldInterceptionProxy(null).GetType(); + var deserializationConstructor = proxyType.GetConstructor( + BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, + null, + new[] { typeof(SerializationInfo), typeof(StreamingContext) }, + null); + _deserializedProxy = deserializationConstructor.Invoke(new object[] { info, context }); + } + ((IFieldInterceptorAccessor) _deserializedProxy).FieldInterceptor = _fieldInterceptor; + } + + [SecurityCritical] + public object GetRealObject(StreamingContext context) + { + return _deserializedProxy; + } + + [SecurityCritical] + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue(nameof(_proxyFactoryInfo), _proxyFactoryInfo); + info.AddValue(nameof(_fieldInterceptor), _fieldInterceptor); + } + + [SecurityCritical] + public void GetBaseData(SerializationInfo info, StreamingContext context, object proxy, System.Type proxyBaseType) + { + if (proxyBaseType == null) + throw new ArgumentNullException(nameof(proxyBaseType)); + + info.AddValue(HasAdditionalDataName, true); + + var members = FormatterServices.GetSerializableMembers(proxyBaseType, context); + info.AddValue(AdditionalMemberName, members); + + foreach (var member in members) + { + switch (member) + { + case FieldInfo field: + info.AddValue(GetAdditionalMemberName(field), field.GetValue(proxy)); + break; + case PropertyInfo property: + info.AddValue(GetAdditionalMemberName(property), property.GetValue(proxy)); + break; + default: + throw new NotSupportedException($"Serializing a member of type {member.GetType()} is not supported."); + } + } + } + + [SecurityCritical] + public void SetNoAdditionalData(SerializationInfo info) + { + info.AddValue(HasAdditionalDataName, false); + } + + private static string GetAdditionalMemberName(FieldInfo fieldInfo) + { + return $"proxy${fieldInfo.DeclaringType.Name}${fieldInfo.Name}"; + } + + private static string GetAdditionalMemberName(PropertyInfo propertyInfo) + { + return $"proxy${propertyInfo.DeclaringType.Name}${propertyInfo.Name}"; + } + } +} diff --git a/src/NHibernate/Proxy/FieldInterceptorProxyBuilder.cs b/src/NHibernate/Proxy/FieldInterceptorProxyBuilder.cs new file mode 100644 index 00000000000..c7b9981b378 --- /dev/null +++ b/src/NHibernate/Proxy/FieldInterceptorProxyBuilder.cs @@ -0,0 +1,416 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Reflection.Emit; +using System.Runtime.Serialization; +using NHibernate.Intercept; +using NHibernate.Util; + +namespace NHibernate.Proxy +{ + internal static class FieldInterceptorProxyBuilder + { + private const MethodAttributes constructorAttributes = + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName; + + private static readonly System.Type FieldInterceptorAccessorType = typeof(IFieldInterceptorAccessor); + private static readonly PropertyInfo AccessorTypeFieldInterceptorProperty = + FieldInterceptorAccessorType.GetProperty(nameof(IFieldInterceptorAccessor.FieldInterceptor)); + private static readonly System.Type FieldInterceptorType = typeof(IFieldInterceptor); + private static readonly MethodInfo FieldInterceptorInterceptMethod = FieldInterceptorType.GetMethod(nameof(IFieldInterceptor.Intercept)); + private static readonly MethodInfo FieldInterceptorMarkDirtyMethod = FieldInterceptorType.GetMethod(nameof(IFieldInterceptor.MarkDirty)); + private static readonly System.Type AbstractFieldInterceptorType = typeof(AbstractFieldInterceptor); + private static readonly FieldInfo AbstractFieldInterceptorInvokeImplementationField = + AbstractFieldInterceptorType.GetField(nameof(AbstractFieldInterceptor.InvokeImplementation)); + + private static readonly System.Type FieldInterceptorObjectReferenceType = typeof(FieldInterceptorObjectReference); + private static readonly ConstructorInfo FieldInterceptorObjectReferenceConstructor = + FieldInterceptorObjectReferenceType.GetConstructor(new[] { typeof(NHibernateProxyFactoryInfo), typeof(IFieldInterceptor) }); + private static readonly MethodInfo FieldInterceptorObjectReferenceGetBaseDataMethod = + FieldInterceptorObjectReferenceType.GetMethod(nameof(FieldInterceptorObjectReference.GetBaseData)); + private static readonly MethodInfo FieldInterceptorObjectReferenceSetNoAdditionalDataMethod = + FieldInterceptorObjectReferenceType.GetMethod(nameof(FieldInterceptorObjectReference.SetNoAdditionalData)); + + private static readonly ConstructorInfo InvalidOperationWithMessageConstructor = + typeof(InvalidOperationException).GetConstructor(new[] { typeof(string) }); + + public static TypeInfo CreateProxyType(System.Type baseType) + { + // Avoid having a suffix ending with "Proxy", for disambiguation with INHibernateProxy proxies + var typeName = $"{baseType.Name}ProxyForFieldInterceptor"; + var assemblyName = $"{typeName}Assembly"; + var moduleName = $"{typeName}Module"; + + var name = new AssemblyName(assemblyName); + + var assemblyBuilder = ProxyBuilderHelper.DefineDynamicAssembly(AppDomain.CurrentDomain, name); + var moduleBuilder = ProxyBuilderHelper.DefineDynamicModule(assemblyBuilder, moduleName); + + const TypeAttributes typeAttributes = TypeAttributes.AutoClass | TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.BeforeFieldInit; + + var interfaces = new HashSet + { + typeof(IFieldInterceptorAccessor), + typeof(ISerializable) + }; + + // Use the object as the base type + // since we're not inheriting from any class type + var parentType = baseType; + if (baseType.IsInterface) + { + throw new ArgumentException( + $"Field interceptor proxy does not support being build on an interface baseType ({baseType.FullName}).", + nameof(baseType)); + } + + interfaces.RemoveWhere(i => !i.IsVisible); + + var typeBuilder = moduleBuilder.DefineType(typeName, typeAttributes, parentType, interfaces.ToArray()); + + var fieldInterceptorField = typeBuilder.DefineField("__fieldInterceptor", FieldInterceptorType, FieldAttributes.Private); + var proxyInfoField = typeBuilder.DefineField("__proxyInfo", typeof(NHibernateProxyFactoryInfo), FieldAttributes.Private); + + ImplementConstructor(typeBuilder, parentType, proxyInfoField); + + // Provide a custom implementation of ISerializable instead of redirecting it back to the interceptor + foreach (var method in ProxyBuilderHelper.GetProxiableMethods(baseType, interfaces.Except(new[] { typeof(ISerializable) }))) + { + CreateProxiedMethod(typeBuilder, method, fieldInterceptorField); + } + + ProxyBuilderHelper.MakeProxySerializable(typeBuilder); + ImplementDeserializationConstructor(typeBuilder, parentType); + ImplementGetObjectData(typeBuilder, proxyInfoField, fieldInterceptorField, parentType); + + var proxyType = typeBuilder.CreateTypeInfo(); + + ProxyBuilderHelper.Save(assemblyBuilder); + + return proxyType; + } + + private static void CreateProxiedMethod(TypeBuilder typeBuilder, MethodInfo method, FieldInfo fieldInterceptorField) + { + if (method == AccessorTypeFieldInterceptorProperty.GetMethod) + { + ImplementGetFieldInterceptor(typeBuilder, method, fieldInterceptorField); + } + else if (method == AccessorTypeFieldInterceptorProperty.SetMethod) + { + ImplementSetFieldInterceptor(typeBuilder, method, fieldInterceptorField); + } + else if (ReflectHelper.IsPropertyGet(method)) + { + ImplementGet(typeBuilder, method, fieldInterceptorField); + } + else if (ReflectHelper.IsPropertySet(method)) + { + ImplementSet(typeBuilder, method, fieldInterceptorField); + } + // else skip + // The field interceptor proxy stores the entity data in its base implementation (unlike + // the NHibernateProxy which delegates the entity data to an instance of the entity). + // As such, it only needs to intercept the properties, and can let the other methods be handled + // by its base implementation. + } + + private static void ImplementConstructor(TypeBuilder typeBuilder, System.Type parentType, FieldInfo proxyInfoField) + { + var constructor = typeBuilder.DefineConstructor(constructorAttributes, CallingConventions.Standard, new[] { typeof(NHibernateProxyFactoryInfo) }); + constructor.SetImplementationFlags(MethodImplAttributes.IL | MethodImplAttributes.Managed); + + var IL = constructor.GetILGenerator(); + + ProxyBuilderHelper.CallDefaultBaseConstructor(IL, parentType); + + // __proxyInfo == proxyInfo; + IL.Emit(OpCodes.Ldarg_0); + IL.Emit(OpCodes.Ldarg_1); + IL.Emit(OpCodes.Stfld, proxyInfoField); + + IL.Emit(OpCodes.Ret); + } + + private static void ImplementDeserializationConstructor(TypeBuilder typeBuilder, System.Type parentType) + { + var parameterTypes = new[] { typeof (SerializationInfo), typeof (StreamingContext) }; + var constructor = typeBuilder.DefineConstructor(constructorAttributes, CallingConventions.Standard, parameterTypes); + constructor.SetImplementationFlags(MethodImplAttributes.IL | MethodImplAttributes.Managed); + + var IL = constructor.GetILGenerator(); + + if (typeof(ISerializable).IsAssignableFrom(parentType)) + { + var baseConstructor = parentType.GetConstructor( + BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, + null, + parameterTypes, + null); + if (baseConstructor == null) + { + // Throw new InvalidOperationException(); + IL.Emit( + OpCodes.Ldstr, + $"Proxy for class {parentType.FullName} cannot be deserialized because the class implements " + + $"{nameof(ISerializable)} without having a deserialization constructor (see CA2229)."); + IL.Emit(OpCodes.Newobj, InvalidOperationWithMessageConstructor); + IL.Emit(OpCodes.Throw); + } + else + { + IL.Emit(OpCodes.Ldarg_0); + IL.Emit(OpCodes.Ldarg_1); + IL.Emit(OpCodes.Ldarg_2); + IL.Emit(OpCodes.Call, baseConstructor); + } + } + else + ProxyBuilderHelper.CallDefaultBaseConstructor(IL, parentType); + + // Everything else is done in FieldInterceptorObjectReference. + IL.Emit(OpCodes.Ret); + } + + private static void ImplementGetObjectData(TypeBuilder typeBuilder, FieldInfo proxyInfoField, FieldInfo fieldInterceptorField, System.Type parentType) + { + var methodBuilder = ProxyBuilderHelper.GetObjectDataMethodBuilder(typeBuilder); + + var IL = methodBuilder.GetILGenerator(); + IL.DeclareLocal(FieldInterceptorObjectReferenceType); + + // info.SetType(); + IL.Emit(OpCodes.Ldarg_1); + IL.Emit(OpCodes.Ldtoken, FieldInterceptorObjectReferenceType); + IL.Emit(OpCodes.Call, ReflectionCache.TypeMethods.GetTypeFromHandle); + IL.Emit(OpCodes.Callvirt, ProxyBuilderHelper.SerializationInfoSetTypeMethod); + + // var objectReference = new FieldInterceptorObjectReference(this.__proxyInfo, this.__fieldInterceptor)); + IL.Emit(OpCodes.Ldarg_0); + IL.Emit(OpCodes.Ldfld, proxyInfoField); + IL.Emit(OpCodes.Ldarg_0); + IL.Emit(OpCodes.Ldfld, fieldInterceptorField); + IL.Emit(OpCodes.Newobj, FieldInterceptorObjectReferenceConstructor); + IL.Emit(OpCodes.Stloc_0); + + // objectReference.GetObjectData(info, context); + IL.Emit(OpCodes.Ldloc_0); + IL.Emit(OpCodes.Ldarg_1); + IL.Emit(OpCodes.Ldarg_2); + IL.Emit(OpCodes.Callvirt, ProxyBuilderHelper.SerializableGetObjectDataMethod); + + if (typeof(ISerializable).IsAssignableFrom(parentType)) + { + var parentGetObjectData = parentType.GetMethod( + nameof(ISerializable.GetObjectData), + BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, + null, + new[] { typeof (SerializationInfo), typeof (StreamingContext) }, + null); + if (parentGetObjectData == null) + { + // Throw new InvalidOperationException(); + IL.Emit( + OpCodes.Ldstr, + $"Proxy for class {parentType.FullName} cannot be serialized because the class implements " + + $"{nameof(ISerializable)} without having a public or protected GetObjectData."); + IL.Emit(OpCodes.Newobj, InvalidOperationWithMessageConstructor); + IL.Emit(OpCodes.Throw); + typeBuilder.DefineMethodOverride(methodBuilder, ProxyBuilderHelper.SerializableGetObjectDataMethod); + return; + } + + // base.GetObjectData(info, context); + IL.Emit(OpCodes.Ldarg_0); + IL.Emit(OpCodes.Ldarg_1); + IL.Emit(OpCodes.Ldarg_2); + IL.Emit(OpCodes.Call, parentGetObjectData); + + // objectReference.SetNoAdditionalData(info); + IL.Emit(OpCodes.Ldloc_0); + IL.Emit(OpCodes.Ldarg_1); + IL.Emit(OpCodes.Callvirt, FieldInterceptorObjectReferenceSetNoAdditionalDataMethod); + } + else + { + // objectReference.SerializeBaseData(info, context, this, ); + IL.Emit(OpCodes.Ldloc_0); + IL.Emit(OpCodes.Ldarg_1); + IL.Emit(OpCodes.Ldarg_2); + IL.Emit(OpCodes.Ldarg_0); + IL.Emit(OpCodes.Ldtoken, parentType); + IL.Emit(OpCodes.Call, ReflectionCache.TypeMethods.GetTypeFromHandle); + IL.Emit(OpCodes.Callvirt, FieldInterceptorObjectReferenceGetBaseDataMethod); + } + + IL.Emit(OpCodes.Ret); + + typeBuilder.DefineMethodOverride(methodBuilder, ProxyBuilderHelper.SerializableGetObjectDataMethod); + } + + private static void ImplementGetFieldInterceptor(TypeBuilder typeBuilder, MethodInfo method, FieldInfo fieldInterceptorField) + { + // get { return this.__fieldInterceptor; } + + const MethodAttributes attributes = + MethodAttributes.Private | MethodAttributes.Final | MethodAttributes.HideBySig | + MethodAttributes.SpecialName | MethodAttributes.NewSlot | MethodAttributes.Virtual; + + var getMethod = typeBuilder.DefineMethod( + $"{FieldInterceptorAccessorType.FullName}.get_{nameof(INHibernateProxy.HibernateLazyInitializer)}", + attributes, CallingConventions.HasThis, FieldInterceptorType, System.Type.EmptyTypes); + getMethod.SetImplementationFlags(MethodImplAttributes.Managed | MethodImplAttributes.IL); + + var IL = getMethod.GetILGenerator(); + + IL.Emit(OpCodes.Ldarg_0); + IL.Emit(OpCodes.Ldfld, fieldInterceptorField); + IL.Emit(OpCodes.Ret); + + typeBuilder.DefineMethodOverride(getMethod, method); + } + + private static void ImplementSetFieldInterceptor(TypeBuilder typeBuilder, MethodInfo method, FieldInfo fieldInterceptorField) + { + // set { this.__fieldInterceptor = value; } + + const MethodAttributes attributes = + MethodAttributes.Private | MethodAttributes.Final | MethodAttributes.HideBySig | + MethodAttributes.SpecialName | MethodAttributes.NewSlot | MethodAttributes.Virtual; + + var setMethod = typeBuilder.DefineMethod( + $"{FieldInterceptorAccessorType.FullName}.set_{nameof(INHibernateProxy.HibernateLazyInitializer)}", + attributes, CallingConventions.HasThis, null, new[] {FieldInterceptorType}); + setMethod.SetImplementationFlags(MethodImplAttributes.Managed | MethodImplAttributes.IL); + + var IL = setMethod.GetILGenerator(); + + IL.Emit(OpCodes.Ldarg_0); + IL.Emit(OpCodes.Ldarg_1); + IL.Emit(OpCodes.Stfld, fieldInterceptorField); + IL.Emit(OpCodes.Ret); + + typeBuilder.DefineMethodOverride(setMethod, method); + } + + private static void ImplementGet(TypeBuilder typeBuilder, MethodInfo getter, FieldInfo fieldInterceptorField) + { + /* + var propValue = base.(); + if (this.__fieldInterceptor != null) + { + var result = this.__fieldInterceptor.Intercept(this, , propValue); + + if (result != AbstractFieldInterceptor.InvokeImplementation) + { + return ()result; + } + } + return propValue; + */ + var methodOverride = ProxyBuilderHelper.GenerateMethodSignature(getter.Name, getter, typeBuilder); + + var IL = methodOverride.GetILGenerator(); + IL.DeclareLocal(getter.ReturnType); // propValue + IL.DeclareLocal(typeof(object)); // result + + // var propValue = base.(); + IL.Emit(OpCodes.Ldarg_0); + IL.Emit(OpCodes.Call, getter); + IL.Emit(OpCodes.Stloc_0); + + // if (this.__fieldInterceptor != null) + IL.Emit(OpCodes.Ldarg_0); + IL.Emit(OpCodes.Ldfld, fieldInterceptorField); + IL.Emit(OpCodes.Ldnull); + var skipInterceptor = IL.DefineLabel(); + IL.Emit(OpCodes.Beq, skipInterceptor); + + // var result = this.__fieldInterceptor.Intercept(this, , propValue); + IL.Emit(OpCodes.Ldarg_0); + IL.Emit(OpCodes.Ldfld, fieldInterceptorField); + IL.Emit(OpCodes.Ldarg_0); + IL.Emit(OpCodes.Ldstr, ReflectHelper.GetPropertyName(getter)); + IL.Emit(OpCodes.Ldloc_0); + if (getter.ReturnType.IsValueType) + IL.Emit(OpCodes.Box, getter.ReturnType); + IL.Emit(OpCodes.Callvirt, FieldInterceptorInterceptMethod); + IL.Emit(OpCodes.Stloc_1); + + // if (result != AbstractFieldInterceptor.InvokeImplementation) + IL.Emit(OpCodes.Ldloc_1); + IL.Emit(OpCodes.Ldsfld, AbstractFieldInterceptorInvokeImplementationField); + var skipInterceptorResult = IL.DefineLabel(); + IL.Emit(OpCodes.Beq, skipInterceptorResult); + + // return ()result; + IL.Emit(OpCodes.Ldloc_1); + IL.Emit(OpCodes.Unbox_Any, getter.ReturnType); + IL.Emit(OpCodes.Ret); + + // end if (result != AbstractFieldInterceptor.InvokeImplementation) + IL.MarkLabel(skipInterceptorResult); + + // end if (this.__fieldInterceptor != null) + IL.MarkLabel(skipInterceptor); + + // return propValue; + IL.Emit(OpCodes.Ldloc_0); + IL.Emit(OpCodes.Ret); + + typeBuilder.DefineMethodOverride(methodOverride, getter); + } + + private static void ImplementSet(TypeBuilder typeBuilder, MethodInfo setter, FieldInfo fieldInterceptorField) + { + /* + if (this.__fieldInterceptor != null) + { + this.__fieldInterceptor.MarkDirty(); + this.__fieldInterceptor.Intercept(this, , value); + } + base.(value); + */ + var methodOverride = ProxyBuilderHelper.GenerateMethodSignature(setter.Name, setter, typeBuilder); + + var IL = methodOverride.GetILGenerator(); + + // if (this.__fieldInterceptor != null) + IL.Emit(OpCodes.Ldarg_0); + IL.Emit(OpCodes.Ldfld, fieldInterceptorField); + IL.Emit(OpCodes.Ldnull); + var skipInterceptor = IL.DefineLabel(); + IL.Emit(OpCodes.Beq, skipInterceptor); + + // this.__fieldInterceptor.MarkDirty(); + IL.Emit(OpCodes.Ldarg_0); + IL.Emit(OpCodes.Ldfld, fieldInterceptorField); + IL.Emit(OpCodes.Callvirt, FieldInterceptorMarkDirtyMethod); + + // this.__fieldInterceptor.Intercept(this, , propValue); + IL.Emit(OpCodes.Ldarg_0); + IL.Emit(OpCodes.Ldfld, fieldInterceptorField); + IL.Emit(OpCodes.Ldarg_0); + IL.Emit(OpCodes.Ldstr, ReflectHelper.GetPropertyName(setter)); + IL.Emit(OpCodes.Ldarg_1); + var propertyType = setter.GetParameters()[0].ParameterType; + if (propertyType.IsValueType) + IL.Emit(OpCodes.Box, propertyType); + IL.Emit(OpCodes.Callvirt, FieldInterceptorInterceptMethod); + IL.Emit(OpCodes.Pop); + + // end if (this.__fieldInterceptor != null) + IL.MarkLabel(skipInterceptor); + + // base.(value); + IL.Emit(OpCodes.Ldarg_0); + IL.Emit(OpCodes.Ldarg_1); + IL.Emit(OpCodes.Call, setter); + + IL.Emit(OpCodes.Ret); + + typeBuilder.DefineMethodOverride(methodOverride, setter); + } + } +} diff --git a/src/NHibernate/Proxy/NHibernateProxyBuilder.cs b/src/NHibernate/Proxy/NHibernateProxyBuilder.cs index 2d7615f65f9..daa15daafed 100644 --- a/src/NHibernate/Proxy/NHibernateProxyBuilder.cs +++ b/src/NHibernate/Proxy/NHibernateProxyBuilder.cs @@ -4,8 +4,6 @@ using System.Reflection; using System.Reflection.Emit; using System.Runtime.Serialization; -using System.Security; -using NHibernate.Proxy.DynamicProxy; using NHibernate.Type; using NHibernate.Util; @@ -16,25 +14,18 @@ internal class NHibernateProxyBuilder private const MethodAttributes constructorAttributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName; - private static readonly ConstructorInfo ObjectConstructor = typeof(object).GetConstructor(System.Type.EmptyTypes); - private static readonly System.Type NHibernateProxyType = typeof(INHibernateProxy); private static readonly PropertyInfo NHibernateProxyTypeLazyInitializerProperty = NHibernateProxyType.GetProperty(nameof(INHibernateProxy.HibernateLazyInitializer)); private static readonly System.Type LazyInitializerType = typeof(ILazyInitializer); private static readonly PropertyInfo LazyInitializerIdentifierProperty = LazyInitializerType.GetProperty(nameof(ILazyInitializer.Identifier)); private static readonly MethodInfo LazyInitializerInitializeMethod = LazyInitializerType.GetMethod(nameof(ILazyInitializer.Initialize)); private static readonly MethodInfo LazyInitializerGetImplementationMethod = LazyInitializerType.GetMethod(nameof(ILazyInitializer.GetImplementation), System.Type.EmptyTypes); - private static readonly IProxyAssemblyBuilder ProxyAssemblyBuilder = new DefaultProxyAssemblyBuilder(); - private static readonly ConstructorInfo SecurityCriticalAttributeConstructor = typeof(SecurityCriticalAttribute).GetConstructor(System.Type.EmptyTypes); - private static readonly MethodInfo SerializableGetObjectDataMethod = typeof(ISerializable).GetMethod(nameof(ISerializable.GetObjectData)); - private static readonly MethodInfo SerializationInfoSetTypeMethod = ReflectHelper.GetMethod(si => si.SetType(null)); - private readonly MethodInfo _getIdentifierMethod; private readonly MethodInfo _setIdentifierMethod; private readonly IAbstractComponentType _componentIdType; private readonly bool _overridesEquals; - + public NHibernateProxyBuilder(MethodInfo getIdentifierMethod, MethodInfo setIdentifierMethod, IAbstractComponentType componentIdType, bool overridesEquals) { _getIdentifierMethod = getIdentifierMethod; @@ -51,8 +42,8 @@ public TypeInfo CreateProxyType(System.Type baseType, IReadOnlyCollection()); - typeBuilder.SetCustomAttribute(customAttributeBuilder); - - ImplementDeserializationConstructor(typeBuilder); + ProxyBuilderHelper.MakeProxySerializable(typeBuilder); + ImplementDeserializationConstructor(typeBuilder, parentType); ImplementGetObjectData(typeBuilder, proxyInfoField, lazyInitializerField); var proxyType = typeBuilder.CreateTypeInfo(); - ProxyAssemblyBuilder.Save(assemblyBuilder); + ProxyBuilderHelper.Save(assemblyBuilder); return proxyType; } @@ -141,19 +127,11 @@ private static void ImplementConstructor(TypeBuilder typeBuilder, System.Type pa { var constructor = typeBuilder.DefineConstructor(constructorAttributes, CallingConventions.Standard, new[] {LazyInitializerType, typeof(NHibernateProxyFactoryInfo)}); - var baseConstructor = parentType.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, System.Type.EmptyTypes, null); - - // if there is no default constructor, or the default constructor is private/internal, call System.Object constructor - // this works, but the generated assembly will fail PeVerify (cannot use in medium trust for example) - if (baseConstructor == null || baseConstructor.IsPrivate || baseConstructor.IsAssembly) - baseConstructor = ObjectConstructor; - var IL = constructor.GetILGenerator(); constructor.SetImplementationFlags(MethodImplAttributes.IL | MethodImplAttributes.Managed); - IL.Emit(OpCodes.Ldarg_0); - IL.Emit(OpCodes.Call, baseConstructor); + ProxyBuilderHelper.CallDefaultBaseConstructor(IL, parentType); // __lazyInitializer == lazyInitializer; IL.Emit(OpCodes.Ldarg_0); @@ -168,36 +146,29 @@ private static void ImplementConstructor(TypeBuilder typeBuilder, System.Type pa IL.Emit(OpCodes.Ret); } - private static void ImplementDeserializationConstructor(TypeBuilder typeBuilder) + private static void ImplementDeserializationConstructor(TypeBuilder typeBuilder, System.Type parentType) { var parameterTypes = new[] {typeof (SerializationInfo), typeof (StreamingContext)}; var constructor = typeBuilder.DefineConstructor(constructorAttributes, CallingConventions.Standard, parameterTypes); constructor.SetImplementationFlags(MethodImplAttributes.IL | MethodImplAttributes.Managed); var IL = constructor.GetILGenerator(); + ProxyBuilderHelper.CallDefaultBaseConstructor(IL, parentType); //Everything is done in NHibernateProxyObjectReference, so just return data. IL.Emit(OpCodes.Ret); } private static void ImplementGetObjectData(TypeBuilder typeBuilder, FieldInfo proxyInfoField, FieldInfo lazyInitializerField) { - const MethodAttributes attributes = - MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual; - - var parameterTypes = new[] {typeof (SerializationInfo), typeof (StreamingContext)}; - - var methodBuilder = typeBuilder.DefineMethod("GetObjectData", attributes, typeof (void), parameterTypes); - methodBuilder.SetImplementationFlags(MethodImplAttributes.IL | MethodImplAttributes.Managed); - methodBuilder.SetCustomAttribute(new CustomAttributeBuilder(SecurityCriticalAttributeConstructor, Array.Empty())); + var methodBuilder = ProxyBuilderHelper.GetObjectDataMethodBuilder(typeBuilder); var IL = methodBuilder.GetILGenerator(); - //LocalBuilder proxyBaseType = IL.DeclareLocal(typeof(Type)); // info.SetType(typeof(NHibernateProxyObjectReference)); IL.Emit(OpCodes.Ldarg_1); IL.Emit(OpCodes.Ldtoken, typeof (NHibernateProxyObjectReference)); IL.Emit(OpCodes.Call, ReflectionCache.TypeMethods.GetTypeFromHandle); - IL.Emit(OpCodes.Callvirt, SerializationInfoSetTypeMethod); + IL.Emit(OpCodes.Callvirt, ProxyBuilderHelper.SerializationInfoSetTypeMethod); // (new NHibernateProxyObjectReference(this.__proxyInfo, this.__lazyInitializer.Identifier)).GetObjectData(info, context); //this.__proxyInfo @@ -219,11 +190,11 @@ private static void ImplementGetObjectData(TypeBuilder typeBuilder, FieldInfo pr IL.Emit(OpCodes.Ldarg_1); IL.Emit(OpCodes.Ldarg_2); - IL.Emit(OpCodes.Callvirt, SerializableGetObjectDataMethod); + IL.Emit(OpCodes.Callvirt, ProxyBuilderHelper.SerializableGetObjectDataMethod); IL.Emit(OpCodes.Ret); - typeBuilder.DefineMethodOverride(methodBuilder, SerializableGetObjectDataMethod); + typeBuilder.DefineMethodOverride(methodBuilder, ProxyBuilderHelper.SerializableGetObjectDataMethod); } private static void ImplementGetLazyInitializer(TypeBuilder typeBuilder, MethodInfo method, FieldInfo lazyInitializerField) @@ -256,7 +227,7 @@ private static void ImplementGetIdentifier(TypeBuilder typeBuilder, MethodInfo m return ()this.__lazyInitializer.Identifier; } */ - var methodOverride = DefaultyProxyMethodBuilder.GenerateMethodSignature(method.Name, method, typeBuilder); + var methodOverride = ProxyBuilderHelper.GenerateMethodSignature(method.Name, method, typeBuilder); var IL = methodOverride.GetILGenerator(); @@ -284,7 +255,7 @@ private static void ImplementSetIdentifier(TypeBuilder typeBuilder, MethodInfo m } */ var propertyType = method.GetParameters()[0].ParameterType; - var methodOverride = DefaultyProxyMethodBuilder.GenerateMethodSignature(method.Name, method, typeBuilder); + var methodOverride = ProxyBuilderHelper.GenerateMethodSignature(method.Name, method, typeBuilder); var IL = methodOverride.GetILGenerator(); EmitCallBaseIfLazyInitializerIsNull(IL, method, lazyInitializerField); @@ -314,7 +285,7 @@ private static void ImplementCallMethodOnEmbeddedComponentId(TypeBuilder typeBui return base.(args..); this.__lazyInitializer.Identifier.(args..); */ - var methodOverride = DefaultyProxyMethodBuilder.GenerateMethodSignature(method.Name, method, typeBuilder); + var methodOverride = ProxyBuilderHelper.GenerateMethodSignature(method.Name, method, typeBuilder); var IL = methodOverride.GetILGenerator(); @@ -337,7 +308,7 @@ private static void ImplementCallMethodOnImplementation(TypeBuilder typeBuilder, return base.(args..); return this.__lazyInitializer.GetImplementation().(args..) */ - var methodOverride = DefaultyProxyMethodBuilder.GenerateMethodSignature(method.Name, method, typeBuilder); + var methodOverride = ProxyBuilderHelper.GenerateMethodSignature(method.Name, method, typeBuilder); var IL = methodOverride.GetILGenerator(); diff --git a/src/NHibernate/Proxy/ProxyBuilderHelper.cs b/src/NHibernate/Proxy/ProxyBuilderHelper.cs new file mode 100644 index 00000000000..7c69280d27b --- /dev/null +++ b/src/NHibernate/Proxy/ProxyBuilderHelper.cs @@ -0,0 +1,237 @@ +#region Credits + +// Part of this work is based on LinFu.DynamicProxy framework (c) Philip Laureano who has donated it to NHibernate project. +// The license is the same of NHibernate license (LGPL Version 2.1, February 1999). + +#endregion + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Reflection.Emit; +using System.Runtime.Serialization; +using System.Security; +using NHibernate.Util; + +namespace NHibernate.Proxy +{ + internal static class ProxyBuilderHelper + { + private static readonly ConstructorInfo ObjectConstructor = typeof(object).GetConstructor(System.Type.EmptyTypes); + private static readonly ConstructorInfo SecurityCriticalAttributeConstructor = typeof(SecurityCriticalAttribute).GetConstructor(System.Type.EmptyTypes); + + internal static readonly MethodInfo SerializableGetObjectDataMethod = typeof(ISerializable).GetMethod(nameof(ISerializable.GetObjectData)); + internal static readonly MethodInfo SerializationInfoSetTypeMethod = ReflectHelper.GetMethod(si => si.SetType(null)); + +#if NETFX + private static bool _saveAssembly; + private static string _saveAssemblyPath; + + // Called by reflection + internal static void EnableDynamicAssemblySaving(bool enable, string saveAssemblyPath) + { + _saveAssembly = enable; + _saveAssemblyPath = saveAssemblyPath; + } +#endif + + internal static AssemblyBuilder DefineDynamicAssembly(AppDomain appDomain, AssemblyName name) + { +#if NETFX + var access = _saveAssembly ? AssemblyBuilderAccess.RunAndSave : AssemblyBuilderAccess.Run; + var assemblyBuilder = _saveAssembly && !string.IsNullOrEmpty(_saveAssemblyPath) + ? appDomain.DefineDynamicAssembly(name, access, Path.GetDirectoryName(_saveAssemblyPath)) + : AssemblyBuilder.DefineDynamicAssembly(name, access); +#else + var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run); +#endif + return assemblyBuilder; + } + + internal static ModuleBuilder DefineDynamicModule(AssemblyBuilder assemblyBuilder, string moduleName) + { +#if NETFX + var moduleBuilder = _saveAssembly + ? assemblyBuilder.DefineDynamicModule(moduleName, $"{moduleName}.mod", true) + : assemblyBuilder.DefineDynamicModule(moduleName); +#else + var moduleBuilder = assemblyBuilder.DefineDynamicModule(moduleName); +#endif + return moduleBuilder; + } + + internal static void Save(AssemblyBuilder assemblyBuilder) + { +#if NETFX + if (_saveAssembly) + assemblyBuilder.Save( + string.IsNullOrEmpty(_saveAssemblyPath) + ? "generatedAssembly.dll" + : Path.GetFileName(_saveAssemblyPath)); +#endif + } + + internal static void CallDefaultBaseConstructor(ILGenerator il, System.Type parentType) + { + var baseConstructor = parentType.GetConstructor( + BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, + null, + System.Type.EmptyTypes, + null); + // if there is no default constructor, or the default constructor is private/internal, call System.Object constructor + // this works, but the generated assembly will fail PeVerify (cannot use in medium trust for example) + if (baseConstructor == null || baseConstructor.IsPrivate || baseConstructor.IsAssembly) + baseConstructor = ObjectConstructor; + + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Call, baseConstructor); + } + + internal static IEnumerable GetProxiableMethods(System.Type type, IEnumerable interfaces) + { + const BindingFlags candidateMethodsBindingFlags = + BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; + return + type.GetMethods(candidateMethodsBindingFlags) + .Where(method => method.IsProxiable()) + .Concat(interfaces.SelectMany(interfaceType => interfaceType.GetMethods())) + .Distinct(); + } + + internal static void MakeProxySerializable(TypeBuilder typeBuilder) + { + var serializableConstructor = typeof(SerializableAttribute).GetConstructor(System.Type.EmptyTypes); + var customAttributeBuilder = new CustomAttributeBuilder(serializableConstructor, Array.Empty()); + typeBuilder.SetCustomAttribute(customAttributeBuilder); + } + + internal static MethodBuilder GetObjectDataMethodBuilder(TypeBuilder typeBuilder) + { + const MethodAttributes attributes = + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual; + + var parameterTypes = new[] { typeof(SerializationInfo), typeof(StreamingContext) }; + + var methodBuilder = typeBuilder.DefineMethod( + nameof(ISerializable.GetObjectData), + attributes, + typeof(void), + parameterTypes); + methodBuilder.SetImplementationFlags(MethodImplAttributes.IL | MethodImplAttributes.Managed); + methodBuilder.SetCustomAttribute( + new CustomAttributeBuilder(SecurityCriticalAttributeConstructor, Array.Empty())); + return methodBuilder; + } + + internal static MethodBuilder GenerateMethodSignature(string name, MethodInfo method, TypeBuilder typeBuilder) + { + //TODO: Should we use attributes of base method? + var methodAttributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual; + + if (method.IsSpecialName) + methodAttributes |= MethodAttributes.SpecialName; + + var parameters = method.GetParameters(); + + var methodBuilder = typeBuilder.DefineMethod( + name, + methodAttributes, + CallingConventions.HasThis, + method.ReturnType, + parameters.Select(param => param.ParameterType).ToArray()); + + var typeArgs = method.GetGenericArguments(); + + if (typeArgs.Length > 0) + { + var typeNames = GenerateTypeNames(typeArgs.Length); + var typeArgBuilders = methodBuilder.DefineGenericParameters(typeNames); + + for (var index = 0; index < typeArgs.Length; index++) + { + // Copy generic parameter attributes (Covariant, Contravariant, ReferenceTypeConstraint, + // NotNullableValueTypeConstraint, DefaultConstructorConstraint). + var typeArgBuilder = typeArgBuilders[index]; + var typeArg = typeArgs[index]; + + typeArgBuilder.SetGenericParameterAttributes(typeArg.GenericParameterAttributes); + + // Copy generic parameter constraints (class and interfaces). + var typeConstraints = typeArg.GetGenericParameterConstraints() + .Select(x => ResolveTypeConstraint(method, x)) + .ToArray(); + + var baseTypeConstraint = typeConstraints.SingleOrDefault(x => x.IsClass); + typeArgBuilder.SetBaseTypeConstraint(baseTypeConstraint); + + var interfaceTypeConstraints = typeConstraints.Where(x => !x.IsClass).ToArray(); + typeArgBuilder.SetInterfaceConstraints(interfaceTypeConstraints); + } + } + + return methodBuilder; + } + + private static System.Type ResolveTypeConstraint(MethodInfo method, System.Type typeConstraint) + { + if (typeConstraint != null && typeConstraint.IsGenericType) + { + var declaringType = method.DeclaringType; + if (declaringType != null && declaringType.IsGenericType) + { + return BuildTypeConstraint(typeConstraint, declaringType); + } + } + + return typeConstraint; + } + + private static System.Type BuildTypeConstraint(System.Type typeConstraint, System.Type declaringType) + { + var constraintGenericArguments = typeConstraint.GetGenericArguments(); + var declaringTypeGenericArguments = declaringType.GetGenericArguments(); + + var parametersMap = declaringType + .GetGenericTypeDefinition() + .GetGenericArguments() + .ToDictionary(x => x, x => declaringTypeGenericArguments[x.GenericParameterPosition]); + + var args = new System.Type[constraintGenericArguments.Length]; + var make = false; + for (var index = 0; index < constraintGenericArguments.Length; index++) + { + var genericArgument = constraintGenericArguments[index]; + if (parametersMap.TryGetValue(genericArgument, out var result)) + { + make = true; + } + else + { + result = genericArgument; + } + + args[index] = result; + } + + if (make) + { + return typeConstraint.GetGenericTypeDefinition().MakeGenericType(args); + } + + return typeConstraint; + } + + private static string[] GenerateTypeNames(int count) + { + var result = new string[count]; + for (var index = 0; index < count; index++) + { + result[index] = $"T{index}"; + } + + return result; + } + } +} diff --git a/src/NHibernate/Proxy/DynamicProxy/ProxyCacheEntry.cs b/src/NHibernate/Proxy/ProxyCacheEntry.cs similarity index 86% rename from src/NHibernate/Proxy/DynamicProxy/ProxyCacheEntry.cs rename to src/NHibernate/Proxy/ProxyCacheEntry.cs index e8118925729..fd081139f3b 100644 --- a/src/NHibernate/Proxy/DynamicProxy/ProxyCacheEntry.cs +++ b/src/NHibernate/Proxy/ProxyCacheEntry.cs @@ -10,7 +10,7 @@ using System.Collections.Generic; using System.Linq; -namespace NHibernate.Proxy.DynamicProxy +namespace NHibernate.Proxy { public class ProxyCacheEntry : IEquatable { @@ -26,6 +26,7 @@ public ProxyCacheEntry(System.Type baseType, System.Type[] interfaces) { uniqueInterfaces.UnionWith(interfaces.Where(i => i != null)); } + _uniqueInterfaces = uniqueInterfaces; _hashCode = 59 ^ baseType.GetHashCode(); @@ -66,3 +67,15 @@ public bool Equals(ProxyCacheEntry other) public override int GetHashCode() => _hashCode; } } + +namespace NHibernate.Proxy.DynamicProxy +{ + // Since v5.2 + [Obsolete("Use NHibernate.Proxy.ProxyCacheEntry instead")] + public class ProxyCacheEntry : NHibernate.Proxy.ProxyCacheEntry + { + public ProxyCacheEntry(System.Type baseType, System.Type[] interfaces) : base(baseType, interfaces) + { + } + } +} diff --git a/src/NHibernate/Proxy/StaticProxyFactory.cs b/src/NHibernate/Proxy/StaticProxyFactory.cs index d053a93abd2..a6f620219a7 100644 --- a/src/NHibernate/Proxy/StaticProxyFactory.cs +++ b/src/NHibernate/Proxy/StaticProxyFactory.cs @@ -3,7 +3,6 @@ using System.Linq.Expressions; using NHibernate.Engine; using NHibernate.Intercept; -using NHibernate.Proxy.DynamicProxy; namespace NHibernate.Proxy { @@ -11,6 +10,8 @@ public sealed class StaticProxyFactory : AbstractProxyFactory { private static readonly ConcurrentDictionary> Cache = new ConcurrentDictionary>(); + private static readonly ConcurrentDictionary> + FieldInterceptorCache = new ConcurrentDictionary>(); private static readonly INHibernateLogger Log = NHibernateLogger.For(typeof(StaticProxyFactory)); @@ -43,9 +44,18 @@ private Func Cre public override object GetFieldInterceptionProxy(object instanceToWrap) { - var factory = new ProxyFactory(); - var interceptor = new DefaultDynamicLazyFieldInterceptor(); - return factory.CreateProxy(PersistentClass, interceptor, typeof(IFieldInterceptorAccessor)); + var cacheEntry = new ProxyCacheEntry(PersistentClass, System.Type.EmptyTypes); + var proxyActivator = FieldInterceptorCache.GetOrAdd(cacheEntry, CreateFieldInterceptionProxyActivator); + return proxyActivator( + new NHibernateProxyFactoryInfo(EntityName, PersistentClass, Interfaces, GetIdentifierMethod, SetIdentifierMethod, ComponentIdType)); + } + + private Func CreateFieldInterceptionProxyActivator(ProxyCacheEntry pke) + { + var type = FieldInterceptorProxyBuilder.CreateProxyType(pke.BaseType); + var ctor = type.GetConstructor(new[] { typeof(NHibernateProxyFactoryInfo) }); + var pf = Expression.Parameter(typeof(NHibernateProxyFactoryInfo)); + return Expression.Lambda>(Expression.New(ctor, pf), pf).Compile(); } } }