docs/decisions/0003-support-multiple-native-function-args.md
Move native functions closer to a normal C# experience.
Example
Before:
[SKFunction("Adds value to a value")]
[SKFunctionName("Add")]
[SKFunctionInput(Description = "The value to add")]
[SKFunctionContextParameter(Name = "Amount", Description = "Amount to add")]
public Task<string> AddAsync(string initialValueText, SKContext context)
{
if (!int.TryParse(initialValueText, NumberStyles.Any, CultureInfo.InvariantCulture, out var initialValue))
{
return Task.FromException<string>(new ArgumentOutOfRangeException(
nameof(initialValueText), initialValueText, "Initial value provided is not in numeric format"));
}
string contextAmount = context["Amount"];
if (!int.TryParse(contextAmount, NumberStyles.Any, CultureInfo.InvariantCulture, out var amount))
{
return Task.FromException<string>(new ArgumentOutOfRangeException(
nameof(context), contextAmount, "Context amount provided is not in numeric format"));
}
var result = initialValue + amount;
return Task.FromResult(result.ToString(CultureInfo.InvariantCulture));
}
After:
[SKFunction, Description("Adds an amount to a value")]
public int Add(
[Description("The value to add")] int value,
[Description("Amount to add")] int amount) =>
value + amount;
Example
Before:
[SKFunction("Wait a given amount of seconds")]
[SKFunctionName("Seconds")]
[SKFunctionInput(DefaultValue = "0", Description = "The number of seconds to wait")]
public async Task SecondsAsync(string secondsText)
{
if (!decimal.TryParse(secondsText, NumberStyles.Any, CultureInfo.InvariantCulture, out var seconds))
{
throw new ArgumentException("Seconds provided is not in numeric format", nameof(secondsText));
}
var milliseconds = seconds * 1000;
milliseconds = (milliseconds > 0) ? milliseconds : 0;
await this._waitProvider.DelayAsync((int)milliseconds).ConfigureAwait(false);
}
After:
[SKFunction, Description("Wait a given amount of seconds")]
public async Task SecondsAsync([Description("The number of seconds to wait")] decimal seconds)
{
var milliseconds = seconds * 1000;
milliseconds = (milliseconds > 0) ? milliseconds : 0;
await this._waitProvider.DelayAsync((int)milliseconds).ConfigureAwait(false);
}
Example
Before:
[SKFunction("Add an event to my calendar.")]
[SKFunctionInput(Description = "Event subject")]
[SKFunctionContextParameter(Name = Parameters.Start, Description = "Event start date/time as DateTimeOffset")]
[SKFunctionContextParameter(Name = Parameters.End, Description = "Event end date/time as DateTimeOffset")]
[SKFunctionContextParameter(Name = Parameters.Location, Description = "Event location (optional)")]
[SKFunctionContextParameter(Name = Parameters.Content, Description = "Event content/body (optional)")]
[SKFunctionContextParameter(Name = Parameters.Attendees, Description = "Event attendees, separated by ',' or ';'.")]
public async Task AddEventAsync(string subject, SKContext context)
{
ContextVariables variables = context.Variables;
if (string.IsNullOrWhiteSpace(subject))
{
context.Fail("Missing variables input to use as event subject.");
return;
}
if (!variables.TryGetValue(Parameters.Start, out string? start))
{
context.Fail($"Missing variable {Parameters.Start}.");
return;
}
if (!variables.TryGetValue(Parameters.End, out string? end))
{
context.Fail($"Missing variable {Parameters.End}.");
return;
}
CalendarEvent calendarEvent = new()
{
Subject = variables.Input,
Start = DateTimeOffset.Parse(start, CultureInfo.InvariantCulture.DateTimeFormat),
End = DateTimeOffset.Parse(end, CultureInfo.InvariantCulture.DateTimeFormat)
};
if (variables.TryGetValue(Parameters.Location, out string? location))
{
calendarEvent.Location = location;
}
if (variables.TryGetValue(Parameters.Content, out string? content))
{
calendarEvent.Content = content;
}
if (variables.TryGetValue(Parameters.Attendees, out string? attendees))
{
calendarEvent.Attendees = attendees.Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries);
}
this._logger.LogInformation("Adding calendar event '{0}'", calendarEvent.Subject);
await this._connector.AddEventAsync(calendarEvent).ConfigureAwait(false);
}
After:
[SKFunction, Description("Add an event to my calendar.")]
public async Task AddEventAsync(
[Description("Event subject"), SKName("input")] string subject,
[Description("Event start date/time as DateTimeOffset")] DateTimeOffset start,
[Description("Event end date/time as DateTimeOffset")] DateTimeOffset end,
[Description("Event location (optional)")] string? location = null,
[Description("Event content/body (optional)")] string? content = null,
[Description("Event attendees, separated by ',' or ';'.")] string? attendees = null)
{
if (string.IsNullOrWhiteSpace(subject))
{
throw new ArgumentException($"{nameof(subject)} variable was null or whitespace", nameof(subject));
}
CalendarEvent calendarEvent = new()
{
Subject = subject,
Start = start,
End = end,
Location = location,
Content = content,
Attendees = attendees is not null ? attendees.Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries) : Enumerable.Empty<string>(),
};
this._logger.LogInformation("Adding calendar event '{0}'", calendarEvent.Subject);
await this._connector.AddEventAsync(calendarEvent).ConfigureAwait(false);
}