Skip to content

Instantly share code, notes, and snippets.

@galvesribeiro
Created May 4, 2018 20:56
Show Gist options
  • Save galvesribeiro/fd3d9e7996a0787f880dc864b01e75f5 to your computer and use it in GitHub Desktop.
Save galvesribeiro/fd3d9e7996a0787f880dc864b01e75f5 to your computer and use it in GitHub Desktop.
Blazor Promises
public interface IPromiseCallbackHandler
{
void SetResult(string json);
void SetError(string error);
}
public class PromiseCallbackHandler<TResult> : IPromiseCallbackHandler
{
private readonly TaskCompletionSource<TResult> _tcs;
public PromiseCallbackHandler(TaskCompletionSource<TResult> tcs)
{
this._tcs = tcs;
}
public void SetResult(string json)
{
TResult result = JsonUtil.Deserialize<TResult>(json);
this._tcs.SetResult(result);
}
public void SetError(string error)
{
var exception = new Exception(error);
this._tcs.SetException(exception);
}
}
public static class Promises
{
private const string PROXY_FUNCTION = "GP.Portal.Utils.Promises.Proxy";
private static ConcurrentDictionary<string, IPromiseCallbackHandler> _callbackHandlers =
new ConcurrentDictionary<string, IPromiseCallbackHandler>();
public static void PromiseCallback(string callbackId, string result)
{
if (_callbackHandlers.TryGetValue(callbackId, out IPromiseCallbackHandler handler))
{
handler.SetResult(result);
_callbackHandlers.TryRemove(callbackId, out IPromiseCallbackHandler _);
}
}
public static void PromiseError(string callbackId, string error)
{
if (_callbackHandlers.TryGetValue(callbackId, out IPromiseCallbackHandler handler))
{
handler.SetError(error);
_callbackHandlers.TryRemove(callbackId, out IPromiseCallbackHandler _);
}
}
public static Task<TResult> ExecuteAsync<TResult>(string fnName, object data = null)
{
var tcs = new TaskCompletionSource<TResult>();
string callbackId = Guid.NewGuid().ToString();
if (_callbackHandlers.TryAdd(callbackId, new PromiseCallbackHandler<TResult>(tcs)))
{
if (data == null)
{
RegisteredFunction.Invoke<bool>(PROXY_FUNCTION, callbackId, fnName);
}
else
{
RegisteredFunction.Invoke<bool>(PROXY_FUNCTION, callbackId, fnName, data);
}
return tcs.Task;
}
throw new Exception("An entry with the same callback id already existed, really should never happen");
}
}
const PromisesProxy = {};
const assemblyName = 'GP.Portal.Utils';
const namespace = 'GP.Portal.Utils';
const typeName = 'Promises';
const methodName = 'PromiseCallback';
const errorMethodName = 'PromiseError';
Blazor.registerFunction('GP.Portal.Utils.Promises.Proxy', (callbackId, fnName, data) => {
const callbackMethod = Blazor.platform.findMethod(
assemblyName,
namespace,
typeName,
methodName
);
const errorCallbackMethod = Blazor.platform.findMethod(
assemblyName,
namespace,
typeName,
errorMethodName
);
let promise = PromisesProxy[fnName](data);
promise.then(value => {
if (value === undefined) {
value = null;
}
const result = JSON.stringify(value);
Blazor.platform.callMethod(
callbackMethod,
null,
[
Blazor.platform.toDotNetString(callbackId),
Blazor.platform.toDotNetString(result)
]
);
}).catch(reason => {
if (!reason) {
reason = "Something went wrong";
}
const result = reason.toString();
Blazor.platform.callMethod(
errorCallbackMethod,
null,
[
Blazor.platform.toDotNetString(callbackId),
Blazor.platform.toDotNetString(result)
]
);
});
// Your function currently has to return something.
return true;
});
PromisesProxy.Test = () => {
console.log("1");
return new Promise((resolve, reject) => {
console.log("2");
setTimeout(() => {
console.log("3");
resolve("From JS!");
}, 1000);
console.log("4");
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment