-
-
Notifications
You must be signed in to change notification settings - Fork 341
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Possible to Support Async members in RenderAsync? #368
Labels
Comments
Here's the approach I've come up with, but open to suggestions if there's a better approach using System;
using System.Threading.Tasks;
using Scriban;
using Scriban.Runtime;
using Scriban.Syntax;
namespace ScribanAsync
{
public class TemplateContextAsync : TemplateContext
{
public override async ValueTask<object> EvaluateAsync(ScriptNode scriptNode, bool aliasReturnedFunction)
{
// base implementation
var value = base.EvaluateAsync(scriptNode, aliasReturnedFunction);
// is the object also a Task? If so, await its value
if ((await value) is Task valueTask)
{
// TODO: Is there an alternative to using dynamic?
// TResult of Task<TResult> is unknown here.
var result = await (dynamic)valueTask;
// return a ValueTask of the awaited value
return new ValueTask<object>(result);
}
// object is not a Task, just return the ValueTask<object> as usual
return value;
}
}
class Program
{
static async Task Main(string[] args)
{
var template = "Hello {{ a }} | {{ b }} | {{ c }}";
var data = new
{
a = "World",
b = Task.FromResult(42),
c = Task.Run(async () => { await Task.Delay(5000); return "Thanks for waiting"; })
};
// Current approach
// > Hello World | System.Threading.Tasks.Task`1[System.Int32] | System.Threading.Tasks.UnwrapPromise`1[System.String]
var result1 = await Template.Parse(template).RenderAsync(data);
Console.WriteLine(result1);
// New approach
// > Hello World | 42 | Thanks for waiting
var scriptObject = new ScriptObject();
scriptObject.Import(data);
var context = new TemplateContextAsync();
context.PushGlobal(scriptObject);
var result2 = await Template.Parse(template).RenderAsync(context);
Console.WriteLine(result2);
context.PopGlobal();
}
}
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I have some Async members in an object that I would like to render with RenderAsync.
For example:
However, if I send this data to
RenderAsync
, value remains aTask<int>
— it doesn't get awaited to its underlying value:Of course, it wouldn't make sense to await Tasks in
Render
, but forRenderAsync
it would be useful to await any Task objects and display their result values (i.e., "Hello 42" in the above example)Any thoughts on how to best accomplish this? Am I missing some configuration setting that enables this?
The text was updated successfully, but these errors were encountered: