Skip to content

Support collection of model-type bindings for out-of-proc workers #8948

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

Merged
merged 15 commits into from
Jan 10, 2023
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ public static ValueTask<TypedData> ToRpc(this object value, ILogger logger, Grpc
string str => new TypedData() { String = str },
double dbl => new TypedData() { Double = dbl },
ParameterBindingData bindingData => bindingData.ToModelBindingData(),
ParameterBindingData[] bindingDataArray => bindingDataArray.ToModelBindingDataArray(),
byte[][] arrBytes when IsTypedDataCollectionSupported(capabilities) => arrBytes.ToRpcByteArray(),
string[] arrStr when IsTypedDataCollectionSupported(capabilities) => arrStr.ToRpcStringArray(
ShouldIncludeEmptyEntriesInMessagePayload(capabilities)),
Expand Down Expand Up @@ -84,6 +85,21 @@ internal static TypedData ToModelBindingData(this ParameterBindingData data)
return typedData;
}

internal static TypedData ToModelBindingDataArray(this ParameterBindingData[] dataArray)
{
var collectionModelBindingData = new CollectionModelBindingData();

foreach (ParameterBindingData element in dataArray)
{
if (element != null)
{
collectionModelBindingData.ModelBindingData.Add(element.ToModelBindingData().ModelBindingData);
}
}

return new TypedData() { CollectionModelBindingData = collectionModelBindingData };
}

internal static async Task<TypedData> ToRpcHttp(this HttpRequest request, ILogger logger, GrpcCapabilities capabilities)
{
var http = new RpcHttp()
Expand Down
4 changes: 4 additions & 0 deletions src/WebJobs.Script/Binding/ExtensionBinding.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ public override async Task BindAsync(BindingContext context)
{
await BindStringAsync(context);
}
else if (_binding.DefaultType == typeof(ParameterBindingData[]))
{
await BindCollectionAsync<ParameterBindingData>(context);
}
else if (_binding.DefaultType == typeof(ParameterBindingData))
{
await BindParameterBindingDataAsync(context);
Expand Down
7 changes: 7 additions & 0 deletions src/WebJobs.Script/Binding/FunctionBinding.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Collections.ObjectModel;
using System.Dynamic;
using System.IO;
using System.Linq;
using System.Reflection.Emit;
using System.Text;
using System.Threading.Tasks;
Expand Down Expand Up @@ -221,6 +222,12 @@ internal static async Task BindStringAsync(BindingContext context)
context.Value = str;
}

internal static async Task BindCollectionAsync<T>(BindingContext context)
{
T[] bindingList = await context.Binder.BindAsync<T[]>(context.Attributes);
context.Value = bindingList;
}

internal static async Task BindParameterBindingDataAsync(BindingContext context)
{
var parameterBindingData = await context.Binder.BindAsync<ParameterBindingData>(context.Attributes);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -711,5 +711,54 @@ public void ToModelBindingData_Creates_Valid_BindingData()

Assert.Equal(typedData.ModelBindingData, returned_typedata.ModelBindingData);
}

[Fact]
public void ToModelBindingDataArray_Creates_Valid_BindingData()
{
var logger = MockNullLoggerFactory.CreateLogger();
var capabilities = new GrpcCapabilities(logger);

var binaryData = new BinaryData("hello world");
var parameterBindingData = new ParameterBindingData("1.0", "CosmosDB", binaryData, "application/json");
var parameterBindingDataArray = new ParameterBindingData[] { parameterBindingData, parameterBindingData };

TypedData returned_typedData = parameterBindingDataArray.ToModelBindingDataArray();

var modelBindingData = new ModelBindingData
{
Version = parameterBindingData.Version,
ContentType = parameterBindingData.ContentType,
Source = parameterBindingData.Source,
Content = ByteString.CopyFrom(parameterBindingData.Content)
};

var collectionModelBindingData = new CollectionModelBindingData();
collectionModelBindingData.ModelBindingData.Add(modelBindingData);
collectionModelBindingData.ModelBindingData.Add(modelBindingData);

TypedData typedData = new TypedData();
typedData.CollectionModelBindingData = collectionModelBindingData;

Assert.Equal(2, returned_typedData.CollectionModelBindingData.ModelBindingData.Count);
Assert.Equal(typedData.CollectionModelBindingData.ModelBindingData.First(), returned_typedData.CollectionModelBindingData.ModelBindingData.First());
}

[Fact]
public void ToModelBindingData_EmptyAndNullArray_Creates_Valid_BindingData()
{
var parameterBindingDataEmptyArray = new ParameterBindingData[] { };
var parameterBindingDataNullArray = new ParameterBindingData[] { null };

TypedData returned_emptyTypedData = parameterBindingDataEmptyArray.ToModelBindingDataArray();
TypedData returned_nullTypedData = parameterBindingDataNullArray.ToModelBindingDataArray();

var collectionModelBindingData = new CollectionModelBindingData();

TypedData typedData = new TypedData();
typedData.CollectionModelBindingData = collectionModelBindingData;

Assert.Equal(0, returned_emptyTypedData.CollectionModelBindingData.ModelBindingData.Count);
Assert.Equal(0, returned_nullTypedData.CollectionModelBindingData.ModelBindingData.Count);
}
}
}