2
0
mirror of https://github.com/esiur/esiur-dotnet.git synced 2025-05-06 11:32:59 +00:00

Added JSON

This commit is contained in:
Ahmed Zamil 2021-02-20 11:38:11 +03:00
parent df88317b1f
commit 7c707637de
14 changed files with 296 additions and 106 deletions

View File

@ -79,7 +79,7 @@ namespace Esiur.Stores.EntityCore
public AsyncReply<bool> Put(IResource resource)
{
if (resource is EntityStore)
return new AsyncReply<bool>(false);
return new AsyncReply<bool>(true);
var type = ResourceProxy.GetBaseType(resource);//.GetType().;

View File

@ -12,7 +12,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="5.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.2" />
<PackageReference Include="System.Collections" Version="4.3.0" />
</ItemGroup>

View File

@ -22,6 +22,7 @@ SOFTWARE.
*/
using Esiur.Core;
using Esiur.Resource;
using Esiur.Security.Permissions;
using Microsoft.EntityFrameworkCore;
@ -43,6 +44,9 @@ namespace Esiur.Stores.EntityCore
//}
public static T AddResource<T>(this DbSet<T> dbSet, object properties = null) where T : class, IResource
=> AddResourceAsync(dbSet, properties).Wait();
public static async AsyncReply<T> AddResourceAsync<T>(this DbSet<T> dbSet, object properties = null) where T : class, IResource
{
var store = dbSet.GetInfrastructure().GetService<IDbContextOptions>().FindExtension<EsiurExtensionOptions>().Store;
var manager = store.Instance.Managers.FirstOrDefault();// > 0 ? store.Instance.Managers.First() : null;
@ -51,28 +55,31 @@ namespace Esiur.Stores.EntityCore
//var resource = dbSet.GetInfrastructure().CreateResource<T>(properties);
//var resource = Warehouse.New<T>("", options.Store, null, null, null, properties);
var resource = Warehouse.New<T>("", null, null, null, null, properties);
var resource = await Warehouse.New<T>("", null, null, null, null, properties);
var entity = dbSet.Add(resource);
entity.Context.SaveChanges();
await entity.Context.SaveChangesAsync();
var id = store.TypesByType[typeof(T)].PrimaryKey.GetValue(resource);
Warehouse.Put(resource, id.ToString(), store, null, null, 0, manager);
await Warehouse.Put(resource, id.ToString(), store, null, null, 0, manager);
return resource;
}
public static T CreateResource<T>(this IServiceProvider serviceProvider, object properties = null) where T : class, IResource
public static async AsyncReply<T> CreateResourceAsync<T>(this IServiceProvider serviceProvider, object properties = null) where T : class, IResource
{
var options = serviceProvider.GetService<IDbContextOptions>().FindExtension<EsiurExtensionOptions>();
var resource = Warehouse.New<T>("", options.Store, null, null, null, properties);
var resource = await Warehouse.New<T>("", options.Store, null, null, null, properties);
resource.Instance.Managers.AddRange(options.Store.Instance.Managers.ToArray());
return resource;
}
public static T CreateResource<T>(this IServiceProvider serviceProvider, object properties = null) where T : class, IResource
=> CreateResourceAsync<T>(serviceProvider, properties).Wait();
public static DbContextOptionsBuilder UseEsiur(this DbContextOptionsBuilder optionsBuilder,
//DbContext context,
string name = null,
@ -86,7 +93,7 @@ namespace Esiur.Stores.EntityCore
if (extension == null)
{
var store = Warehouse.New<EntityStore>(name, null, parent, manager, new { Options = optionsBuilder, DbContextProvider = dbContextProvider });
var store = Warehouse.New<EntityStore>(name, null, parent, manager, new { Options = optionsBuilder, DbContextProvider = dbContextProvider }).Wait();
extension = new EsiurExtensionOptions(store);
//store.Options = optionsBuilder;
//store.DbContext = context;
@ -113,7 +120,7 @@ namespace Esiur.Stores.EntityCore
if (extension == null)
{
var store = Warehouse.New<EntityStore>(name, null, parent, manager, new { Options = optionsBuilder, DbContextProvider = dbContextProvider });
var store = Warehouse.New<EntityStore>(name, null, parent, manager, new { Options = optionsBuilder, DbContextProvider = dbContextProvider }).Wait();
extension = new EsiurExtensionOptions(store);
//store.Options = optionsBuilder;
//store.Options = extension;

View File

@ -76,10 +76,10 @@ namespace Esiur.Stores.EntityCore
return cache;
// check if the object exists
var obj = Warehouse.New(entityType.ClrType) as EntityResource;//, "", options.Store, null, manager);
var obj = Warehouse.New(entityType.ClrType).Wait() as EntityResource;//, "", options.Store, null, manager);
//obj._PrimaryId = id;
options.Store.TypesByType[entityType.ClrType].PrimaryKey.SetValue(obj, id);
Warehouse.Put(obj, id.ToString(), options.Store, null, null, 0, manager);
Warehouse.Put(obj, id.ToString(), options.Store, null, null, 0, manager).Wait();
// obj.Instance.IntVal = id;//.Variables.Add("eid", id);

View File

@ -36,6 +36,7 @@ using System.Reflection;
using Esiur.Resource.Template;
using System.Runtime.CompilerServices;
using System.Collections;
using System.Dynamic;
namespace Esiur.Data
{
@ -239,7 +240,8 @@ namespace Esiur.Data
/// <param name="includeTypes">Whether to include each item DataType</param>
/// <param name="prependLength">If true, prepend the length as UInt32 at the beginning of the returned bytes array</param>
/// <returns>Array of bytes in the network byte order</returns>
public static byte[] ComposeStructure(Structure value, DistributedConnection connection, bool includeKeys = true, bool includeTypes = true, bool prependLength = false)
public static byte[] ComposeStructure(Structure value, DistributedConnection connection,
bool includeKeys = true, bool includeTypes = true, bool prependLength = false)
{
var rt = new BinaryList();
@ -1269,7 +1271,7 @@ namespace Esiur.Data
type = DataType.String;
else if (t == typeof(DateTime))
type = DataType.DateTime;
else if (typeof(Structure).IsAssignableFrom(t))
else if (typeof(Structure).IsAssignableFrom(t) || t == typeof(ExpandoObject))
type = DataType.Structure;
//else if (t == typeof(DistributedResource))
// type = DataType.DistributedResource;

View File

@ -533,16 +533,22 @@ namespace Esiur.Data
public static string ToHex(this byte[] ba, uint offset, uint length, string separator = " ")
{
StringBuilder hex = new StringBuilder((int)length * 2);
for (var i = offset; i < offset + length; i++)
{
hex.AppendFormat("{0:x2}", ba[i]);
if (separator != null)
hex.Append(separator);
}
if (separator == null)
separator = "";
return hex.ToString();
return string.Join(separator, ba.Skip((int)offset).Take((int)length).Select(x => x.ToString("x2")).ToArray());
//StringBuilder hex = new StringBuilder((int)length * 2);
//for (var i = offset; i < offset + length; i++)
//{
// hex.AppendFormat("{0:x2}", ba[i]);
// if (separator != null)
// hex.Append(separator);
//}
//return hex.ToString();
}
public static byte[] FromHex(string hexString, string separator = " ")

View File

@ -0,0 +1,91 @@
using Esiur.Resource;
/*
Copyright (c) 2017-2021 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Esiur.Data
{
class ResourceJsonConverter : JsonConverter<IResource>
{
public override IResource Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options)
{
return (IResource)JsonSerializer.Deserialize(ref reader,typeof(IResource), options);
}
public override void Write(
Utf8JsonWriter writer,
IResource resource,
JsonSerializerOptions options)
{
writer.WriteStartObject();
foreach (var pt in resource.Instance.Template.Properties)
{
var rt = pt.Info.GetValue(resource, null);
writer.WritePropertyName(options.PropertyNamingPolicy?.ConvertName(pt.Name) ?? pt.Name);
JsonSerializer.Serialize(writer, rt, options);
}
writer.WriteEndObject();
}
}
public class DoubleJsonConverter : JsonConverter<double>
{
public override double Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.String && reader.GetString() == "NaN")
{
return double.NaN;
}
return reader.GetDouble(); // JsonException thrown if reader.TokenType != JsonTokenType.Number
}
public override void Write(Utf8JsonWriter writer, double value, JsonSerializerOptions options)
{
if (double.IsNaN(value))
{
writer.WriteStringValue("NaN");
}
else
{
writer.WriteNumberValue(value);
}
}
}
}

View File

@ -85,6 +85,8 @@ namespace Esiur.Data
rt.dic = source.dic;
return rt;
}
public static explicit operator Structure(ExpandoObject obj) => FromDynamic(obj);
public static Structure FromDynamic(ExpandoObject obj)
{

View File

@ -1,13 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFramework>netstandard2.1</TargetFramework>
<Description>Distributed Resources Platform</Description>
<Copyright>Ahmed Kh. Zamil</Copyright>
<PackageLicenseUrl>https://github.com/Esiur/Esiur-dotnet/blob/master/LICENSE</PackageLicenseUrl>
<PackageProjectUrl>http://www.esiur.com</PackageProjectUrl>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Version>1.5.0</Version>
<Version>1.5.1</Version>
<RepositoryUrl>https://github.com/esiur/esiur-dotnet</RepositoryUrl>
<Authors>Ahmed Kh. Zamil</Authors>
<AssemblyVersion>1.3.1.0</AssemblyVersion>
@ -28,6 +28,12 @@
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Compile Remove="obj\**" />
<EmbeddedResource Remove="obj\**" />
<None Remove="obj\**" />
</ItemGroup>
<ItemGroup>
<Compile Remove="Core\AsyncReplyNon.cs" />
<Compile Remove="Core\IAsyncReply.cs" />
@ -38,7 +44,6 @@
<ItemGroup>
<Folder Include="Net\DataLink\Sources\" />
<Folder Include="obj\" />
</ItemGroup>
<ItemGroup>
@ -57,6 +62,7 @@
<PackageReference Include="System.Net.NetworkInformation" Version="4.3.0" />
<PackageReference Include="System.Net.Security" Version="4.3.2" />
<PackageReference Include="System.Reflection.Emit" Version="4.7.0" />
<PackageReference Include="System.Text.Json" Version="5.0.1" />
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" />
</ItemGroup>

View File

@ -38,6 +38,9 @@ using System.Linq;
using Esiur.Core;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text.Json;
using Esiur.Resource;
using System.Text.Json.Serialization;
namespace Esiur.Misc
{
@ -58,6 +61,30 @@ namespace Esiur.Misc
public static event LogEvent SystemLog;
public static string ToJson(this IResource resource)
{
try
{
return JsonSerializer.Serialize(resource, Global.SerializeOptions);
}catch (Exception ex)
{
Console.WriteLine(ex.ToString());
return "";
}
}
public static JsonSerializerOptions SerializeOptions = new JsonSerializerOptions
{
ReferenceHandler = ReferenceHandler.Preserve,
WriteIndented = true,
Converters =
{
new ResourceJsonConverter(),
new DoubleJsonConverter()
}
};
public static string Version { get; }= FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion;

View File

@ -29,11 +29,14 @@ using System.Text;
using Esiur.Data;
using Esiur.Core;
using System.ComponentModel;
using System.Text.Json.Serialization;
namespace Esiur.Resource
{
public delegate bool QueryFilter<T>(T value);
//[JsonConverter(typeof(ResourceJsonConverter))]
public interface IResource : IDestructible///, INotifyPropertyChanged
{

View File

@ -13,6 +13,7 @@ using Esiur.Resource.Template;
using Esiur.Security.Authority;
using Esiur.Proxy;
using Esiur.Core;
using System.Text.Json;
namespace Esiur.Resource
{
@ -20,7 +21,8 @@ namespace Esiur.Resource
{
string name;
// public int IntVal { get; set; }
// public int IntVal { get; set; }
WeakReference<IResource> resource;
IStore store;
@ -115,7 +117,7 @@ namespace Esiur.Resource
return rt;
/*
var st = new Structure();
@ -183,7 +185,7 @@ namespace Esiur.Resource
if (at != null)
if (at.Info.CanWrite)
at.Info.SetValue(res, DC.CastConvert(kv.Value, at.Info.PropertyType));
}
}
@ -426,6 +428,15 @@ namespace Esiur.Resource
return true;
}
public string ToJson()
{
IResource res;
if (resource.TryGetTarget(out res))
return JsonSerializer.Serialize(res, Global.SerializeOptions);
else
return null;
}
/// <summary>
/// Export all properties with ResourceProperty attributed as bytes array.
/// </summary>
@ -436,28 +447,18 @@ namespace Esiur.Resource
foreach (var pt in template.Properties)
{
/*
#if NETSTANDARD
var pi = resource.GetType().GetTypeInfo().GetProperty(pt.Name);
#else
var pi = resource.GetType().GetProperty(pt.Name);
#endif
*/
IResource res;
//if (pt.Serilize)
//{
IResource res;
if (resource.TryGetTarget(out res))
{
var rt = pt.Info.GetValue(res, null);// pt.Serilize ? pt.Info.GetValue(res, null) : null;
props.Add(new PropertyValue(rt, ages[pt.Index], modificationDates[pt.Index]));
}
//}
if (resource.TryGetTarget(out res))
{
var rt = pt.Info.GetValue(res, null);
props.Add(new PropertyValue(rt, ages[pt.Index], modificationDates[pt.Index]));
}
}
return props.ToArray();
}
/*
public bool Deserialize(byte[] data, uint offset, uint length)
{
@ -712,7 +713,7 @@ namespace Esiur.Resource
if (this.resource.TryGetTarget(out res))
{
//if (!(store is null))
return store.Children<T>(res, name);
return store.Children<T>(res, name);
//else
// return (res as IStore).Children<T>(res, name);
}
@ -824,14 +825,14 @@ namespace Esiur.Resource
if (this.resource.TryGetTarget(out res))
{
//return store.Applicable(res, session, action, member, inquirer);
foreach (IPermissionsManager manager in managers)
{
var r = manager.Applicable(res, session, action, member, inquirer);
if (r != Ruling.DontCare)
return r;
}
}
return Ruling.DontCare;
@ -873,14 +874,14 @@ namespace Esiur.Resource
this.template = customTemplate;
else
this.template = Warehouse.GetTemplate(resource.GetType());
// set ages
// set ages
for (byte i = 0; i < template.Properties.Length; i++)
{
ages.Add(0);
modificationDates.Add(DateTime.MinValue);
}
// connect events
Type t = ResourceProxy.GetBaseType(resource);
@ -903,9 +904,9 @@ namespace Esiur.Resource
if (evt.Info.EventHandlerType == typeof(ResourceEventHanlder))
{
// var ca = (ResourceEvent[])evt.GetCustomAttributes(typeof(ResourceEvent), true);
// if (ca.Length == 0)
// continue;
// var ca = (ResourceEvent[])evt.GetCustomAttributes(typeof(ResourceEvent), true);
// if (ca.Length == 0)
// continue;
ResourceEventHanlder proxyDelegate = (args) => EmitResourceEvent(evt.Name, args);
evt.Info.AddEventHandler(resource, proxyDelegate);
@ -920,7 +921,7 @@ namespace Esiur.Resource
CustomResourceEventHanlder proxyDelegate = (issuer, receivers, args) => EmitCustomResourceEvent(issuer, receivers, evt.Name, args);
evt.Info.AddEventHandler(resource, proxyDelegate);
}
/*
else if (evt.EventHandlerType == typeof(CustomUsersEventHanlder))
@ -959,7 +960,7 @@ namespace Esiur.Resource
//IQueryable<IResource> Children => store.GetChildren(this);
/*
* private void Children_OnRemoved(Instance parent, IResource value)
{

View File

@ -47,9 +47,9 @@ namespace Esiur.Resource
public abstract AsyncReply<bool> Trigger(ResourceTrigger trigger);
public T New(string name = null, object attributes = null, object properties = null)
public async AsyncReply<T> New(string name = null, object attributes = null, object properties = null)
{
var resource = Warehouse.New<T>(name, this, null, null, attributes, properties);
var resource = await Warehouse.New<T>(name, this, null, null, attributes, properties);
resource.Instance.Managers.AddRange(this.Instance.Managers.ToArray());
return resource;
}

View File

@ -37,6 +37,7 @@ using System.Text.RegularExpressions;
using Esiur.Misc;
using System.Collections.Concurrent;
using System.Collections;
using System.Data;
namespace Esiur.Resource
{
@ -62,7 +63,7 @@ namespace Esiur.Resource
public static event StoreConnectedEvent StoreConnected;
public static event StoreDisconnectedEvent StoreDisconnected;
public delegate IStore ProtocolInstance(string name, object properties);
public delegate AsyncReply<IStore> ProtocolInstance(string name, object properties);
public static KeyList<string, ProtocolInstance> Protocols { get; } = GetSupportedProtocols();
@ -73,7 +74,7 @@ namespace Esiur.Resource
static KeyList<string, ProtocolInstance> GetSupportedProtocols()
{
var rt = new KeyList<string, ProtocolInstance>();
rt.Add("iip", (name, props) => Warehouse.New<DistributedConnection>(name, null, null, null, props));
rt.Add("iip", async (name, attributes) => await Warehouse.New<DistributedConnection>(name, null, null, null, attributes));
return rt;
}
@ -378,68 +379,100 @@ namespace Esiur.Resource
/// </summary>
/// <param name="path"></param>
/// <returns>Resource instance.</returns>
public static AsyncReply<IResource> Get(string path, object attributes = null, IResource parent = null, IPermissionsManager manager = null)
public static async AsyncReply<IResource> Get(string path, object attributes = null, IResource parent = null, IPermissionsManager manager = null)
{
var rt = new AsyncReply<IResource>();
//var rt = new AsyncReply<IResource>();
// Should we create a new store ?
if (urlRegex.IsMatch(path))
{
//if (path.Contains("://"))
//{
var url = urlRegex.Split(path);
//var url = path.Split(new string[] { "://" }, 2, StringSplitOptions.None);
//var hostname = url[1].Split(new char[] { '/' }, 2)[0];
//var pathname = string.Join("/", url[1].Split(new char[] { '/' }).Skip(1));
if (Protocols.ContainsKey(url[1]))
{
if (!warehouseIsOpen)
await Open();
var handler = Protocols[url[1]];
var store = await handler(url[2], attributes);
var store = handler(url[2], attributes);
store.Trigger(ResourceTrigger.Open).Then(x =>
try
{
warehouseIsOpen = true;
Put(store, url[2], null, parent, null, 0, manager, attributes);
//await Put(store, url[2], null, parent, null, 0, manager, attributes);
if (url[3].Length > 0 && url[3] != "")
store.Get(url[3]).Then(r =>
{
rt.Trigger(r);
}).Error(e =>
{
Warehouse.Remove(store);
rt.TriggerError(e);
});
return await store.Get(url[3]);
else
rt.Trigger(store);
}).Error(e =>
{
rt.TriggerError(e);
//Warehouse.Remove(store);
});
return store;
}
catch (Exception ex)
{
Warehouse.Remove(store);
throw ex;
}
return rt;
}
// store.Get(url[3]).Then(r =>
// {
// rt.Trigger(r);
// }).Error(e =>
// {
// Warehouse.Remove(store);
// rt.TriggerError(e);
// });
// else
// rt.Trigger(store);
// store.Trigger(ResourceTrigger.Open).Then(x =>
// {
// warehouseIsOpen = true;
// await Put(store, url[2], null, parent, null, 0, manager, attributes);
// if (url[3].Length > 0 && url[3] != "")
// store.Get(url[3]).Then(r =>
// {
// rt.Trigger(r);
// }).Error(e =>
// {
// Warehouse.Remove(store);
// rt.TriggerError(e);
// });
// else
// rt.Trigger(store);
// }).Error(e =>
// {
// rt.TriggerError(e);
// //Warehouse.Remove(store);
// });
// return rt;
//}
}
Query(path).Then(rs =>
{
// rt.TriggerError(new Exception());
if (rs != null && rs.Length > 0)
rt.Trigger(rs.First());
else
rt.Trigger(null);
});
//await Query(path).Then(rs =>
//{
// // rt.TriggerError(new Exception());
// if (rs != null && rs.Length > 0)
// rt.Trigger(rs.First());
// else
// rt.Trigger(null);
//});
return rt;
//return rt;
var res = await Query(path);
if (res.Length == 0)
return null;
else
return res.First();
}
@ -450,7 +483,7 @@ namespace Esiur.Resource
/// <param name="name">Resource name.</param>
/// <param name="store">IStore that manages the resource. Can be null if the resource is a store.</param>
/// <param name="parent">Parent resource. if not presented the store becomes the parent for the resource.</param>
public static void Put(IResource resource, string name, IStore store = null, IResource parent = null, ResourceTemplate customTemplate = null, ulong age = 0, IPermissionsManager manager = null, object attributes = null)
public static async AsyncReply<bool> Put(IResource resource, string name, IStore store = null, IResource parent = null, ResourceTemplate customTemplate = null, ulong age = 0, IPermissionsManager manager = null, object attributes = null)
{
if (resource.Instance != null)
throw new Exception("Resource has a store.");
@ -522,13 +555,14 @@ namespace Esiur.Resource
//else
store.Put(resource);
if (!await store.Put(resource))
return false;
if (parent != null)
{
parent.Instance.Store.AddChild(parent, resource);
store.AddParent(resource, parent);
await parent.Instance.Store.AddChild(parent, resource);
await store.AddParent(resource, parent);
//store.AddChild(parent, resource);
}
@ -542,11 +576,19 @@ namespace Esiur.Resource
resources.TryAdd(resource.Instance.Id, resourceReference);
if (warehouseIsOpen)
resource.Trigger(ResourceTrigger.Initialize);
{
await resource.Trigger(ResourceTrigger.Initialize);
if (resource is IStore)
await resource.Trigger(ResourceTrigger.Open);
return true;
}
else
return true;
}
public static IResource New(Type type, string name = null, IStore store = null, IResource parent = null, IPermissionsManager manager = null, object attributes = null, object properties = null)
public static async AsyncReply<IResource> New(Type type, string name = null, IStore store = null, IResource parent = null, IPermissionsManager manager = null, object attributes = null, object properties = null)
{
type = ResourceProxy.GetProxy(type);
@ -608,16 +650,19 @@ namespace Esiur.Resource
}
if (store != null || parent != null || res is IStore)
Put(res, name, store, parent, null, 0, manager, attributes);
{
if (!await Put(res, name, store, parent, null, 0, manager, attributes))
return null;
}
return res;
}
public static T New<T>(string name, IStore store = null, IResource parent = null, IPermissionsManager manager = null, object attributes = null, object properties = null)
public static async AsyncReply<T> New<T>(string name, IStore store = null, IResource parent = null, IPermissionsManager manager = null, object attributes = null, object properties = null)
where T : IResource
{
return (T)New(typeof(T), name, store, parent, manager, attributes, properties);
return (T)(await New(typeof(T), name, store, parent, manager, attributes, properties));
}
/// <summary>