mirror of
https://github.com/esiur/esiur-dotnet.git
synced 2025-05-06 11:32:59 +00:00
Resource Proxy
This commit is contained in:
parent
2d9f61c0d9
commit
a2f4238933
@ -11,7 +11,7 @@
|
||||
<PackageProjectUrl>http://www.esiur.com</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/esiur/esiur-dotnet/</RepositoryUrl>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
<Version>1.2.0</Version>
|
||||
<Version>1.2.2</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -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<IResource>(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);
|
||||
|
@ -7,10 +7,10 @@
|
||||
<PackageLicenseUrl>https://github.com/esiur/esiur-dotnet/blob/master/LICENSE</PackageLicenseUrl>
|
||||
<PackageProjectUrl>http://www.esiur.com</PackageProjectUrl>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<Version>1.2.3</Version>
|
||||
<Version>1.2.5</Version>
|
||||
<RepositoryUrl>https://github.com/esiur/esiur-dotnet</RepositoryUrl>
|
||||
<Authors>Ahmed Kh. Zamil</Authors>
|
||||
<AssemblyVersion>1.2.3.0</AssemblyVersion>
|
||||
<AssemblyVersion>1.2.5.0</AssemblyVersion>
|
||||
<Company>Esiur Foundation</Company>
|
||||
</PropertyGroup>
|
||||
|
||||
@ -44,6 +44,7 @@
|
||||
<PackageReference Include="System.Net.NameResolution" Version="4.3.0" />
|
||||
<PackageReference Include="System.Net.NetworkInformation" Version="4.3.0" />
|
||||
<PackageReference Include="System.Net.Security" Version="4.3.1" />
|
||||
<PackageReference Include="System.Reflection.Emit" Version="4.3.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -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)
|
||||
{
|
||||
|
||||
|
151
Esiur/Proxy/ResourceProxy.cs
Normal file
151
Esiur/Proxy/ResourceProxy.cs
Normal file
@ -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<Type, Type> cache = new Dictionary<Type, Type>();
|
||||
|
||||
#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<T>()
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -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
|
||||
/// <param name="propertyName"></param>
|
||||
/// <param name="newValue"></param>
|
||||
/// <param name="oldValue"></param>
|
||||
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
|
||||
/// <returns>True, if the resource has the property.</returns>
|
||||
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<IManager, object>)(sender);
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
|
||||
value = pt.Info.GetValue(resource, null);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
value = null;
|
||||
|
@ -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 {
|
||||
|
@ -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,6 +160,7 @@ 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);
|
||||
pt.Info = pi;
|
||||
properties.Add(pt);
|
||||
}
|
||||
}
|
||||
|
@ -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<T>(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<T>();
|
||||
var res = Activator.CreateInstance(type) as IResource;
|
||||
Put(res, name, store, parent, null, 0, manager);
|
||||
return (T)res;
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ using System.Text;
|
||||
|
||||
namespace Test
|
||||
{
|
||||
class MyMembership : IMembership
|
||||
public class MyMembership : IMembership
|
||||
{
|
||||
public Instance Instance { get; set; }
|
||||
|
||||
|
@ -9,7 +9,7 @@ using System.Threading;
|
||||
|
||||
namespace Test
|
||||
{
|
||||
class MyObject : Resource
|
||||
public class MyObject : Resource
|
||||
{
|
||||
|
||||
[ResourceEvent]
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -44,9 +44,10 @@ namespace Test
|
||||
|
||||
|
||||
|
||||
|
||||
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.<MyObject>();
|
||||
//Warehouse.Put(obj, "dd", system);
|
||||
//obj.Level2= 33;
|
||||
|
||||
// Create new distributed server object
|
||||
var iip = Warehouse.New<DistributedServer>("iip", system);
|
||||
// Set membership which handles authentication.
|
||||
@ -136,8 +142,11 @@ namespace Test
|
||||
running = false;
|
||||
});
|
||||
else
|
||||
{
|
||||
myObject.Level = 88;
|
||||
Console.WriteLine(myObject.Name + " " + myObject.Level );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user