diff --git a/Esiur.Stores.EntityCore/Esiur.Stores.EntityCore.csproj b/Esiur.Stores.EntityCore/Esiur.Stores.EntityCore.csproj index 1567d44..f799cc0 100644 --- a/Esiur.Stores.EntityCore/Esiur.Stores.EntityCore.csproj +++ b/Esiur.Stores.EntityCore/Esiur.Stores.EntityCore.csproj @@ -9,7 +9,7 @@ Esiur Entity Framework Extension true Esiur.Stores.EntityCore - 1.2.1 + 1.2.3 diff --git a/Esiur.Stores.MongoDB/Esiur.Stores.MongoDB.csproj b/Esiur.Stores.MongoDB/Esiur.Stores.MongoDB.csproj index ebe3330..eaa469a 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.5.0 + 1.5.2 Esiur.Stores.MongoDB diff --git a/Esiur.Stores.MongoDB/MongoDBStore.cs b/Esiur.Stores.MongoDB/MongoDBStore.cs index 733bd43..c796963 100644 --- a/Esiur.Stores.MongoDB/MongoDBStore.cs +++ b/Esiur.Stores.MongoDB/MongoDBStore.cs @@ -52,10 +52,10 @@ namespace Esiur.Stores.MongoDB [Public] - public event ResourceEventHanlder ResourceAdded; + public event ResourceEventHandler ResourceAdded; [Public] - public event ResourceEventHanlder ResourceRemoved; + public event ResourceEventHandler ResourceRemoved; int count = 0; diff --git a/Esiur/Core/AsyncBag.cs b/Esiur/Core/AsyncBag.cs index 1f98322..008528e 100644 --- a/Esiur/Core/AsyncBag.cs +++ b/Esiur/Core/AsyncBag.cs @@ -39,7 +39,9 @@ namespace Esiur.Core int count = 0; bool sealedBag = false; - + + public Type ArrayType { get; set; } + public AsyncBag Then(Action callback) { base.Then(new Action(o => callback((object[])o))); @@ -82,7 +84,17 @@ namespace Esiur.Core results[index] = r; count++; if (count == results.Count) - Trigger(results.ToArray()); + { + if (ArrayType != null) + { + var ar = Array.CreateInstance(ArrayType, count); + for (var i = 0; i < count; i++) + ar.SetValue(results[i], i); + Trigger(ar); + } + else + Trigger(results.ToArray()); + } }); } } diff --git a/Esiur/Data/Codec.cs b/Esiur/Data/Codec.cs index a91419d..c2c9182 100644 --- a/Esiur/Data/Codec.cs +++ b/Esiur/Data/Codec.cs @@ -255,10 +255,10 @@ namespace Esiur.Data } - public static AsyncBag ParseRecordArray(byte[] data, uint offset, uint length, DistributedConnection connection) + public static AsyncBag ParseRecordArray(byte[] data, uint offset, uint length, DistributedConnection connection) { + var reply = new AsyncBag(); - var reply = new AsyncBag(); if (length == 0) { reply.Seal(); @@ -267,30 +267,61 @@ namespace Esiur.Data var end = offset + length; - var result = (RecordComparisonResult)data[offset++]; + var isTyped = (data[offset] & 0x10) == 0x10; - AsyncReply previous = null; - Guid? classId = null; + var result = (RecordComparisonResult)(data[offset++] & 0xF); - if (result == RecordComparisonResult.Null) - previous = new AsyncReply(null); - else if (result == RecordComparisonResult.Record) + if (isTyped) { - uint cs = data.GetUInt32(offset); - uint recordLength = cs - 16; - offset += 4; - classId = data.GetGuid(offset); + var classId = data.GetGuid(offset); offset += 16; - previous = ParseRecord(data, offset, recordLength, connection, classId); - offset += recordLength; + + var template = Warehouse.GetTemplateByClassId(classId, TemplateType.Record); + + reply.ArrayType = template.DefinedType; + + AsyncReply previous = null; + + if (result == RecordComparisonResult.Null) + previous = new AsyncReply(null); + else if (result == RecordComparisonResult.Record + || result == RecordComparisonResult.RecordSameType) + { + uint cs = data.GetUInt32(offset); + uint recordLength = cs; + offset += 4; + previous = ParseRecord(data, offset, recordLength, connection, classId); + offset += recordLength; + } + + reply.Add(previous); + + while (offset < end) + { + result = (RecordComparisonResult)data[offset++]; + + if (result == RecordComparisonResult.Null) + previous = new AsyncReply(null); + else if (result == RecordComparisonResult.Record + || result == RecordComparisonResult.RecordSameType) + { + uint cs = data.GetUInt32(offset); + offset += 4; + previous = ParseRecord(data, offset, cs, connection, classId); + offset += cs; + } + else if (result == RecordComparisonResult.Same) + { + // do nothing + } + + reply.Add(previous); + } } - - reply.Add(previous); - - - while (offset < end) + else { - result = (RecordComparisonResult)data[offset++]; + AsyncReply previous = null; + Guid? classId = null; if (result == RecordComparisonResult.Null) previous = new AsyncReply(null); @@ -301,22 +332,44 @@ namespace Esiur.Data offset += 4; classId = data.GetGuid(offset); offset += 16; - previous = ParseRecord(data, offset, recordLength, connection, classId); + previous = ParseRecord(data, offset, recordLength, connection, classId); offset += recordLength; } - else if (result == RecordComparisonResult.RecordSameType) - { - uint cs = data.GetUInt32(offset); - offset += 4; - previous = ParseRecord(data, offset, cs, connection, classId); - offset += cs; - } - else if (result == RecordComparisonResult.Same) - { - // do nothing - } reply.Add(previous); + + + while (offset < end) + { + result = (RecordComparisonResult)data[offset++]; + + if (result == RecordComparisonResult.Null) + previous = new AsyncReply(null); + else if (result == RecordComparisonResult.Record) + { + uint cs = data.GetUInt32(offset); + uint recordLength = cs - 16; + offset += 4; + classId = data.GetGuid(offset); + offset += 16; + previous = ParseRecord(data, offset, recordLength, connection, classId); + offset += recordLength; + } + else if (result == RecordComparisonResult.RecordSameType) + { + uint cs = data.GetUInt32(offset); + offset += 4; + previous = ParseRecord(data, offset, cs, connection, classId); + offset += cs; + } + else if (result == RecordComparisonResult.Same) + { + // do nothing + } + + reply.Add(previous); + } + } reply.Seal(); @@ -335,15 +388,15 @@ namespace Esiur.Data length -= 16; } - var template = Warehouse.GetTemplateByClassId((Guid)classId); + var template = Warehouse.GetTemplateByClassId((Guid)classId, TemplateType.Record); if (template != null) { ParseVarArray(data, offset, length, connection).Then(ar => { - if (template.ResourceType != null) + if (template.DefinedType != null) { - var record = Activator.CreateInstance(template.ResourceType) as IRecord; + var record = Activator.CreateInstance(template.DefinedType) as IRecord; for (var i = 0; i < template.Properties.Length; i++) template.Properties[i].PropertyInfo.SetValue(record, ar[i]); @@ -399,7 +452,8 @@ namespace Esiur.Data return rt.ToArray(); } - public static byte[] ComposeRecordArray(IRecord[] records, DistributedConnection connection, bool prependLength = false) + public static byte[] ComposeRecordArray(T[] records, DistributedConnection connection, bool prependLength = false) + where T : IRecord { if (records == null || records?.Length == 0) @@ -408,23 +462,59 @@ namespace Esiur.Data var rt = new BinaryList(); var comparsion = Compare(null, records[0]); - rt.AddUInt8((byte)comparsion); + var type = records.GetType().GetElementType(); + var isTyped = type != typeof(IRecord); - - if (comparsion == RecordComparisonResult.Record) - rt.AddUInt8Array(ComposeRecord(records[0], connection, true, true)); - - for (var i = 1; i < records.Length; i++) + if (isTyped) + { + var template = Warehouse.GetTemplateByType(type); + + if (template != null) + { + // typed array ... no need to add class id , it will be included at the first entry + rt.AddUInt8((byte)(0x10 | (byte)comparsion)); + rt.AddGuid(template.ClassId); + } + else // something wrong + { + throw new Exception($"Template for type `{type.FullName}` not found."); + } + + if (comparsion == RecordComparisonResult.Record) + rt.AddUInt8Array(ComposeRecord(records[0], connection, false, true)); + + for (var i = 1; i < records.Length; i++) + { + comparsion = Compare(records[i - 1], records[i]); + + rt.AddUInt8((byte)comparsion); + + if (comparsion == RecordComparisonResult.RecordSameType + || comparsion == RecordComparisonResult.Record) + rt.AddUInt8Array(ComposeRecord(records[i], connection, false, true)); + } + } + else { - comparsion = Compare(records[i - 1], records[i]); rt.AddUInt8((byte)comparsion); if (comparsion == RecordComparisonResult.Record) - rt.AddUInt8Array(ComposeRecord(records[i], connection, true, true)); - else if (comparsion == RecordComparisonResult.RecordSameType) - rt.AddUInt8Array(ComposeRecord(records[i], connection, false, true)); + rt.AddUInt8Array(ComposeRecord(records[0], connection, true, true)); + + for (var i = 1; i < records.Length; i++) + { + comparsion = Compare(records[i - 1], records[i]); + + rt.AddUInt8((byte)comparsion); + + if (comparsion == RecordComparisonResult.Record) + rt.AddUInt8Array(ComposeRecord(records[i], connection, true, true)); + else if (comparsion == RecordComparisonResult.RecordSameType) + rt.AddUInt8Array(ComposeRecord(records[i], connection, false, true)); + } } + if (prependLength) rt.InsertInt32(0, rt.Length); @@ -839,15 +929,40 @@ namespace Esiur.Data /// DistributedConnection is required to check locality. /// If True, prepend the length of the output at the beginning. /// Array of bytes in the network byte order. - public static byte[] ComposeResourceArray(IResource[] resources, DistributedConnection connection, bool prependLength = false) + public static byte[] ComposeResourceArray(T[] resources, DistributedConnection connection, bool prependLength = false) + where T : IResource { + if (resources == null || resources?.Length == 0) return prependLength ? new byte[] { 0, 0, 0, 0 } : new byte[0]; var rt = new BinaryList(); var comparsion = Compare(null, resources[0], connection); - rt.AddUInt8((byte)comparsion); + var type = resources.GetType().GetElementType(); + + + if (type != typeof(IResource)) + { + // get template + var tmp = Warehouse.GetTemplateByType(type); + + if (tmp == null) // something wrong + rt.AddUInt8((byte)comparsion); + else + { + // typed array + rt.AddUInt8((byte)((byte)( tmp.Type == TemplateType.Resource ? ResourceArrayType.Static : ResourceArrayType.Wrapper) + | (byte)comparsion)); + // add type + rt.AddGuid(tmp.ClassId); + } + } + else + { + rt.AddUInt8((byte)comparsion); + } + if (comparsion == ResourceComparisonResult.Local) rt.AddUInt32((resources[0] as DistributedResource).Id); @@ -889,8 +1004,29 @@ namespace Esiur.Data var end = offset + length; - // - var result = (ResourceComparisonResult)data[offset++]; + // Is typed array ? + var type = (ResourceArrayType) (data[offset] & 0xF0); + + var result = (ResourceComparisonResult)(data[offset++] & 0xF); + + + if (type == ResourceArrayType.Wrapper) + { + var classId = data.GetGuid(offset); + offset += 16; + var tmp = Warehouse.GetTemplateByClassId(classId, TemplateType.Resource); + // not mine, look if the type is elsewhere + if (tmp == null) + Warehouse.GetTemplateByClassId(classId, TemplateType.Wrapper); + reply.ArrayType = tmp?.DefinedType; + } + else if (type == ResourceArrayType.Static) + { + var classId = data.GetGuid(offset); + offset += 16; + var tmp = Warehouse.GetTemplateByClassId(classId, TemplateType.Wrapper); + reply.ArrayType = tmp?.DefinedType; + } AsyncReply previous = null; @@ -1236,11 +1372,14 @@ namespace Esiur.Data break; case DataType.ResourceArray: - if (value is IResource[]) - rt.AddUInt8Array(ComposeResourceArray((IResource[])value, connection, true)); - else - rt.AddUInt8Array(ComposeResourceArray((IResource[])DC.CastConvert(value, typeof(IResource[])), connection, true)); + + rt.AddUInt8Array(ComposeResourceArray((IResource[])value, connection, true)); break; + //if (value is IResource[]) + // rt.AddUInt8Array(ComposeResourceArray((IResource[])value, connection, true)); + //else + // rt.AddUInt8Array(ComposeResourceArray((IResource[])DC.CastConvert(value, typeof(IResource[])), connection, true)); + //break; case DataType.StructureArray: rt.AddUInt8Array(ComposeStructureArray((Structure[])value, connection, true)); @@ -1281,38 +1420,6 @@ namespace Esiur.Data /// True, if implements . public static bool ImplementsInterface(Type type, Type iface) { - /* - if (iface.GetTypeInfo().IsGenericType) - { - //var x = (type.GetTypeInfo().GetInterfaces().Any(x => x.GetTypeInfo().IsGenericType Contains(iface)) - - iface = iface.GetTypeInfo().GetGenericTypeDefinition(); - - //if (type.GetTypeInfo().IsGenericType) - // type = - while (type != null) - { - if (type == iface) - return true; - -#if NETSTANDARD - if (type.GetTypeInfo().GetInterfaces().Contains(iface))// (x=>x.GetTypeInfo().IsGenericType (iface)) - return true; - - type = type.GetTypeInfo().BaseType; -#else - if (type.GetInterfaces().Contains(iface)) - return true; - type = type.BaseType; -#endif - } - - - } - else - */ - //{ - while (type != null) { if (type == iface) @@ -1330,10 +1437,12 @@ namespace Esiur.Data #endif } - //} return false; } + public static bool InheritsClass(Type type, Type parent) + => type.IsSubclassOf(parent); + /// /// Check if a type inherits another type. /// diff --git a/Esiur/Data/ResourceArrayType.cs b/Esiur/Data/ResourceArrayType.cs new file mode 100644 index 0000000..3f110d5 --- /dev/null +++ b/Esiur/Data/ResourceArrayType.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Data +{ + public enum ResourceArrayType + { + Dynamic = 0x0, + Static = 0x10, + Wrapper = 0x20, + } +} diff --git a/Esiur/Data/ResourceComparisonResult.cs b/Esiur/Data/ResourceComparisonResult.cs index b6b7a12..741a9b5 100644 --- a/Esiur/Data/ResourceComparisonResult.cs +++ b/Esiur/Data/ResourceComparisonResult.cs @@ -6,9 +6,9 @@ namespace Esiur.Data { public enum ResourceComparisonResult { - Null, - Distributed, - Local, - Same + Null, // null + Distributed, // resource is distributed + Local, // resource is local + Same, // Same as previous } } diff --git a/Esiur/Esiur.csproj b/Esiur/Esiur.csproj index 9ae0cc4..20d92e6 100644 --- a/Esiur/Esiur.csproj +++ b/Esiur/Esiur.csproj @@ -7,12 +7,12 @@ https://github.com/Esiur/Esiur-dotnet/blob/master/LICENSE http://www.esiur.com true - 1.8.2.18 + 1.8.5 https://github.com/esiur/esiur-dotnet Ahmed Kh. Zamil - 1.8.1.0 + 1.8.5.0 Esiur Foundation - 1.8.1.0 + 1.8.5.0 Esiur Esiur Esiur @@ -41,7 +41,6 @@ - @@ -54,7 +53,6 @@ - diff --git a/Esiur/Net/IIP/DistributedConnection.cs b/Esiur/Net/IIP/DistributedConnection.cs index 95e8102..ac7f8c5 100644 --- a/Esiur/Net/IIP/DistributedConnection.cs +++ b/Esiur/Net/IIP/DistributedConnection.cs @@ -556,7 +556,7 @@ namespace Esiur.Net.IIP case IIPPacket.IIPPacketAction.TemplateFromClassName: case IIPPacket.IIPPacketAction.TemplateFromClassId: case IIPPacket.IIPPacketAction.TemplateFromResourceId: - IIPReply(packet.CallbackId, ResourceTemplate.Parse(packet.Content)); + IIPReply(packet.CallbackId, TypeTemplate.Parse(packet.Content)); break; case IIPPacketAction.QueryLink: diff --git a/Esiur/Net/IIP/DistributedConnectionProtocol.cs b/Esiur/Net/IIP/DistributedConnectionProtocol.cs index d11d3fe..4650e65 100644 --- a/Esiur/Net/IIP/DistributedConnectionProtocol.cs +++ b/Esiur/Net/IIP/DistributedConnectionProtocol.cs @@ -44,12 +44,12 @@ namespace Esiur.Net.IIP { KeyList resources = new KeyList(); KeyList> resourceRequests = new KeyList>(); - KeyList> templateRequests = new KeyList>(); + KeyList> templateRequests = new KeyList>(); KeyList> pathRequests = new KeyList>(); - Dictionary templates = new Dictionary(); + Dictionary templates = new Dictionary(); KeyList requests = new KeyList(); @@ -1095,11 +1095,11 @@ namespace Esiur.Net.IIP var msg = new BinaryList(); - var templates = new List(); + var templates = new List(); foreach (var resource in list) - templates.AddRange(ResourceTemplate.GetDependencies(resource.Instance.Template).Where(x => !templates.Contains(x))); + templates.AddRange(TypeTemplate.GetDependencies(resource.Instance.Template).Where(x => !templates.Contains(x))); - foreach(var t in templates) + foreach (var t in templates) { msg.AddInt32(t.Content.Length) .AddUInt8Array(t.Content); @@ -1122,19 +1122,18 @@ namespace Esiur.Net.IIP void IIPRequestTemplateFromClassName(uint callback, string className) { - Warehouse.GetTemplateByClassName(className).Then((t) => + var t = Warehouse.GetTemplateByClassName(className); + + if (t != null) + SendReply(IIPPacket.IIPPacketAction.TemplateFromClassName, callback) + .AddInt32(t.Content.Length) + .AddUInt8Array(t.Content) + .Done(); + else { - if (t != null) - SendReply(IIPPacket.IIPPacketAction.TemplateFromClassName, callback) - .AddInt32(t.Content.Length) - .AddUInt8Array(t.Content) - .Done(); - else - { - // reply failed - SendError(ErrorType.Management, callback, (ushort)ExceptionCode.TemplateNotFound); - } - }); + // reply failed + SendError(ErrorType.Management, callback, (ushort)ExceptionCode.TemplateNotFound); + } } void IIPRequestTemplateFromClassId(uint callback, Guid classId) @@ -2037,14 +2036,14 @@ namespace Esiur.Net.IIP /// /// Class GUID. /// ResourceTemplate. - public AsyncReply GetTemplate(Guid classId) + public AsyncReply GetTemplate(Guid classId) { if (templates.ContainsKey(classId)) - return new AsyncReply(templates[classId]); + return new AsyncReply(templates[classId]); else if (templateRequests.ContainsKey(classId)) return templateRequests[classId]; - var reply = new AsyncReply(); + var reply = new AsyncReply(); templateRequests.Add(classId, reply); SendRequest(IIPPacket.IIPPacketAction.TemplateFromClassId) @@ -2053,8 +2052,8 @@ namespace Esiur.Net.IIP .Then((rt) => { templateRequests.Remove(classId); - templates.Add(((ResourceTemplate)rt[0]).ClassId, (ResourceTemplate)rt[0]); - Warehouse.PutTemplate(rt[0] as ResourceTemplate); + templates.Add(((TypeTemplate)rt[0]).ClassId, (TypeTemplate)rt[0]); + Warehouse.PutTemplate(rt[0] as TypeTemplate); reply.Trigger(rt[0]); }).Error((ex) => { @@ -2134,9 +2133,9 @@ namespace Esiur.Net.IIP } - public AsyncReply GetLinkTemplates(string link) + public AsyncReply GetLinkTemplates(string link) { - var reply = new AsyncReply(); + var reply = new AsyncReply(); var l = DC.ToBytes(link); @@ -2147,7 +2146,7 @@ namespace Esiur.Net.IIP .Then((rt) => { - var templates = new List(); + var templates = new List(); // parse templates var data = (byte[])rt[0]; @@ -2156,7 +2155,7 @@ namespace Esiur.Net.IIP { var cs = data.GetUInt32(offset); offset += 4; - templates.Add(ResourceTemplate.Parse(data, offset, cs)); + templates.Add(TypeTemplate.Parse(data, offset, cs)); offset += cs; } @@ -2208,9 +2207,9 @@ namespace Esiur.Net.IIP if (resource == null) { - var template = Warehouse.GetTemplateByClassId((Guid)rt[0], true); - if (template?.ResourceType != null) - dr = Activator.CreateInstance(template.ResourceType, this, id, (ulong)rt[1], (string)rt[2]) as DistributedResource; + var template = Warehouse.GetTemplateByClassId((Guid)rt[0], TemplateType.Wrapper); + if (template?.DefinedType != null) + dr = Activator.CreateInstance(template.DefinedType, this, id, (ulong)rt[1], (string)rt[2]) as DistributedResource; else dr = new DistributedResource(this, id, (ulong)rt[1], (string)rt[2]); } diff --git a/Esiur/Proxy/ResourceGenerator.cs b/Esiur/Proxy/ResourceGenerator.cs index c75bf0b..708ab69 100644 --- a/Esiur/Proxy/ResourceGenerator.cs +++ b/Esiur/Proxy/ResourceGenerator.cs @@ -22,7 +22,7 @@ namespace Esiur.Proxy - private KeyList cache = new(); + private KeyList cache = new(); // private List inProgress = new(); public void Initialize(GeneratorInitializationContext context) @@ -41,7 +41,7 @@ namespace Esiur.Proxy - void GenerateModel(GeneratorExecutionContext context, ResourceTemplate[] templates) + void GenerateModel(GeneratorExecutionContext context, TypeTemplate[] templates) { foreach (var tmp in templates) { @@ -126,7 +126,7 @@ namespace Esiur.Proxy catch (Exception ex) { ReportError(context, ex.Source, ex.Message, "Esiur"); - System.IO.File.AppendAllText("c:\\gen\\error.log", ex.ToString() + "\r\n"); + //System.IO.File.AppendAllText("c:\\gen\\error.log", ex.ToString() + "\r\n"); } //inProgress.Remove(path); diff --git a/Esiur/Proxy/TemplateGenerator.cs b/Esiur/Proxy/TemplateGenerator.cs index 8cd7dc3..8fca0b0 100644 --- a/Esiur/Proxy/TemplateGenerator.cs +++ b/Esiur/Proxy/TemplateGenerator.cs @@ -16,7 +16,7 @@ namespace Esiur.Proxy { internal static Regex urlRegex = new Regex(@"^(?:([\S]*)://([^/]*)/?)"); - internal static string GenerateRecord(ResourceTemplate template, ResourceTemplate[] templates) + internal static string GenerateRecord(TypeTemplate template, TypeTemplate[] templates) { var cls = template.ClassName.Split('.'); @@ -42,7 +42,7 @@ namespace Esiur.Proxy return rt.ToString(); } - static string GetTypeName(TemplateDataType templateDataType, ResourceTemplate[] templates) + static string GetTypeName(TemplateDataType templateDataType, TypeTemplate[] templates) { if (templateDataType.Type == DataType.Resource) @@ -162,7 +162,7 @@ namespace Esiur.Proxy } } - internal static string GenerateClass(ResourceTemplate template, ResourceTemplate[] templates) + internal static string GenerateClass(TypeTemplate template, TypeTemplate[] templates) { var cls = template.ClassName.Split('.'); @@ -213,7 +213,7 @@ namespace Esiur.Proxy { var etTypeName = GetTypeName(e.ArgumentType, templates); rt.AppendLine($"case {e.Index}: {e.Name}?.Invoke(({etTypeName})args); break;"); - eventsList.AppendLine($"public event ResourceEventHanlder<{etTypeName}> {e.Name};"); + eventsList.AppendLine($"public event ResourceEventHandler<{etTypeName}> {e.Name};"); } rt.AppendLine("}}"); diff --git a/Esiur/Resource/Instance.cs b/Esiur/Resource/Instance.cs index 36b172f..3425519 100644 --- a/Esiur/Resource/Instance.cs +++ b/Esiur/Resource/Instance.cs @@ -28,7 +28,7 @@ namespace Esiur.Resource WeakReference resource; IStore store; - ResourceTemplate template; + TypeTemplate template; AutoList managers; @@ -794,7 +794,7 @@ namespace Esiur.Resource /// /// Resource template describes the properties, functions and events of the resource. /// - public ResourceTemplate Template + public TypeTemplate Template { get { return template; } @@ -853,7 +853,7 @@ namespace Esiur.Resource /// Name of the instance. /// Resource to manage. /// Store responsible for the resource. - public Instance(uint id, string name, IResource resource, IStore store, ResourceTemplate customTemplate = null, ulong age = 0) + public Instance(uint id, string name, IResource resource, IStore store, TypeTemplate customTemplate = null, ulong age = 0) { this.store = store; this.resource = new WeakReference(resource); @@ -897,7 +897,7 @@ namespace Esiur.Resource foreach (var evt in template.Events) { - //if (evt.EventHandlerType != typeof(ResourceEventHanlder)) + //if (evt.EventHandlerType != typeof(ResourceEventHandler)) // continue; if (evt.EventInfo == null) @@ -905,24 +905,24 @@ namespace Esiur.Resource var eventGenericType = evt.EventInfo.EventHandlerType.GetGenericTypeDefinition(); - if (eventGenericType == typeof(ResourceEventHanlder<>)) + if (eventGenericType == typeof(ResourceEventHandler<>)) { // var ca = (ResourceEvent[])evt.GetCustomAttributes(typeof(ResourceEvent), true); // if (ca.Length == 0) // continue; - ResourceEventHanlder proxyDelegate = (args) => EmitResourceEvent(evt.Name, args); + ResourceEventHandler proxyDelegate = (args) => EmitResourceEvent(evt.Name, args); evt.EventInfo.AddEventHandler(resource, proxyDelegate); } - else if (eventGenericType == typeof(CustomResourceEventHanlder<>)) + else if (eventGenericType == typeof(CustomResourceEventHandler<>)) { //var ca = (ResourceEvent[])evt.GetCustomAttributes(typeof(ResourceEvent), true); //if (ca.Length == 0) // continue; - CustomResourceEventHanlder proxyDelegate = (issuer, receivers, args) => EmitCustomResourceEvent(issuer, receivers, evt.Name, args); + CustomResourceEventHandler proxyDelegate = (issuer, receivers, args) => EmitCustomResourceEvent(issuer, receivers, evt.Name, args); evt.EventInfo.AddEventHandler(resource, proxyDelegate); } diff --git a/Esiur/Resource/ResourceEventHandler.cs b/Esiur/Resource/ResourceEventHandler.cs index d2840b0..1870097 100644 --- a/Esiur/Resource/ResourceEventHandler.cs +++ b/Esiur/Resource/ResourceEventHandler.cs @@ -35,12 +35,12 @@ namespace Esiur.Resource { public delegate R DCovariant(); - public delegate void ResourceEventHanlder(T argument); + public delegate void ResourceEventHandler(T argument); // public delegate void CustomUsersEventHanlder(string[] usernames, params object[] args); //public delegate void CustomReceiversEventHanlder(DistributedConnection[] connections, params object[] args); //public delegate void CustomInquirerEventHanlder(object inquirer, params object[] args); - public delegate void CustomResourceEventHanlder(object issuer, Func receivers, T argument);// object issuer, Session[] receivers, params object[] args); + public delegate void CustomResourceEventHandler(object issuer, Func receivers, T argument);// object issuer, Session[] receivers, params object[] args); // public delegate void CustomReceiversEventHanlder(string[] usernames, DistributedConnection[] connections, params object[] args); diff --git a/Esiur/Resource/Template/AttributeTemplate.cs b/Esiur/Resource/Template/AttributeTemplate.cs index 1eaa829..199ca5b 100644 --- a/Esiur/Resource/Template/AttributeTemplate.cs +++ b/Esiur/Resource/Template/AttributeTemplate.cs @@ -17,7 +17,7 @@ namespace Esiur.Resource.Template } - public AttributeTemplate(ResourceTemplate template, byte index, string name) + public AttributeTemplate(TypeTemplate template, byte index, string name) : base(template, MemberType.Attribute, index, name) { diff --git a/Esiur/Resource/Template/EventTemplate.cs b/Esiur/Resource/Template/EventTemplate.cs index 5cee5db..7b4830e 100644 --- a/Esiur/Resource/Template/EventTemplate.cs +++ b/Esiur/Resource/Template/EventTemplate.cs @@ -48,7 +48,7 @@ namespace Esiur.Resource.Template } - public EventTemplate(ResourceTemplate template, byte index, string name, TemplateDataType argumentType, string expansion = null, bool listenable=false) + public EventTemplate(TypeTemplate template, byte index, string name, TemplateDataType argumentType, string expansion = null, bool listenable=false) :base(template, MemberType.Property, index, name) { this.Expansion = expansion; diff --git a/Esiur/Resource/Template/FunctionTemplate.cs b/Esiur/Resource/Template/FunctionTemplate.cs index edc79ac..92ea1c0 100644 --- a/Esiur/Resource/Template/FunctionTemplate.cs +++ b/Esiur/Resource/Template/FunctionTemplate.cs @@ -64,7 +64,7 @@ namespace Esiur.Resource.Template } - public FunctionTemplate(ResourceTemplate template, byte index, string name, ArgumentTemplate[] arguments, TemplateDataType returnType, string expansion = null) + public FunctionTemplate(TypeTemplate template, byte index, string name, ArgumentTemplate[] arguments, TemplateDataType returnType, string expansion = null) : base(template, MemberType.Property, index, name) { //this.IsVoid = isVoid; diff --git a/Esiur/Resource/Template/MemberTemplate.cs b/Esiur/Resource/Template/MemberTemplate.cs index 004e702..4378f63 100644 --- a/Esiur/Resource/Template/MemberTemplate.cs +++ b/Esiur/Resource/Template/MemberTemplate.cs @@ -21,14 +21,14 @@ namespace Esiur.Resource.Template public string Name => name; public MemberType Type => type; - ResourceTemplate template; + TypeTemplate template; string name; MemberType type; byte index; - public ResourceTemplate Template => template; + public TypeTemplate Template => template; - public MemberTemplate(ResourceTemplate template, MemberType type, byte index, string name) + public MemberTemplate(TypeTemplate template, MemberType type, byte index, string name) { this.template = template; this.type = type; diff --git a/Esiur/Resource/Template/PropertyTemplate.cs b/Esiur/Resource/Template/PropertyTemplate.cs index 9744cd2..f4508bc 100644 --- a/Esiur/Resource/Template/PropertyTemplate.cs +++ b/Esiur/Resource/Template/PropertyTemplate.cs @@ -130,7 +130,7 @@ namespace Esiur.Resource.Template } } - public PropertyTemplate(ResourceTemplate template, byte index, string name, TemplateDataType valueType, string read = null, string write = null, bool recordable = false) + public PropertyTemplate(TypeTemplate template, byte index, string name, TemplateDataType valueType, string read = null, string write = null, bool recordable = false) : base(template, MemberType.Property, index, name) { this.Recordable = recordable; diff --git a/Esiur/Resource/Template/RecordTemplate.cs b/Esiur/Resource/Template/RecordTemplate.cs deleted file mode 100644 index 6bb33e6..0000000 --- a/Esiur/Resource/Template/RecordTemplate.cs +++ /dev/null @@ -1,277 +0,0 @@ -using Esiur.Data; -using System; -using System.Collections.Generic; -using System.Reflection; -using System.Text; - -namespace Esiur.Resource.Template -{ - public class RecordTemplate : ResourceTemplate - { - //Guid classId; - //public Guid ClassId => classId; - - //string className; - //public string ClassName => className; - - public RecordTemplate() - { - - } - - public new static RecordTemplate Parse(byte[] data, uint offset, uint contentLength) - { - - uint ends = offset + contentLength; - - uint oOffset = offset; - - // start parsing... - - var od = new RecordTemplate(); - od.content = data.Clip(offset, contentLength); - - od.classId = data.GetGuid(offset); - offset += 16; - od.className = data.GetString(offset + 1, data[offset]); - offset += (uint)data[offset] + 1; - - od.version = data.GetInt32(offset); - offset += 4; - - ushort methodsCount = data.GetUInt16(offset); - offset += 2; - - - - for (int i = 0; i < methodsCount; i++) - { - var type = data[offset] >> 5; - - if (type == 0) // function - { - string expansion = null; - var hasExpansion = ((data[offset++] & 0x10) == 0x10); - - var name = data.GetString(offset + 1, data[offset]); - offset += (uint)data[offset] + 1; - - // return type - var (rts, returnType) = TemplateDataType.Parse(data, offset); - offset += rts; - - // arguments count - var argsCount = data[offset++]; - List arguments = new(); - - for (var a = 0; a < argsCount; a++) - { - var (cs, argType) = ArgumentTemplate.Parse(data, offset); - arguments.Add(argType); - offset += cs; - } - - // arguments - if (hasExpansion) // expansion ? - { - var cs = data.GetUInt32(offset); - offset += 4; - expansion = data.GetString(offset, cs); - offset += cs; - } - - var ft = new FunctionTemplate(od, functionIndex++, name, arguments.ToArray(), returnType, expansion); - - od.functions.Add(ft); - } - else if (type == 1) // property - { - - string readExpansion = null, writeExpansion = null; - - var hasReadExpansion = ((data[offset] & 0x8) == 0x8); - var hasWriteExpansion = ((data[offset] & 0x10) == 0x10); - var recordable = ((data[offset] & 1) == 1); - var permission = (PropertyTemplate.PropertyPermission)((data[offset++] >> 1) & 0x3); - var name = data.GetString(offset + 1, data[offset]);// Encoding.ASCII.GetString(data, (int)offset + 1, data[offset]); - - offset += (uint)data[offset] + 1; - - var (dts, valueType) = TemplateDataType.Parse(data, offset); - - offset += dts; - - if (hasReadExpansion) // expansion ? - { - var cs = data.GetUInt32(offset); - offset += 4; - readExpansion = data.GetString(offset, cs); - offset += cs; - } - - if (hasWriteExpansion) // expansion ? - { - var cs = data.GetUInt32(offset); - offset += 4; - writeExpansion = data.GetString(offset, cs); - offset += cs; - } - - var pt = new PropertyTemplate(od, propertyIndex++, name, valueType, readExpansion, writeExpansion, recordable); - - od.properties.Add(pt); - } - else if (type == 2) // Event - { - - string expansion = null; - var hasExpansion = ((data[offset] & 0x10) == 0x10); - var listenable = ((data[offset++] & 0x8) == 0x8); - - var name = data.GetString(offset + 1, data[offset]);// Encoding.ASCII.GetString(data, (int)offset + 1, (int)data[offset]); - offset += (uint)data[offset] + 1; - - var (dts, argType) = TemplateDataType.Parse(data, offset); - - offset += dts; - - if (hasExpansion) // expansion ? - { - var cs = data.GetUInt32(offset); - offset += 4; - expansion = data.GetString(offset, cs); - offset += cs; - } - - var et = new EventTemplate(od, eventIndex++, name, argType, expansion, listenable); - - od.events.Add(et); - - } - } - - // append signals - for (int i = 0; i < od.events.Count; i++) - od.members.Add(od.events[i]); - // append slots - for (int i = 0; i < od.functions.Count; i++) - od.members.Add(od.functions[i]); - // append properties - for (int i = 0; i < od.properties.Count; i++) - od.members.Add(od.properties[i]); - - - //od.isReady = true; - /* - var oo = owner.Socket.Engine.GetObjectDescription(od.GUID); - if (oo != null) - { - Console.WriteLine("Already there ! description"); - return oo; - } - else - { - owner.Socket.Engine.AddObjectDescription(od); - return od; - } - */ - - return od; - } - - public RecordTemplate(Type type) - { - if (!Codec.ImplementsInterface(type, typeof(IRecord))) - throw new Exception("Type is not a record."); - - className = type.FullName; - classId = ResourceTemplate.GetTypeGuid(className); - -#if NETSTANDARD - PropertyInfo[] propsInfo = type.GetTypeInfo().GetProperties(BindingFlags.Public | BindingFlags.Instance); -#else - PropertyInfo[] propsInfo = type.GetProperties(BindingFlags.Public | BindingFlags.Instance); -#endif - - bool classIsPublic = type.GetCustomAttribute() != null; - - byte i = 0; - - if (classIsPublic) - { - foreach (var pi in propsInfo) - { - var privateAttr = pi.GetCustomAttribute(true); - - if (privateAttr == null) - continue; - - var annotationAttr = pi.GetCustomAttribute(true); - var storageAttr = pi.GetCustomAttribute(true); - - var pt = new PropertyTemplate(this, i++, pi.Name, TemplateDataType.FromType(pi.PropertyType)); - - if (storageAttr != null) - pt.Recordable = storageAttr.Mode == StorageMode.Recordable; - - if (annotationAttr != null) - pt.ReadExpansion = annotationAttr.Annotation; - else - pt.ReadExpansion = pi.PropertyType.Name; - - pt.PropertyInfo = pi; - //pt.Serilize = publicAttr.Serialize; - properties.Add(pt); - members.Add(pt); - } - } - else - { - foreach (var pi in propsInfo) - { - var publicAttr = pi.GetCustomAttribute(true); - - if (publicAttr == null) - continue; - - - var annotationAttr = pi.GetCustomAttribute(true); - var storageAttr = pi.GetCustomAttribute(true); - var valueType = TemplateDataType.FromType(pi.PropertyType); - - var pt = new PropertyTemplate(this, i++, pi.Name, valueType);//, rp.ReadExpansion, rp.WriteExpansion, rp.Storage); - if (storageAttr != null) - pt.Recordable = storageAttr.Mode == StorageMode.Recordable; - - if (annotationAttr != null) - pt.ReadExpansion = annotationAttr.Annotation; - else - pt.ReadExpansion = pi.PropertyType.Name; - - pt.PropertyInfo = pi; - //pt.Serilize = publicAttr.Serialize; - properties.Add(pt); - members.Add(pt); - } - } - - - - // bake it binarily - var b = new BinaryList(); - b.AddGuid(classId) - .AddUInt8((byte)className.Length) - .AddString(className) - .AddInt32(version) - .AddUInt16((ushort)members.Count); - - - foreach (var pt in properties) - b.AddUInt8Array(pt.Compose()); - - content = b.ToArray(); - - - } - } -} diff --git a/Esiur/Resource/Template/TemplateDataType.cs b/Esiur/Resource/Template/TemplateDataType.cs index 7ceb11a..25d84f5 100644 --- a/Esiur/Resource/Template/TemplateDataType.cs +++ b/Esiur/Resource/Template/TemplateDataType.cs @@ -10,7 +10,7 @@ namespace Esiur.Resource.Template { public DataType Type { get; set; } //public string TypeName { get; set; } - public ResourceTemplate TypeTemplate => TypeGuid == null ? null : Warehouse.GetTemplateByClassId((Guid)TypeGuid); + public TypeTemplate TypeTemplate => TypeGuid == null ? null : Warehouse.GetTemplateByClassId((Guid)TypeGuid); public Guid? TypeGuid { get; set; } //public TemplateDataType(DataType type, string typeName) @@ -49,6 +49,7 @@ namespace Esiur.Resource.Template _ when t == typeof(string) => DataType.String, _ when t == typeof(DateTime) => DataType.DateTime, _ when t == typeof(IResource) => DataType.Void, // Dynamic resource (unspecified type) + _ when t == typeof(IRecord) => DataType.Void, // Dynamic record (unspecified type) _ when typeof(Structure).IsAssignableFrom(t) || t == typeof(ExpandoObject) => DataType.Structure, _ when Codec.ImplementsInterface(t, typeof(IResource)) => DataType.Resource, _ when Codec.ImplementsInterface(t, typeof(IRecord)) => DataType.Record, @@ -59,7 +60,7 @@ namespace Esiur.Resource.Template Guid? typeGuid = null; if (dt == DataType.Resource || dt == DataType.Record) - typeGuid = ResourceTemplate.GetTypeGuid(t); + typeGuid = TypeTemplate.GetTypeGuid(t); if (type.IsArray) dt = (DataType)((byte)dt | 0x80); diff --git a/Esiur/Resource/Template/TemplateType.cs b/Esiur/Resource/Template/TemplateType.cs index 58d39a7..f29edde 100644 --- a/Esiur/Resource/Template/TemplateType.cs +++ b/Esiur/Resource/Template/TemplateType.cs @@ -6,7 +6,9 @@ namespace Esiur.Resource.Template { public enum TemplateType:byte { + Unspecified, Resource, Record, + Wrapper, } } diff --git a/Esiur/Resource/Template/ResourceTemplate.cs b/Esiur/Resource/Template/TypeTemplate.cs similarity index 95% rename from Esiur/Resource/Template/ResourceTemplate.cs rename to Esiur/Resource/Template/TypeTemplate.cs index 124dc1c..7a87aee 100644 --- a/Esiur/Resource/Template/ResourceTemplate.cs +++ b/Esiur/Resource/Template/TypeTemplate.cs @@ -18,7 +18,7 @@ namespace Esiur.Resource.Template // Record //} - public class ResourceTemplate + public class TypeTemplate { protected Guid classId; @@ -44,7 +44,7 @@ namespace Esiur.Resource.Template public TemplateType Type => templateType; - public Type ResourceType { get; set; } + public Type DefinedType { get; set; } @@ -146,7 +146,7 @@ namespace Esiur.Resource.Template - public ResourceTemplate() + public TypeTemplate() { } @@ -171,18 +171,18 @@ namespace Esiur.Resource.Template - public static ResourceTemplate[] GetDependencies(ResourceTemplate template) + public static TypeTemplate[] GetDependencies(TypeTemplate template) { - var list = new List(); + var list = new List(); list.Add(template); - Action> getDependenciesFunc = null; + Action> getDependenciesFunc = null; - getDependenciesFunc = (ResourceTemplate tmp, List bag) => + getDependenciesFunc = (TypeTemplate tmp, List bag) => { - if (template.ResourceType == null) + if (template.DefinedType == null) return; // functions @@ -267,14 +267,16 @@ namespace Esiur.Resource.Template return list.ToArray(); } - public ResourceTemplate(Type type) + public TypeTemplate(Type type, bool addToWarehouse = false) { - if (Codec.ImplementsInterface(type, typeof(IRecord))) - templateType = TemplateType.Record; + if (Codec.InheritsClass(type, typeof(DistributedResource))) + templateType = TemplateType.Wrapper; else if (Codec.ImplementsInterface(type, typeof(IResource))) templateType = TemplateType.Resource; + else if (Codec.ImplementsInterface(type, typeof(IRecord))) + templateType = TemplateType.Record; else - throw new Exception("Type is neither a resource nor a record."); + throw new Exception("Type must implement IResource, IRecord or inherit from DistributedResource."); //if (isRecord && isResource) // throw new Exception("Type can't have both IResource and IRecord interfaces"); @@ -284,7 +286,7 @@ namespace Esiur.Resource.Template type = ResourceProxy.GetBaseType(type); - ResourceType = type; + DefinedType = type; className = type.FullName; @@ -292,7 +294,10 @@ namespace Esiur.Resource.Template // set guid classId = GetTypeGuid(className); - + + if (addToWarehouse) + Warehouse.PutTemplate(this); + #if NETSTANDARD PropertyInfo[] propsInfo = type.GetTypeInfo().GetProperties(BindingFlags.Public | BindingFlags.Instance);// | BindingFlags.DeclaredOnly); EventInfo[] eventsInfo = type.GetTypeInfo().GetEvents(BindingFlags.Public | BindingFlags.Instance);// | BindingFlags.DeclaredOnly); @@ -395,8 +400,7 @@ namespace Esiur.Resource.Template Name = x.Name, Type = TemplateDataType.FromType(x.ParameterType), ParameterInfo = x - }) - .ToArray(); + }).ToArray(); var ft = new FunctionTemplate(this, i++, mi.Name, arguments, returnType);// mi.ReturnType == typeof(void)); @@ -546,13 +550,13 @@ namespace Esiur.Resource.Template } - public static ResourceTemplate Parse(byte[] data) + public static TypeTemplate Parse(byte[] data) { return Parse(data, 0, (uint)data.Length); } - public static ResourceTemplate Parse(byte[] data, uint offset, uint contentLength) + public static TypeTemplate Parse(byte[] data, uint offset, uint contentLength) { uint ends = offset + contentLength; @@ -561,7 +565,7 @@ namespace Esiur.Resource.Template // start parsing... - var od = new ResourceTemplate(); + var od = new TypeTemplate(); od.content = data.Clip(offset, contentLength); od.templateType = (TemplateType)data[offset++]; diff --git a/Esiur/Resource/Warehouse.cs b/Esiur/Resource/Warehouse.cs index 4712f88..14e0bef 100644 --- a/Esiur/Resource/Warehouse.cs +++ b/Esiur/Resource/Warehouse.cs @@ -53,8 +53,17 @@ namespace Esiur.Resource static uint resourceCounter = 0; - static KeyList templates = new KeyList(); - static KeyList wrapperTemplates = new KeyList(); + //static KeyList templates = new KeyList(); + //static KeyList wrapperTemplates = new KeyList(); + + static KeyList> templates + = new KeyList>() + { + [TemplateType.Unspecified] = new KeyList(), + [TemplateType.Resource] = new KeyList(), + [TemplateType.Record] = new KeyList(), + [TemplateType.Wrapper] = new KeyList(), + }; static bool warehouseIsOpen = false; @@ -124,13 +133,13 @@ namespace Esiur.Resource var resourceTypes = (Type[])generatedType.GetProperty("Resources").GetValue(null); foreach (var t in resourceTypes) { - PutTemplate(new ResourceTemplate(t), true); + PutTemplate(new TypeTemplate(t)); } var recordTypes = (Type[])generatedType.GetProperty("Records").GetValue(null); foreach (var t in recordTypes) { - PutTemplate(new ResourceTemplate(t)); + PutTemplate(new TypeTemplate(t)); } } } @@ -519,7 +528,7 @@ namespace Esiur.Resource /// Resource instance. /// IStore that manages the resource. Can be null if the resource is a store. /// Parent resource. if not presented the store becomes the parent for the resource. - public static async AsyncReply Put(string name, T resource, IStore store = null, IResource parent = null, ResourceTemplate customTemplate = null, ulong age = 0, IPermissionsManager manager = null, object attributes = null) where T:IResource + public static async AsyncReply Put(string name, T resource, IStore store = null, IResource parent = null, TypeTemplate customTemplate = null, ulong age = 0, IPermissionsManager manager = null, object attributes = null) where T:IResource { if (resource.Instance != null) throw new Exception("Resource has a store."); @@ -737,15 +746,9 @@ namespace Esiur.Resource /// Put a resource template in the templates warehouse. /// /// Resource template. - public static void PutTemplate(ResourceTemplate template, bool wrapper = false) + public static void PutTemplate(TypeTemplate template) { - if (wrapper) - { - if (!wrapperTemplates.ContainsKey(template.ClassId)) - wrapperTemplates.Add(template.ClassId, template); - } - else if (!templates.ContainsKey(template.ClassId)) - templates.Add(template.ClassId, template); + templates[template.Type][template.ClassId] = template; } @@ -754,26 +757,31 @@ namespace Esiur.Resource /// /// .Net type. /// Resource template. - public static ResourceTemplate GetTemplateByType(Type type) + public static TypeTemplate GetTemplateByType(Type type) { - - if (!(Codec.ImplementsInterface(type, typeof(IResource)) - || Codec.ImplementsInterface(type, typeof(IRecord)))) - return null; + TemplateType templateType = TemplateType.Unspecified; + + if (Codec.InheritsClass(type, typeof(DistributedResource))) + templateType = TemplateType.Wrapper; + if (Codec.ImplementsInterface(type, typeof(IResource))) + templateType = TemplateType.Resource; + else if (Codec.ImplementsInterface(type, typeof(IRecord))) + templateType = TemplateType.Record; + else + return null; + var baseType = ResourceProxy.GetBaseType(type); if (baseType == typeof(IResource) || baseType == typeof(IRecord)) return null; + var template = templates[templateType].Values.FirstOrDefault(x => x.DefinedType == type); + // loaded ? - foreach (var t in templates.Values) - if (t.ClassName == baseType.FullName) - return t; - - var template = new ResourceTemplate(baseType); - templates.Add(template.ClassId, template); + if (template == null) + template = new TypeTemplate(baseType, true); return template; } @@ -783,17 +791,26 @@ namespace Esiur.Resource /// /// Class Id. /// Resource template. - public static ResourceTemplate GetTemplateByClassId(Guid classId, bool wrapper = false) + public static TypeTemplate GetTemplateByClassId(Guid classId, TemplateType templateType = TemplateType.Unspecified) { - if (wrapper) + if (templateType == TemplateType.Unspecified) { - if (wrapperTemplates.ContainsKey(classId)) - return wrapperTemplates[classId]; - } - else if (templates.ContainsKey(classId)) - return templates[classId]; + // look in resources + var template = templates[TemplateType.Resource][classId]; + if (template != null) + return template; + + // look in records + template = templates[TemplateType.Record][classId]; + if (template != null) + return template; - return null; + // look in wrappers + template = templates[TemplateType.Wrapper][classId]; + return template; + } + else + return templates[templateType][classId]; } /// @@ -801,13 +818,28 @@ namespace Esiur.Resource /// /// Class name. /// Resource template. - public static AsyncReply GetTemplateByClassName(string className) + public static TypeTemplate GetTemplateByClassName(string className, TemplateType templateType = TemplateType.Unspecified) { - foreach (var t in templates.Values) - if (t.ClassName == className) - return new AsyncReply(t); + if (templateType == TemplateType.Unspecified) + { + // look in resources + var template = templates[TemplateType.Resource].Values.FirstOrDefault(x => x.ClassName == className); + if (template != null) + return template; - return null; + // look in records + template = templates[TemplateType.Record].Values.FirstOrDefault(x => x.ClassName == className); + if (template != null) + return template; + + // look in wrappers + template = templates[TemplateType.Wrapper].Values.FirstOrDefault(x => x.ClassName == className); + return template; + } + else + { + return templates[templateType].Values.FirstOrDefault(x => x.ClassName == className); + } } public static bool Remove(IResource resource)