diff --git a/Esiur.Stores.MongoDB/Esiur.Stores.MongoDB.csproj b/Esiur.Stores.MongoDB/Esiur.Stores.MongoDB.csproj
index 8aa98d7..72a67d6 100644
--- a/Esiur.Stores.MongoDB/Esiur.Stores.MongoDB.csproj
+++ b/Esiur.Stores.MongoDB/Esiur.Stores.MongoDB.csproj
@@ -11,7 +11,7 @@
http://www.esiur.com
https://github.com/esiur/esiur-dotnet/
True
- 1.2.0
+ 1.2.2
diff --git a/Esiur.Stores.MongoDB/MongoDBStore.cs b/Esiur.Stores.MongoDB/MongoDBStore.cs
index 40dce94..18fa2ea 100644
--- a/Esiur.Stores.MongoDB/MongoDBStore.cs
+++ b/Esiur.Stores.MongoDB/MongoDBStore.cs
@@ -11,6 +11,7 @@ using System.Threading.Tasks;
using Esiur.Resource.Template;
using System.Linq;
using Esiur.Security.Permissions;
+using Esiur.Proxy;
namespace Esiur.Stores.MongoDB
{
@@ -100,8 +101,9 @@ namespace Esiur.Stores.MongoDB
return new AsyncReply(null);
var document = list[0];
+ var type = Type.GetType(document["classname"].AsString);
- IResource resource = (IResource)Activator.CreateInstance(Type.GetType(document["classname"].AsString));
+ IResource resource = (IResource)Activator.CreateInstance(ResourceProxy.GetProxy(type));
resources.Add(document["_id"].AsObjectId.ToString(), resource);
Warehouse.Put(resource, document["name"].AsString, this);
diff --git a/Esiur/Esiur.csproj b/Esiur/Esiur.csproj
index 356bf69..489fd08 100644
--- a/Esiur/Esiur.csproj
+++ b/Esiur/Esiur.csproj
@@ -7,10 +7,10 @@
https://github.com/esiur/esiur-dotnet/blob/master/LICENSE
http://www.esiur.com
true
- 1.2.3
+ 1.2.5
https://github.com/esiur/esiur-dotnet
Ahmed Kh. Zamil
- 1.2.3.0
+ 1.2.5.0
Esiur Foundation
@@ -44,6 +44,7 @@
+
\ No newline at end of file
diff --git a/Esiur/Net/IIP/DistributedConnectionProtocol.cs b/Esiur/Net/IIP/DistributedConnectionProtocol.cs
index 31e74c4..43861c5 100644
--- a/Esiur/Net/IIP/DistributedConnectionProtocol.cs
+++ b/Esiur/Net/IIP/DistributedConnectionProtocol.cs
@@ -1369,11 +1369,16 @@ namespace Esiur.Net.IIP
}
else
{
+
+ /*
#if NETSTANDARD1_5
var pi = r.GetType().GetTypeInfo().GetProperty(pt.Name);
#else
var pi = r.GetType().GetProperty(pt.Name);
-#endif
+#endif*/
+
+ var pi = pt.Info;
+
if (pi != null)
{
diff --git a/Esiur/Proxy/ResourceProxy.cs b/Esiur/Proxy/ResourceProxy.cs
new file mode 100644
index 0000000..9549f8f
--- /dev/null
+++ b/Esiur/Proxy/ResourceProxy.cs
@@ -0,0 +1,151 @@
+using Esiur.Resource;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Text;
+
+namespace Esiur.Proxy
+{
+ public static class ResourceProxy
+ {
+ static Dictionary cache = new Dictionary();
+
+#if NETSTANDARD1_5
+ static MethodInfo modifyMethod = typeof(Instance).GetTypeInfo().GetMethod("Modified");
+ static MethodInfo instanceGet = typeof(IResource).GetTypeInfo().GetProperty("Instance").GetGetMethod();
+#else
+ static MethodInfo modifyMethod = typeof(Instance).GetMethod("Modified");
+ static MethodInfo instanceGet = typeof(IResource).GetProperty("Instance").GetGetMethod();
+#endif
+
+
+ public static Type GetProxy(Type type)
+ {
+
+ if (cache.ContainsKey(type))
+ return cache[type];
+
+#if NETSTANDARD1_5
+ var typeInfo = type.GetTypeInfo();
+
+ if (typeInfo.IsSealed)
+ throw new Exception("Sealed class can't be proxied.");
+
+ var props = from p in typeInfo.GetProperties()
+ where p.CanWrite && p.GetSetMethod().IsVirtual &&
+ p.GetCustomAttributes(typeof(ResourceProperty), false).Count() > 0
+ select p;
+
+#else
+ if (type.IsSealed)
+ throw new Exception("Sealed class can't be proxied.");
+
+ var props = from p in type.GetProperties()
+ where p.CanWrite && p.GetSetMethod().IsVirtual &&
+ p.GetCustomAttributes(typeof(ResourceProperty), false).Count() > 0
+ select p;
+
+#endif
+ var assemblyName = new AssemblyName("Esiur.Proxy.T." + type.Namespace);
+ var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
+ var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name);
+ var typeName = Assembly.CreateQualifiedName(assemblyName.FullName, type.Name);
+
+ var typeBuilder = moduleBuilder.DefineType(typeName,
+ TypeAttributes.Public | TypeAttributes.Class, type);
+
+ foreach (PropertyInfo propertyInfo in props)
+ CreateProperty(propertyInfo, typeBuilder);
+
+
+
+#if NETSTANDARD1_5
+ var t = typeBuilder.CreateTypeInfo().AsType();
+ cache.Add(type, t);
+ return t;
+#else
+
+ var t = typeBuilder.CreateType();
+ cache.Add(type, t);
+ return t;
+#endif
+ }
+
+ public static Type GetProxy()
+ where T : IResource
+ {
+ return GetProxy(typeof(T));
+ }
+
+
+
+ private static void CreateProperty(PropertyInfo pi, TypeBuilder typeBuilder)
+ {
+ var propertyBuilder = typeBuilder.DefineProperty(pi.Name, PropertyAttributes.None, pi.PropertyType, null);
+
+ // Create set method
+ MethodBuilder builder = typeBuilder.DefineMethod("set_" + pi.Name,
+ MethodAttributes.Public | MethodAttributes.Virtual, null, new Type[] { pi.PropertyType });
+ builder.DefineParameter(1, ParameterAttributes.None, "value");
+ ILGenerator g = builder.GetILGenerator();
+
+ Label callModified = g.DefineLabel();
+ Label exitMethod = g.DefineLabel();
+
+ /*
+ IL_0000: ldarg.0
+ IL_0001: call instance class [Esiur]Esiur.Resource.Instance [Esiur]Esiur.Resource.Resource::get_Instance()
+ // (no C# code)
+ IL_0006: dup
+ IL_0007: brtrue.s IL_000c
+
+ IL_0009: pop
+ // }
+ IL_000a: br.s IL_0017
+
+ // (no C# code)
+ IL_000c: ldstr "Level3"
+ IL_0011: call instance void [Esiur]Esiur.Resource.Instance::Modified(string)
+ IL_0016: nop
+
+ IL_0017: ret
+
+ */
+
+ // Add IL code for set method
+ g.Emit(OpCodes.Nop);
+ g.Emit(OpCodes.Ldarg_0);
+ g.Emit(OpCodes.Ldarg_1);
+ g.Emit(OpCodes.Call, pi.GetSetMethod());
+
+ /*
+ IL_0000: ldarg.0
+ IL_0001: call instance class [Esiur]Esiur.Resource.Instance [Esiur]Esiur.Resource.Resource::get_Instance()
+ IL_0006: ldstr "Level3"
+ IL_000b: callvirt instance void [Esiur]Esiur.Resource.Instance::Modified(string)
+ IL_0010: ret
+ */
+
+ // Call property changed for object
+ g.Emit(OpCodes.Nop);
+ g.Emit(OpCodes.Ldarg_0);
+ g.Emit(OpCodes.Call, instanceGet);
+
+ g.Emit(OpCodes.Dup);
+ g.Emit(OpCodes.Brtrue_S, callModified);
+ g.Emit(OpCodes.Pop);
+ g.Emit(OpCodes.Br_S, exitMethod);
+
+ g.MarkLabel(callModified);
+ g.Emit(OpCodes.Ldstr, pi.Name);
+ g.Emit(OpCodes.Callvirt, modifyMethod);
+ g.Emit(OpCodes.Nop);
+ g.MarkLabel(exitMethod);
+ g.Emit(OpCodes.Ret);
+ propertyBuilder.SetSetMethod(builder);
+ }
+
+ }
+}
diff --git a/Esiur/Resource/Instance.cs b/Esiur/Resource/Instance.cs
index c8ef27d..473e7fe 100644
--- a/Esiur/Resource/Instance.cs
+++ b/Esiur/Resource/Instance.cs
@@ -270,19 +270,22 @@ namespace Esiur.Resource
if (pt == null)
return false;
+ /*
#if NETSTANDARD1_5
- var pi = resource.GetType().GetTypeInfo().GetProperty(name);
+ var pi = resource.GetType().GetTypeInfo().GetProperty(name, new[] { resource.GetType() });
#else
var pi = resource.GetType().GetProperty(pt.Name);
#endif
- if (pi.PropertyType == typeof(DistributedPropertyContext))
+*/
+
+ if (pt.Info.PropertyType == typeof(DistributedPropertyContext))
return false;
try
{
- if (pi.CanWrite)
- pi.SetValue(resource, DC.CastConvert(value, pi.PropertyType));
+ if (pt.Info.CanWrite)
+ pt.Info.SetValue(resource, DC.CastConvert(value, pt.Info.PropertyType));
}
catch(Exception ex)
{
@@ -354,12 +357,16 @@ namespace Esiur.Resource
foreach (var pt in template.Properties)
{
+ /*
#if NETSTANDARD1_5
var pi = resource.GetType().GetTypeInfo().GetProperty(pt.Name);
#else
var pi = resource.GetType().GetProperty(pt.Name);
#endif
- var rt = pi.GetValue(resource, null);
+*/
+
+
+ var rt = pt.Info.GetValue(resource, null);
props.Add(new PropertyValue(rt, ages[pt.Index], modificationDates[pt.Index]));
}
@@ -474,7 +481,7 @@ namespace Esiur.Resource
///
///
///
- public void Modified([CallerMemberName] string propertyName = "")//, object newValue = null)//, object oldValue = null)
+ public void Modified([CallerMemberName] string propertyName = "")
{
object value;
if (GetPropertyValue(propertyName, out value))
@@ -499,16 +506,20 @@ namespace Esiur.Resource
/// True, if the resource has the property.
public bool GetPropertyValue(string name, out object value)
{
+ /*
#if NETSTANDARD1_5
PropertyInfo pi = resource.GetType().GetTypeInfo().GetProperty(name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
#else
PropertyInfo pi = resource.GetType().GetProperty(name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
#endif
+*/
- if (pi != null)
+ var pt = template.GetPropertyTemplate(name);
+
+ if (pt != null && pt.Info != null)
{
-
+ /*
#if NETSTANDARD1_5
object[] ca = pi.GetCustomAttributes(typeof(ResourceProperty), false).ToArray();
@@ -523,6 +534,11 @@ namespace Esiur.Resource
// value = (value as Func)(sender);
return true;
}
+ */
+
+ value = pt.Info.GetValue(resource, null);
+ return true;
+
}
value = null;
diff --git a/Esiur/Resource/Template/PropertyTemplate.cs b/Esiur/Resource/Template/PropertyTemplate.cs
index 9f6fade..ed77f92 100644
--- a/Esiur/Resource/Template/PropertyTemplate.cs
+++ b/Esiur/Resource/Template/PropertyTemplate.cs
@@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Reflection;
using System.Text;
using System.Threading.Tasks;
@@ -17,6 +18,12 @@ namespace Esiur.Resource.Template
}
+ public PropertyInfo Info
+ {
+ get;
+ set;
+ }
+
//bool ReadOnly;
//IIPTypes::DataType ReturnType;
public PropertyPermission Permission {
diff --git a/Esiur/Resource/Template/ResourceTemplate.cs b/Esiur/Resource/Template/ResourceTemplate.cs
index fa54fa0..06fcc6d 100644
--- a/Esiur/Resource/Template/ResourceTemplate.cs
+++ b/Esiur/Resource/Template/ResourceTemplate.cs
@@ -126,6 +126,10 @@ namespace Esiur.Resource.Template
public ResourceTemplate(Type type)
{
+
+ if (type.Namespace.Contains("Esiur.Proxy.T"))
+ type = type.GetTypeInfo().BaseType;
+
// set guid
var typeName = Encoding.UTF8.GetBytes(type.FullName);
@@ -156,7 +160,8 @@ namespace Esiur.Resource.Template
if (ps.Length > 0)
{
var pt = new PropertyTemplate(this, i++, pi.Name, ps[0].ReadExpansion, ps[0].WriteExpansion, ps[0].Storage);
- properties.Add(pt);
+ pt.Info = pi;
+ properties.Add(pt);
}
}
diff --git a/Esiur/Resource/Warehouse.cs b/Esiur/Resource/Warehouse.cs
index 54f4d27..a95bb42 100644
--- a/Esiur/Resource/Warehouse.cs
+++ b/Esiur/Resource/Warehouse.cs
@@ -24,6 +24,7 @@ SOFTWARE.
using Esiur.Data;
using Esiur.Engine;
+using Esiur.Proxy;
using Esiur.Resource.Template;
using Esiur.Security.Permissions;
using System;
@@ -347,8 +348,10 @@ namespace Esiur.Resource
}
public static T New(string name, IStore store = null, IResource parent = null, IPermissionsManager manager = null)
+ where T:IResource
{
- var res = Activator.CreateInstance(typeof(T)) as IResource;
+ var type = ResourceProxy.GetProxy();
+ var res = Activator.CreateInstance(type) as IResource;
Put(res, name, store, parent, null, 0, manager);
return (T)res;
}
diff --git a/Test/MyMembership.cs b/Test/MyMembership.cs
index 5034f95..0a72bd5 100644
--- a/Test/MyMembership.cs
+++ b/Test/MyMembership.cs
@@ -9,7 +9,7 @@ using System.Text;
namespace Test
{
- class MyMembership : IMembership
+ public class MyMembership : IMembership
{
public Instance Instance { get; set; }
diff --git a/Test/MyObject.cs b/Test/MyObject.cs
index 87d39b5..0869562 100644
--- a/Test/MyObject.cs
+++ b/Test/MyObject.cs
@@ -9,14 +9,14 @@ using System.Threading;
namespace Test
{
- class MyObject : Resource
+ public class MyObject : Resource
{
-
+
[ResourceEvent]
public event ResourceEventHanlder LevelUp;
[ResourceEvent]
public event ResourceEventHanlder LevelDown;
-
+
public MyObject()
{
Info = new Structure();
@@ -27,7 +27,7 @@ namespace Test
Level = 5;
}
-
+
[ResourceFunction]
public int Add(int value)
{
@@ -113,6 +113,7 @@ namespace Test
}
}
+ /*
int level;
[ResourceProperty]
public int Level
@@ -124,6 +125,21 @@ namespace Test
Instance?.Modified();
}
}
+ */
+
+ [ResourceProperty]
+ public virtual int Level
+ {
+ get;
+ set;
+ }
+
+ [ResourceProperty]
+ public int Level3
+ {
+ get => 0;
+ set => Instance?.Modified();
+ }
}
diff --git a/Test/Program.cs b/Test/Program.cs
index b467762..b5d70c7 100644
--- a/Test/Program.cs
+++ b/Test/Program.cs
@@ -41,12 +41,13 @@ namespace Test
{
static MyObject myObject;
static DistributedResource remoteObject;
-
-
+
static async Task Main(string[] args)
{
+
+
//AsyncContext.Run(() => ());
// Create stores to keep objects.
@@ -85,6 +86,11 @@ namespace Test
else
myObject =(MyObject) (await Warehouse.Get("db/my"));//.Then((o) => { myObject = (MyObject)o; });
+
+ //var obj = ProxyObject.();
+ //Warehouse.Put(obj, "dd", system);
+ //obj.Level2= 33;
+
// Create new distributed server object
var iip = Warehouse.New("iip", system);
// Set membership which handles authentication.
@@ -136,7 +142,10 @@ namespace Test
running = false;
});
else
- Console.WriteLine(myObject.Name + " " + myObject.Level);
+ {
+ myObject.Level = 88;
+ Console.WriteLine(myObject.Name + " " + myObject.Level );
+ }
}