-
Notifications
You must be signed in to change notification settings - Fork 285
Closed
Labels
Description
I'd like to be able to use expressions to call context.CallActivityAsync. This would provide stronger typing and remove the "magic string" for the function name.
e.g. given the following function
[FunctionName(nameof(GetMyObject))]
public async Task<MyObject> GetMyObject([ActivityTrigger] string input) { /*...*/ }You could use
context.CallActivityAsync(() => GetMyObject("Hello"))
instead of the current
context.CallActivityAsync<MyObject>(nameof(GetMyObject), "Hello")
The expression syntax could call the existing version for its implementation. A naive implementation would be something like:
Task<TResult> CallActivityAsync<TResult>(Expression<Func<TResult>> expr)
{
var body = (MethodCallExpression)expr.Body;
var functionName = body.Method.GetCustomAttributesData()
.Single(x => x.AttributeType == typeof(FunctionNameAttribute))
.ConstructorArguments[0].Value;
var triggerArgExpr = body.Method.GetParameters().Zip(body.Arguments, ValueTuple.Create)
.First(x => x.Item1.GetCustomAttribute(typeof(ActivityTriggerAttribute)) != null)
.Item2;
var arg = Expression.Lambda(triggerArgExpr).Compile().DynamicInvoke();
return CallActivityAsync<TResult>(functionName, arg);
}Some further thoughts:
- There are more efficient ways of resolving the value than
DynamicInvoke; see e.g. here. - If there are further parameters (e.g., injected
ILog) the values would be ignored. - A Roslyn Analyzer could check for the following:
- The method called is an activity with a function name (required / error level)
- The expression is a
MethodCallExpression(required / error level) - All non-ActivityTrigger parameters are their default values (optional / warning level)
- This works for static activity functions and activity functions in the current class. In a different class, you'd need something with a signature like
Task<TResult> CallActivityAsync<TClass, TResult>(Expression<Func<TClass, TResult>> expr), which would then be called likecontext.CallActivityAsync<DiffClass, MyObject>(c => c.GetMyObject("Hello")).- Note how the expression parameter would not be allowed to reference
c.
- Note how the expression parameter would not be allowed to reference
Of course, you could have Task-returning and CallActivityWithRetryAsync overloads as well.
Reactions are currently unavailable