chore: LCEngineRequestContext insteads of Request.
parent
367c57b00f
commit
4f0d7e9e9f
|
@ -0,0 +1,17 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace LeanCloud.Engine {
|
||||||
|
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)]
|
||||||
|
public class LCEngineFunctionParamAttribute : Attribute {
|
||||||
|
public string ParamName {
|
||||||
|
get;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LCEngineFunctionParamAttribute(string paramName) {
|
||||||
|
if (string.IsNullOrEmpty(paramName)) {
|
||||||
|
throw new ArgumentNullException(nameof(paramName));
|
||||||
|
}
|
||||||
|
ParamName = paramName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,9 +25,9 @@ namespace LeanCloud.Engine {
|
||||||
|
|
||||||
string classHookName = GetClassHookName(className, hookName);
|
string classHookName = GetClassHookName(className, hookName);
|
||||||
if (ClassHooks.TryGetValue(classHookName, out MethodInfo mi)) {
|
if (ClassHooks.TryGetValue(classHookName, out MethodInfo mi)) {
|
||||||
Dictionary<string, object> dict = LCEngine.Decode(body);
|
Dictionary<string, object> data = LCEngine.Decode(body);
|
||||||
|
|
||||||
LCObjectData objectData = LCObjectData.Decode(dict["object"] as Dictionary<string, object>);
|
LCObjectData objectData = LCObjectData.Decode(data["object"] as Dictionary<string, object>);
|
||||||
objectData.ClassName = className;
|
objectData.ClassName = className;
|
||||||
LCObject obj = LCObject.Create(className);
|
LCObject obj = LCObject.Create(className);
|
||||||
obj.Merge(objectData);
|
obj.Merge(objectData);
|
||||||
|
@ -39,24 +39,22 @@ namespace LeanCloud.Engine {
|
||||||
obj.DisableAfterHook();
|
obj.DisableAfterHook();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LCEngine.InitRequestContext(Request);
|
||||||
|
|
||||||
LCUser user = null;
|
LCUser user = null;
|
||||||
if (dict.TryGetValue("user", out object userObj) &&
|
if (data.TryGetValue("user", out object userObj) &&
|
||||||
userObj != null) {
|
userObj != null) {
|
||||||
user = new LCUser();
|
user = new LCUser();
|
||||||
user.Merge(LCObjectData.Decode(userObj as Dictionary<string, object>));
|
user.Merge(LCObjectData.Decode(userObj as Dictionary<string, object>));
|
||||||
|
LCEngineRequestContext.CurrentUser = user;
|
||||||
}
|
}
|
||||||
|
|
||||||
LCClassHookRequest req = new LCClassHookRequest {
|
LCObject result = await LCEngine.Invoke(mi, new object[] { obj }) as LCObject;
|
||||||
Object = obj,
|
|
||||||
CurrentUser = user
|
|
||||||
};
|
|
||||||
|
|
||||||
LCObject result = await LCEngine.Invoke(mi, req) as LCObject;
|
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
return LCCloud.Encode(result);
|
return LCCloud.Encode(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return default;
|
return body;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return StatusCode(500, e.Message);
|
return StatusCode(500, e.Message);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,11 +3,11 @@ using System.Text.Json;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Linq;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.Extensions.Primitives;
|
|
||||||
using Microsoft.AspNetCore.Cors;
|
using Microsoft.AspNetCore.Cors;
|
||||||
using LeanCloud.Storage.Internal.Codec;
|
|
||||||
using LeanCloud.Storage;
|
using LeanCloud.Storage;
|
||||||
|
using LeanCloud.Storage.Internal.Codec;
|
||||||
|
|
||||||
namespace LeanCloud.Engine {
|
namespace LeanCloud.Engine {
|
||||||
[ApiController]
|
[ApiController]
|
||||||
|
@ -32,26 +32,18 @@ namespace LeanCloud.Engine {
|
||||||
LCLogger.Debug(body.ToString());
|
LCLogger.Debug(body.ToString());
|
||||||
|
|
||||||
if (Functions.TryGetValue(funcName, out MethodInfo mi)) {
|
if (Functions.TryGetValue(funcName, out MethodInfo mi)) {
|
||||||
LCUser currentUser = null;
|
LCEngine.InitRequestContext(Request);
|
||||||
if (Request.Headers.TryGetValue("x-lc-session", out StringValues session)) {
|
|
||||||
currentUser = await LCUser.BecomeWithSessionToken(session);
|
object[] ps = ParseParameters(mi, body);
|
||||||
}
|
object result = await LCEngine.Invoke(mi, ps.ToArray());
|
||||||
LCCloudFunctionRequest req = new LCCloudFunctionRequest {
|
|
||||||
Meta = new LCCloudFunctionRequestMeta {
|
|
||||||
RemoteAddress = LCEngine.GetIP(Request)
|
|
||||||
},
|
|
||||||
Params = LCEngine.Decode(body),
|
|
||||||
SessionToken = session.ToString(),
|
|
||||||
User = currentUser
|
|
||||||
};
|
|
||||||
object result = await LCEngine.Invoke(mi, req);
|
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
return new Dictionary<string, object> {
|
return new Dictionary<string, object> {
|
||||||
{ "result", result }
|
{ "result", result }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return default;
|
return body;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return StatusCode(500, e.Message);
|
return StatusCode(500, e.Message);
|
||||||
}
|
}
|
||||||
|
@ -64,29 +56,44 @@ namespace LeanCloud.Engine {
|
||||||
LCLogger.Debug(body.ToString());
|
LCLogger.Debug(body.ToString());
|
||||||
|
|
||||||
if (Functions.TryGetValue(funcName, out MethodInfo mi)) {
|
if (Functions.TryGetValue(funcName, out MethodInfo mi)) {
|
||||||
LCUser currentUser = null;
|
LCEngine.InitRequestContext(Request);
|
||||||
if (Request.Headers.TryGetValue("x-lc-session", out StringValues session)) {
|
|
||||||
currentUser = await LCUser.BecomeWithSessionToken(session);
|
object[] ps = ParseParameters(mi, body);
|
||||||
}
|
object result = await LCEngine.Invoke(mi, ps);
|
||||||
LCCloudRPCRequest req = new LCCloudRPCRequest {
|
|
||||||
Meta = new LCCloudFunctionRequestMeta {
|
|
||||||
RemoteAddress = LCEngine.GetIP(Request)
|
|
||||||
},
|
|
||||||
Params = LCDecoder.Decode(LCEngine.Decode(body)),
|
|
||||||
SessionToken = session.ToString(),
|
|
||||||
User = currentUser
|
|
||||||
};
|
|
||||||
object result = await LCEngine.Invoke(mi, req);
|
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
return new Dictionary<string, object> {
|
return new Dictionary<string, object> {
|
||||||
{ "result", LCCloud.Encode(result) }
|
{ "result", LCCloud.Encode(result) }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return default;
|
return body;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return StatusCode(500, e.Message);
|
return StatusCode(500, e.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static object[] ParseParameters(MethodInfo mi, JsonElement body) {
|
||||||
|
Dictionary<string, object> parameters = LCEngine.Decode(body);
|
||||||
|
List<object> ps = new List<object>();
|
||||||
|
|
||||||
|
if (mi.GetParameters().Length > 0) {
|
||||||
|
if (Array.Exists(mi.GetParameters(),
|
||||||
|
p => p.GetCustomAttribute<LCEngineFunctionParamAttribute>() != null)) {
|
||||||
|
// 如果包含 LCEngineFunctionParamAttribute 的参数,则按照配对方式传递参数
|
||||||
|
foreach (ParameterInfo pi in mi.GetParameters()) {
|
||||||
|
LCEngineFunctionParamAttribute attr = pi.GetCustomAttribute<LCEngineFunctionParamAttribute>();
|
||||||
|
if (attr != null) {
|
||||||
|
string paramName = attr.ParamName;
|
||||||
|
ps.Add(parameters[paramName]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ps.Add(LCDecoder.Decode(LCEngine.Decode(body)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ps.ToArray();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,10 +24,12 @@ namespace LeanCloud.Engine {
|
||||||
LCEngine.CheckHookKey(Request);
|
LCEngine.CheckHookKey(Request);
|
||||||
|
|
||||||
if (UserHooks.TryGetValue(LCEngine.OnSMSVerified, out MethodInfo mi)) {
|
if (UserHooks.TryGetValue(LCEngine.OnSMSVerified, out MethodInfo mi)) {
|
||||||
|
LCEngine.InitRequestContext(Request);
|
||||||
|
|
||||||
Dictionary<string, object> dict = LCEngine.Decode(body);
|
Dictionary<string, object> dict = LCEngine.Decode(body);
|
||||||
return await Invoke(mi, dict);
|
return await Invoke(mi, dict);
|
||||||
}
|
}
|
||||||
return default;
|
return body;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return StatusCode(500, e.Message);
|
return StatusCode(500, e.Message);
|
||||||
}
|
}
|
||||||
|
@ -42,10 +44,12 @@ namespace LeanCloud.Engine {
|
||||||
LCEngine.CheckHookKey(Request);
|
LCEngine.CheckHookKey(Request);
|
||||||
|
|
||||||
if (UserHooks.TryGetValue(LCEngine.OnEmailVerified, out MethodInfo mi)) {
|
if (UserHooks.TryGetValue(LCEngine.OnEmailVerified, out MethodInfo mi)) {
|
||||||
|
LCEngine.InitRequestContext(Request);
|
||||||
|
|
||||||
Dictionary<string, object> dict = LCEngine.Decode(body);
|
Dictionary<string, object> dict = LCEngine.Decode(body);
|
||||||
return await Invoke(mi, dict);
|
return await Invoke(mi, dict);
|
||||||
}
|
}
|
||||||
return default;
|
return body;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return StatusCode(500, e.Message);
|
return StatusCode(500, e.Message);
|
||||||
}
|
}
|
||||||
|
@ -60,10 +64,12 @@ namespace LeanCloud.Engine {
|
||||||
LCEngine.CheckHookKey(Request);
|
LCEngine.CheckHookKey(Request);
|
||||||
|
|
||||||
if (UserHooks.TryGetValue(LCEngine.OnLogin, out MethodInfo mi)) {
|
if (UserHooks.TryGetValue(LCEngine.OnLogin, out MethodInfo mi)) {
|
||||||
|
LCEngine.InitRequestContext(Request);
|
||||||
|
|
||||||
Dictionary<string, object> dict = LCEngine.Decode(body);
|
Dictionary<string, object> dict = LCEngine.Decode(body);
|
||||||
return await Invoke(mi, dict);
|
return await Invoke(mi, dict);
|
||||||
}
|
}
|
||||||
return default;
|
return body;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return StatusCode(500, e.Message);
|
return StatusCode(500, e.Message);
|
||||||
}
|
}
|
||||||
|
@ -73,14 +79,10 @@ namespace LeanCloud.Engine {
|
||||||
LCObjectData objectData = LCObjectData.Decode(dict["object"] as Dictionary<string, object>);
|
LCObjectData objectData = LCObjectData.Decode(dict["object"] as Dictionary<string, object>);
|
||||||
objectData.ClassName = "_User";
|
objectData.ClassName = "_User";
|
||||||
|
|
||||||
LCObject obj = LCObject.Create("_User");
|
LCObject user = LCObject.Create("_User");
|
||||||
obj.Merge(objectData);
|
user.Merge(objectData);
|
||||||
|
|
||||||
LCUserHookRequest req = new LCUserHookRequest {
|
return await LCEngine.Invoke(mi, new object[] { user }) as LCObject;
|
||||||
CurrentUser = obj as LCUser
|
|
||||||
};
|
|
||||||
|
|
||||||
return await LCEngine.Invoke(mi, req) as LCObject;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,9 @@ using System.Text.Json;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Microsoft.Extensions.Primitives;
|
using Microsoft.Extensions.Primitives;
|
||||||
using LeanCloud.Common;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using LeanCloud.Common;
|
||||||
|
using LeanCloud.Storage;
|
||||||
|
|
||||||
namespace LeanCloud.Engine {
|
namespace LeanCloud.Engine {
|
||||||
public class LCEngine {
|
public class LCEngine {
|
||||||
|
@ -202,6 +203,27 @@ namespace LeanCloud.Engine {
|
||||||
LCLogger.Debug($"{key} : {Environment.GetEnvironmentVariable(key)}");
|
LCLogger.Debug($"{key} : {Environment.GetEnvironmentVariable(key)}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static async Task<object> Invoke(MethodInfo mi, object[] parameters) {
|
||||||
|
try {
|
||||||
|
if (mi.ReturnType == typeof(Task) ||
|
||||||
|
(mi.ReturnType.IsGenericType && mi.ReturnType.GetGenericTypeDefinition() == typeof(Task<>))) {
|
||||||
|
Task task = mi.Invoke(null, parameters) as Task;
|
||||||
|
await task;
|
||||||
|
return task.GetType().GetProperty("Result")?.GetValue(task);
|
||||||
|
}
|
||||||
|
return mi.Invoke(null, parameters);
|
||||||
|
} catch (TargetInvocationException e) {
|
||||||
|
Exception ex = e.InnerException;
|
||||||
|
if (ex is LCException lcEx) {
|
||||||
|
throw new Exception(JsonConvert.SerializeObject(new Dictionary<string, object> {
|
||||||
|
{ "code", lcEx.Code },
|
||||||
|
{ "message", lcEx.Message }
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal static async Task<object> Invoke(MethodInfo mi, object request) {
|
internal static async Task<object> Invoke(MethodInfo mi, object request) {
|
||||||
try {
|
try {
|
||||||
object[] ps = null;
|
object[] ps = null;
|
||||||
|
@ -234,6 +256,16 @@ namespace LeanCloud.Engine {
|
||||||
return dict;
|
return dict;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static void InitRequestContext(HttpRequest request) {
|
||||||
|
LCEngineRequestContext.Init();
|
||||||
|
|
||||||
|
LCEngineRequestContext.RemoteAddress = GetIP(request);
|
||||||
|
|
||||||
|
if (request.Headers.TryGetValue("x-lc-session", out StringValues session)) {
|
||||||
|
LCEngineRequestContext.SessionToken = session;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal static string GetIP(HttpRequest request) {
|
internal static string GetIP(HttpRequest request) {
|
||||||
if (request.Headers.TryGetValue("x-real-ip", out StringValues ip)) {
|
if (request.Headers.TryGetValue("x-real-ip", out StringValues ip)) {
|
||||||
return ip.ToString();
|
return ip.ToString();
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
using LeanCloud.Storage;
|
||||||
|
|
||||||
|
namespace LeanCloud.Engine {
|
||||||
|
public class LCEngineRequestContext {
|
||||||
|
public const string RemoteAddressKey = "remoteAddressKey";
|
||||||
|
public const string SessionTokenKey = "sessionToken";
|
||||||
|
public const string CurrentUserKey = "currentUser";
|
||||||
|
|
||||||
|
private static ThreadLocal<Dictionary<string, object>> requestContext = new ThreadLocal<Dictionary<string, object>>();
|
||||||
|
|
||||||
|
public static void Init() {
|
||||||
|
if (requestContext.IsValueCreated) {
|
||||||
|
requestContext.Value.Clear();
|
||||||
|
}
|
||||||
|
requestContext.Value = new Dictionary<string, object>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Set(string key, object value) {
|
||||||
|
if (!requestContext.IsValueCreated) {
|
||||||
|
requestContext.Value = new Dictionary<string, object>();
|
||||||
|
}
|
||||||
|
requestContext.Value[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static object Get(string key) {
|
||||||
|
if (!requestContext.IsValueCreated) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return requestContext.Value[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string RemoteAddress {
|
||||||
|
get {
|
||||||
|
object remoteAddress = Get(RemoteAddressKey);
|
||||||
|
if (remoteAddress != null) {
|
||||||
|
return remoteAddress as string;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
Set(RemoteAddressKey, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string SessionToken {
|
||||||
|
get {
|
||||||
|
object sessionToken = Get(SessionTokenKey);
|
||||||
|
if (sessionToken != null) {
|
||||||
|
return sessionToken as string;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
Set(SessionTokenKey, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LCUser CurrentUser {
|
||||||
|
get {
|
||||||
|
object currentUser = Get(CurrentUserKey);
|
||||||
|
if (currentUser != null) {
|
||||||
|
return currentUser as LCUser;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
Set(CurrentUserKey, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,13 +0,0 @@
|
||||||
using LeanCloud.Storage;
|
|
||||||
|
|
||||||
namespace LeanCloud.Engine {
|
|
||||||
public class LCClassHookRequest {
|
|
||||||
public LCObject Object {
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LCUser CurrentUser {
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using LeanCloud.Storage;
|
|
||||||
|
|
||||||
namespace LeanCloud.Engine {
|
|
||||||
public class LCCloudFunctionRequestMeta {
|
|
||||||
public string RemoteAddress {
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class LCCloudFunctionRequest {
|
|
||||||
public LCCloudFunctionRequestMeta Meta {
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Dictionary<string, object> Params {
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LCUser User {
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string SessionToken {
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
using LeanCloud.Storage;
|
|
||||||
|
|
||||||
namespace LeanCloud.Engine {
|
|
||||||
public class LCCloudRPCRequest {
|
|
||||||
public LCCloudFunctionRequestMeta Meta {
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public object Params {
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LCUser User {
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string SessionToken {
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
using LeanCloud.Storage;
|
|
||||||
|
|
||||||
namespace LeanCloud.Engine {
|
|
||||||
public class LCUserHookRequest {
|
|
||||||
public LCUser CurrentUser {
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -10,7 +10,8 @@ namespace Storage.Test {
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void SetUp() {
|
public void SetUp() {
|
||||||
LCLogger.LogDelegate += Utils.Print;
|
LCLogger.LogDelegate += Utils.Print;
|
||||||
LCApplication.Initialize("ikGGdRE2YcVOemAaRbgp1xGJ-gzGzoHsz", "NUKmuRbdAhg1vrb2wexYo1jo", "https://ikggdre2.lc-cn-n1-shared.com");
|
//LCApplication.Initialize("ikGGdRE2YcVOemAaRbgp1xGJ-gzGzoHsz", "NUKmuRbdAhg1vrb2wexYo1jo", "https://ikggdre2.lc-cn-n1-shared.com");
|
||||||
|
LCApplication.Initialize("8ijVI3gBAnPGynW0rVfh5gHP-gzGzoHsz", "265r8JSHhNYpV0qIJBvUWrQY", "https://8ijvi3gb.lc-cn-n1-shared.com");
|
||||||
}
|
}
|
||||||
|
|
||||||
[TearDown]
|
[TearDown]
|
||||||
|
@ -24,7 +25,7 @@ namespace Storage.Test {
|
||||||
{ "name", "world" }
|
{ "name", "world" }
|
||||||
});
|
});
|
||||||
TestContext.WriteLine(response["result"]);
|
TestContext.WriteLine(response["result"]);
|
||||||
Assert.AreEqual(response["result"], "hello, world");
|
Assert.AreEqual(response["result"], "Hello, world!");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -41,5 +42,35 @@ namespace Storage.Test {
|
||||||
Assert.NotNull(item.ObjectId);
|
Assert.NotNull(item.ObjectId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task RPCObject() {
|
||||||
|
LCQuery<LCObject> query = new LCQuery<LCObject>("Todo");
|
||||||
|
LCObject todo = await query.Get("6052cd87b725a143ea83dbf8");
|
||||||
|
object result = await LCCloud.RPC("getTodo", todo);
|
||||||
|
LCObject obj = result as LCObject;
|
||||||
|
TestContext.WriteLine(obj.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task RPCObjects() {
|
||||||
|
Dictionary<string, object> parameters = new Dictionary<string, object> {
|
||||||
|
{ "limit", 20 }
|
||||||
|
};
|
||||||
|
List<object> result = await LCCloud.RPC("getTodos", parameters) as List<object>;
|
||||||
|
IEnumerable<LCObject> todos = result.Cast<LCObject>();
|
||||||
|
foreach (LCObject todo in todos) {
|
||||||
|
TestContext.WriteLine(todo.ObjectId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task RPCObjectMap() {
|
||||||
|
Dictionary<string, object> result = await LCCloud.RPC("getTodoMap") as Dictionary<string, object>;
|
||||||
|
foreach (KeyValuePair<string, object> kv in result) {
|
||||||
|
LCObject todo = kv.Value as LCObject;
|
||||||
|
TestContext.WriteLine(todo.ObjectId);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,15 +55,23 @@ namespace LeanCloud.Storage {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static object Encode(object parameters) {
|
public static object Encode(object parameters) {
|
||||||
|
if (parameters == null) {
|
||||||
|
return new Dictionary<string, object>();
|
||||||
|
}
|
||||||
|
|
||||||
if (parameters is LCObject lcObj) {
|
if (parameters is LCObject lcObj) {
|
||||||
return EncodeLCObject(lcObj);
|
return EncodeLCObject(lcObj);
|
||||||
} else if (parameters is IList<LCObject> list) {
|
}
|
||||||
|
|
||||||
|
if (parameters is IList<LCObject> list) {
|
||||||
List<object> l = new List<object>();
|
List<object> l = new List<object>();
|
||||||
foreach (LCObject obj in list) {
|
foreach (LCObject obj in list) {
|
||||||
l.Add(EncodeLCObject(obj));
|
l.Add(EncodeLCObject(obj));
|
||||||
}
|
}
|
||||||
return l;
|
return l;
|
||||||
} else if (parameters is IDictionary<string, LCObject> dict) {
|
}
|
||||||
|
|
||||||
|
if (parameters is IDictionary<string, LCObject> dict) {
|
||||||
Dictionary<string, object> d = new Dictionary<string, object>();
|
Dictionary<string, object> d = new Dictionary<string, object>();
|
||||||
foreach (KeyValuePair<string, LCObject> item in dict) {
|
foreach (KeyValuePair<string, LCObject> item in dict) {
|
||||||
d[item.Key] = EncodeLCObject(item.Value);
|
d[item.Key] = EncodeLCObject(item.Value);
|
||||||
|
@ -75,9 +83,11 @@ namespace LeanCloud.Storage {
|
||||||
}
|
}
|
||||||
|
|
||||||
static object EncodeLCObject(LCObject obj) {
|
static object EncodeLCObject(LCObject obj) {
|
||||||
obj.ApplyCustomProperties();
|
|
||||||
Dictionary<string, object> dict = LCObjectData.Encode(obj.data);
|
Dictionary<string, object> dict = LCObjectData.Encode(obj.data);
|
||||||
dict["__type"] = "Object";
|
dict["__type"] = "Object";
|
||||||
|
foreach (KeyValuePair<string, object> kv in obj.estimatedData) {
|
||||||
|
dict[kv.Key] = kv.Value;
|
||||||
|
}
|
||||||
return dict;
|
return dict;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,13 +46,15 @@ namespace LeanCloud.Storage {
|
||||||
ApplyOperation(IgnoreHooksKey, op);
|
ApplyOperation(IgnoreHooksKey, op);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReadOnlyCollection<string> UpdatedKeys {
|
public ReadOnlyCollection<string> GetUpdatedKeys() {
|
||||||
get {
|
if (this["_updatedKeys"] == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return (this["_updatedKeys"] as List<object>)
|
return (this["_updatedKeys"] as List<object>)
|
||||||
.Cast<string>()
|
.Cast<string>()
|
||||||
.ToList()
|
.ToList()
|
||||||
.AsReadOnly();
|
.AsReadOnly();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -494,7 +494,7 @@ namespace LeanCloud.Storage {
|
||||||
data.CreatedAt = objectData.CreatedAt != null ? objectData.CreatedAt : data.CreatedAt;
|
data.CreatedAt = objectData.CreatedAt != null ? objectData.CreatedAt : data.CreatedAt;
|
||||||
data.UpdatedAt = objectData.UpdatedAt != null ? objectData.UpdatedAt : data.UpdatedAt;
|
data.UpdatedAt = objectData.UpdatedAt != null ? objectData.UpdatedAt : data.UpdatedAt;
|
||||||
// 先将本地的预估数据直接替换
|
// 先将本地的预估数据直接替换
|
||||||
ApplyCustomProperties();
|
data.CustomPropertyDict = estimatedData;
|
||||||
// 再将服务端的数据覆盖
|
// 再将服务端的数据覆盖
|
||||||
foreach (KeyValuePair<string, object> kv in objectData.CustomPropertyDict) {
|
foreach (KeyValuePair<string, object> kv in objectData.CustomPropertyDict) {
|
||||||
string key = kv.Key;
|
string key = kv.Key;
|
||||||
|
@ -509,10 +509,6 @@ namespace LeanCloud.Storage {
|
||||||
isNew = false;
|
isNew = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ApplyCustomProperties() {
|
|
||||||
data.CustomPropertyDict = estimatedData;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RebuildEstimatedData() {
|
void RebuildEstimatedData() {
|
||||||
estimatedData = new Dictionary<string, object>();
|
estimatedData = new Dictionary<string, object>();
|
||||||
foreach (KeyValuePair<string, object> kv in data.CustomPropertyDict) {
|
foreach (KeyValuePair<string, object> kv in data.CustomPropertyDict) {
|
||||||
|
|
Loading…
Reference in New Issue