diff --git a/extensions/Worker.Extensions.Abstractions/src/SupportsDeferredBindingAttribute.cs b/extensions/Worker.Extensions.Abstractions/src/SupportsDeferredBindingAttribute.cs deleted file mode 100644 index b88551c43..000000000 --- a/extensions/Worker.Extensions.Abstractions/src/SupportsDeferredBindingAttribute.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; - -namespace Microsoft.Azure.Functions.Worker.Extensions.Abstractions -{ - /// - /// Specifies if a binding attribute supports deferred binding when generating function metadata. - /// This is to be used on input, output or trigger attributes that support deferred binding. - /// - [AttributeUsage(AttributeTargets.Class)] - public class SupportsDeferredBindingAttribute : Attribute - { - } -} diff --git a/extensions/Worker.Extensions.Storage.Blobs/src/BlobInputAttribute.cs b/extensions/Worker.Extensions.Storage.Blobs/src/BlobInputAttribute.cs index 78ab31abc..a2856cad2 100644 --- a/extensions/Worker.Extensions.Storage.Blobs/src/BlobInputAttribute.cs +++ b/extensions/Worker.Extensions.Storage.Blobs/src/BlobInputAttribute.cs @@ -5,7 +5,6 @@ namespace Microsoft.Azure.Functions.Worker { - [SupportsDeferredBinding] public sealed class BlobInputAttribute : InputBindingAttribute { private readonly string _blobPath; diff --git a/extensions/Worker.Extensions.Storage.Blobs/src/BlobStorageConverter.cs b/extensions/Worker.Extensions.Storage.Blobs/src/BlobStorageConverter.cs deleted file mode 100644 index 3e0a6c96f..000000000 --- a/extensions/Worker.Extensions.Storage.Blobs/src/BlobStorageConverter.cs +++ /dev/null @@ -1,236 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Threading; -using System.Threading.Tasks; -using Azure.Storage.Blobs; -using Azure.Storage.Blobs.Specialized; -using Microsoft.Azure.Functions.Worker.Converters; -using Microsoft.Azure.Functions.Worker.Core; -using Microsoft.Extensions.Options; -using Microsoft.Extensions.Logging; - -namespace Microsoft.Azure.Functions.Worker -{ - /// - /// Converter to bind Blob Storage type parameters. - /// - internal class BlobStorageConverter : IInputConverter - { - private readonly IOptions _workerOptions; - private readonly IOptionsSnapshot _blobOptions; - - private readonly ILogger _logger; - - public BlobStorageConverter(IOptions workerOptions, IOptionsSnapshot blobOptions, ILogger logger) - { - _workerOptions = workerOptions ?? throw new ArgumentNullException(nameof(workerOptions)); - _blobOptions = blobOptions ?? throw new ArgumentNullException(nameof(blobOptions)); - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - } - - public async ValueTask ConvertAsync(ConverterContext context) - { - return context?.Source switch - { - ModelBindingData binding => await ConvertFromBindingDataAsync(context, binding), - CollectionModelBindingData binding => await ConvertFromCollectionBindingDataAsync(context, binding), - _ => ConversionResult.Unhandled(), - }; - } - - private async ValueTask ConvertFromBindingDataAsync(ConverterContext context, ModelBindingData modelBindingData) - { - if (!IsBlobExtension(modelBindingData)) - { - return ConversionResult.Unhandled(); - } - - try - { - Dictionary content = GetBindingDataContent(modelBindingData); - var result = await ConvertModelBindingDataAsync(content, context.TargetType, modelBindingData); - - if (result is not null) - { - return ConversionResult.Success(result); - } - } - catch (Exception ex) - { - return ConversionResult.Failed(ex); - } - - return ConversionResult.Unhandled(); - } - - private async ValueTask ConvertFromCollectionBindingDataAsync(ConverterContext context, CollectionModelBindingData collectionModelBindingData) - { - var blobCollection = new List(collectionModelBindingData.ModelBindingDataArray.Length); - Type elementType = context.TargetType.IsArray ? context.TargetType.GetElementType() : context.TargetType.GenericTypeArguments[0]; - - try - { - foreach (ModelBindingData modelBindingData in collectionModelBindingData.ModelBindingDataArray) - { - if (!IsBlobExtension(modelBindingData)) - { - return ConversionResult.Unhandled(); - } - - Dictionary content = GetBindingDataContent(modelBindingData); - var element = await ConvertModelBindingDataAsync(content, elementType, modelBindingData); - - if (element is not null) - { - blobCollection.Add(element); - } - } - - var methodName = context.TargetType.IsArray ? nameof(CloneToArray) : nameof(CloneToList); - var result = ToTargetTypeCollection(blobCollection, methodName, elementType); - - return ConversionResult.Success(result); - } - catch (Exception ex) - { - return ConversionResult.Failed(ex); - } - } - - private bool IsBlobExtension(ModelBindingData bindingData) - { - if (bindingData?.Source is not Constants.BlobExtensionName) - { - _logger.LogTrace("Source '{source}' is not supported by {converter}", bindingData?.Source, nameof(BlobStorageConverter)); - return false; - } - - return true; - } - - private Dictionary GetBindingDataContent(ModelBindingData bindingData) - { - return bindingData?.ContentType switch - { - Constants.JsonContentType => new Dictionary(bindingData?.Content?.ToObjectFromJson>(), StringComparer.OrdinalIgnoreCase), - _ => throw new NotSupportedException($"Unexpected content-type. Currently only {Constants.JsonContentType} is supported.") - }; - } - - private async Task ConvertModelBindingDataAsync(IDictionary content, Type targetType, ModelBindingData bindingData) - { - content.TryGetValue(Constants.Connection, out var connectionName); - content.TryGetValue(Constants.ContainerName, out var containerName); - content.TryGetValue(Constants.BlobName, out var blobName); - - if (string.IsNullOrEmpty(connectionName) || string.IsNullOrEmpty(containerName)) - { - throw new ArgumentNullException("'Connection' and 'ContainerName' cannot be null or empty"); - } - - return await ToTargetTypeAsync(targetType, connectionName, containerName, blobName); - } - - private async Task ToTargetTypeAsync(Type targetType, string connectionName, string containerName, string blobName) => targetType switch - { - Type _ when targetType == typeof(String) => await GetBlobStringAsync(connectionName, containerName, blobName), - Type _ when targetType == typeof(Stream) => await GetBlobStreamAsync(connectionName, containerName, blobName), - Type _ when targetType == typeof(Byte[]) => await GetBlobBinaryDataAsync(connectionName, containerName, blobName), - Type _ when targetType == typeof(BlobBaseClient) => CreateBlobClient(connectionName, containerName, blobName), - Type _ when targetType == typeof(BlobClient) => CreateBlobClient(connectionName, containerName, blobName), - Type _ when targetType == typeof(BlockBlobClient) => CreateBlobClient(connectionName, containerName, blobName), - Type _ when targetType == typeof(PageBlobClient) => CreateBlobClient(connectionName, containerName, blobName), - Type _ when targetType == typeof(AppendBlobClient) => CreateBlobClient(connectionName, containerName, blobName), - Type _ when targetType == typeof(BlobContainerClient) => CreateBlobContainerClient(connectionName, containerName), - _ => await DeserializeToTargetObjectAsync(targetType, connectionName, containerName, blobName) - }; - - private async Task DeserializeToTargetObjectAsync(Type targetType, string connectionName, string containerName, string blobName) - { - var content = await GetBlobStreamAsync(connectionName, containerName, blobName); - return _workerOptions?.Value?.Serializer?.Deserialize(content, targetType, CancellationToken.None); - } - - private object? ToTargetTypeCollection(IEnumerable blobCollection, string methodName, Type type) - { - blobCollection = blobCollection.Select(b => Convert.ChangeType(b, type)); - MethodInfo method = typeof(BlobStorageConverter).GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic); - MethodInfo genericMethod = method.MakeGenericMethod(type); - - return genericMethod.Invoke(null, new[] { blobCollection.ToList() }); - } - - private static T[] CloneToArray(IList source) - { - return source.Cast().ToArray(); - } - - private static IEnumerable CloneToList(IList source) - { - return source.Cast(); - } - - private async Task GetBlobStringAsync(string connectionName, string containerName, string blobName) - { - var client = CreateBlobClient(connectionName, containerName, blobName); - return await GetBlobContentStringAsync(client); - } - - private async Task GetBlobContentStringAsync(BlobClient client) - { - var download = await client.DownloadContentAsync(); - return download.Value.Content.ToString(); - } - - private async Task GetBlobBinaryDataAsync(string connectionName, string containerName, string blobName) - { - using MemoryStream stream = new(); - var client = CreateBlobClient(connectionName, containerName, blobName); - await client.DownloadToAsync(stream); - return stream.ToArray(); - } - - private async Task GetBlobStreamAsync(string connectionName, string containerName, string blobName) - { - var client = CreateBlobClient(connectionName, containerName, blobName); - var download = await client.DownloadStreamingAsync(); - return download.Value.Content; - } - - private BlobContainerClient CreateBlobContainerClient(string connectionName, string containerName) - { - var blobStorageOptions = _blobOptions.Get(connectionName); - BlobServiceClient blobServiceClient = blobStorageOptions.CreateClient(); - BlobContainerClient container = blobServiceClient.GetBlobContainerClient(containerName); - return container; - } - - private T CreateBlobClient(string connectionName, string containerName, string blobName) where T : BlobBaseClient - { - if (string.IsNullOrEmpty(blobName)) - { - throw new ArgumentNullException(nameof(blobName)); - } - - BlobContainerClient container = CreateBlobContainerClient(connectionName, containerName); - - Type targetType = typeof(T); - BlobBaseClient blobClient = targetType switch - { - Type _ when targetType == typeof(BlobClient) => container.GetBlobClient(blobName), - Type _ when targetType == typeof(BlockBlobClient) => container.GetBlockBlobClient(blobName), - Type _ when targetType == typeof(PageBlobClient) => container.GetPageBlobClient(blobName), - Type _ when targetType == typeof(AppendBlobClient) => container.GetAppendBlobClient(blobName), - _ => container.GetBlobBaseClient(blobName) - }; - - return (T)blobClient; - } - } -} \ No newline at end of file diff --git a/extensions/Worker.Extensions.Storage.Blobs/src/BlobTriggerAttribute.cs b/extensions/Worker.Extensions.Storage.Blobs/src/BlobTriggerAttribute.cs index 59ac9fbc8..3a546c6be 100644 --- a/extensions/Worker.Extensions.Storage.Blobs/src/BlobTriggerAttribute.cs +++ b/extensions/Worker.Extensions.Storage.Blobs/src/BlobTriggerAttribute.cs @@ -5,7 +5,6 @@ namespace Microsoft.Azure.Functions.Worker { - [SupportsDeferredBinding] public sealed class BlobTriggerAttribute : TriggerBindingAttribute { private readonly string _blobPath; diff --git a/extensions/Worker.Extensions.Storage.Blobs/src/StorageExtensionStartup.cs b/extensions/Worker.Extensions.Storage.Blobs/src/StorageExtensionStartup.cs index a7bee100d..9f8b10bb1 100644 --- a/extensions/Worker.Extensions.Storage.Blobs/src/StorageExtensionStartup.cs +++ b/extensions/Worker.Extensions.Storage.Blobs/src/StorageExtensionStartup.cs @@ -24,11 +24,6 @@ public override void Configure(IFunctionsWorkerApplicationBuilder applicationBui applicationBuilder.Services.AddAzureClientsCore(); // Adds AzureComponentFactory applicationBuilder.Services.AddOptions(); applicationBuilder.Services.AddSingleton, BlobStorageBindingOptionsSetup>(); - - applicationBuilder.Services.Configure((workerOption) => - { - workerOption.InputConverters.RegisterAt(0); - }); } } } diff --git a/src/DotNetWorker.Core/CollectionModelBindingData.cs b/src/DotNetWorker.Core/CollectionModelBindingData.cs deleted file mode 100644 index a22400c96..000000000 --- a/src/DotNetWorker.Core/CollectionModelBindingData.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -namespace Microsoft.Azure.Functions.Worker.Core -{ - /// - /// A representation of Collection of Microsoft.Azure.WebJobs.ParameterBindingData - /// - public abstract class CollectionModelBindingData - { - /// - /// Gets the array of ModelBindingData - /// - public abstract ModelBindingData[] ModelBindingDataArray { get; } - } -} diff --git a/src/DotNetWorker.Core/ModelBindingData.cs b/src/DotNetWorker.Core/ModelBindingData.cs deleted file mode 100644 index 8e4580f77..000000000 --- a/src/DotNetWorker.Core/ModelBindingData.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; - -namespace Microsoft.Azure.Functions.Worker.Core -{ - /// - /// A representation of a Microsoft.Azure.WebJobs.ParameterBindingData - /// - public abstract class ModelBindingData - { - /// - /// Gets the version of the binding data content - /// - public abstract string Version { get; } - - /// - /// Gets the extension source of the binding data i.e CosmosDB, AzureStorageBlobs - /// - public abstract string Source { get; } - - /// - /// Gets the binding data content - /// - public abstract BinaryData Content { get; } - - /// - /// Gets the content type of the binding data content i.e. "application/json" - /// - public abstract string ContentType { get; } - } -} diff --git a/src/DotNetWorker.Grpc/Features/GrpcFunctionBindingsFeature.cs b/src/DotNetWorker.Grpc/Features/GrpcFunctionBindingsFeature.cs index e45f02acf..ec4e7bcee 100644 --- a/src/DotNetWorker.Grpc/Features/GrpcFunctionBindingsFeature.cs +++ b/src/DotNetWorker.Grpc/Features/GrpcFunctionBindingsFeature.cs @@ -124,8 +124,6 @@ public void SetOutputBinding(string name, object value) TypedData.DataOneofCase.CollectionString => typedData.CollectionString.String, TypedData.DataOneofCase.CollectionDouble => typedData.CollectionDouble.Double, TypedData.DataOneofCase.CollectionSint64 => typedData.CollectionSint64.Sint64, - TypedData.DataOneofCase.ModelBindingData => new GrpcModelBindingData(typedData.ModelBindingData), - TypedData.DataOneofCase.CollectionModelBindingData => new GrpcCollectionModelBindingData(typedData.CollectionModelBindingData), _ => throw new NotSupportedException($"{typedData.DataCase} is not supported."), }; } diff --git a/src/DotNetWorker.Grpc/GrpcCollectionModelBindingData.cs b/src/DotNetWorker.Grpc/GrpcCollectionModelBindingData.cs deleted file mode 100644 index d3e0726fa..000000000 --- a/src/DotNetWorker.Grpc/GrpcCollectionModelBindingData.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Linq; - -namespace Microsoft.Azure.Functions.Worker.Grpc.Messages -{ - internal partial class GrpcCollectionModelBindingData : Microsoft.Azure.Functions.Worker.Core.CollectionModelBindingData - { - public GrpcCollectionModelBindingData(CollectionModelBindingData modelBindingDataArray) - { - ModelBindingDataArray = modelBindingDataArray.ModelBindingData - .Select(p => new GrpcModelBindingData(p)).ToArray(); - } - - public override Core.ModelBindingData[] ModelBindingDataArray { get; } - } -} diff --git a/src/DotNetWorker.Grpc/GrpcModelBindingData.cs b/src/DotNetWorker.Grpc/GrpcModelBindingData.cs deleted file mode 100644 index 66d5de896..000000000 --- a/src/DotNetWorker.Grpc/GrpcModelBindingData.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; - -namespace Microsoft.Azure.Functions.Worker.Grpc.Messages -{ - internal partial class GrpcModelBindingData : Microsoft.Azure.Functions.Worker.Core.ModelBindingData - { - private readonly ModelBindingData _modelBindingData; - - public GrpcModelBindingData(ModelBindingData modelBindingData) - { - _modelBindingData = modelBindingData; - Content = BinaryData.FromBytes(_modelBindingData.Content.ToByteArray()); - } - - public override string Version => _modelBindingData.Version; - - public override string Source => _modelBindingData.Source; - - public override BinaryData Content { get; } - - public override string ContentType => _modelBindingData.ContentType; - } -} diff --git a/test/DotNetWorkerTests/GrpcFunctionBindingsFeatureTests.cs b/test/DotNetWorkerTests/GrpcFunctionBindingsFeatureTests.cs index 3fb8d6445..d449987ff 100644 --- a/test/DotNetWorkerTests/GrpcFunctionBindingsFeatureTests.cs +++ b/test/DotNetWorkerTests/GrpcFunctionBindingsFeatureTests.cs @@ -31,156 +31,5 @@ public GrpcFunctionBindingsFeatureTests() .Setup(m => m.Create()) .Returns(new InvocationFeatures(Enumerable.Empty())); } - - [Fact] - public void BindFunctionTriggerAsync_Populates_ModelBindingData() - { - // Arrange - var invocationId = "5fb3a9b4-0b38-450a-9d46-35946e7edea7"; - var request = TestUtility.CreateInvocationRequest(invocationId); - request.TriggerMetadata.Add("myBlob", new TypedData() { ModelBindingData = new ModelBindingData() { - Version = "1.1.1", - Source = "blob", - Content = ByteString.CopyFromUtf8("stringText")} }); - - IInvocationFeatures invocationFeatures = _mockInvocationFeaturesFactory.Object.Create(); - var context = _mockApplication.Object.CreateContext(invocationFeatures, new CancellationTokenSource().Token); - - // Act - var functionBindingsFeature = new GrpcFunctionBindingsFeature(context, request, _mockOutputBindingsInfoProvider.Object); - - // Assert - Assert.Single(functionBindingsFeature.TriggerMetadata); - - functionBindingsFeature.TriggerMetadata.TryGetValue("myBlob", out object bindingData); - Assert.True(bindingData.GetType() == typeof(GrpcModelBindingData)); - var grpcModelBindingData = (GrpcModelBindingData)bindingData; - - Assert.True(grpcModelBindingData.Version == "1.1.1"); - Assert.True(grpcModelBindingData.Content.GetType() == typeof(BinaryData)); - } - - [Fact] - public void BindFunctionInputAsync_Populates_ModelBindingData() - { - // Arrange - var invocationId = "5fb3a9b4-0b38-450a-9d46-35946e7edea7"; - var request = TestUtility.CreateInvocationRequest(invocationId); - request.InputData.Insert(0, new ParameterBinding() - { - Name = "myBlob", - Data = new TypedData() - { - ModelBindingData = new ModelBindingData() - { - Version = "1.1.1", - Source = "blob", - Content = ByteString.CopyFromUtf8("stringText") - } - } - }); - - IInvocationFeatures invocationFeatures = _mockInvocationFeaturesFactory.Object.Create(); - var context = _mockApplication.Object.CreateContext(invocationFeatures, new CancellationTokenSource().Token); - - // Act - var functionBindingsFeature = new GrpcFunctionBindingsFeature(context, request, _mockOutputBindingsInfoProvider.Object); - - // Assert - Assert.Single(functionBindingsFeature.InputData); - - functionBindingsFeature.InputData.TryGetValue("myBlob", out object bindingData); - Assert.True(bindingData.GetType() == typeof(GrpcModelBindingData)); - var grpcModelBindingData = (GrpcModelBindingData)bindingData; - - Assert.True(grpcModelBindingData.Version == "1.1.1"); - Assert.True(grpcModelBindingData.Content.GetType() == typeof(BinaryData)); - } - - [Fact] - public void BindFunctionTriggerAsync_Populates_CollectionModelBindingData() - { - // Arrange - var invocationId = "5fb3a9b4-0b38-450a-9d46-35946e7edea7"; - var request = TestUtility.CreateInvocationRequest(invocationId); - - var modelBindingData = new ModelBindingData() - { - Version = "1.1.1", - Source = "blob", - Content = ByteString.CopyFromUtf8("stringText") - }; - - var collectionModelBindingData = new CollectionModelBindingData(); - collectionModelBindingData.ModelBindingData.Add(modelBindingData); - - request.TriggerMetadata.Add("myBlob", new TypedData() - { - CollectionModelBindingData = collectionModelBindingData - }); - - IInvocationFeatures invocationFeatures = _mockInvocationFeaturesFactory.Object.Create(); - var context = _mockApplication.Object.CreateContext(invocationFeatures, new CancellationTokenSource().Token); - - // Act - var functionBindingsFeature = new GrpcFunctionBindingsFeature(context, request, _mockOutputBindingsInfoProvider.Object); - - // Assert - Assert.Single(functionBindingsFeature.TriggerMetadata); - - functionBindingsFeature.TriggerMetadata.TryGetValue("myBlob", out object bindingData); - Assert.True(bindingData.GetType() == typeof(GrpcCollectionModelBindingData)); - var grpcCollectionModelBindingData = (GrpcCollectionModelBindingData)bindingData; - - Assert.True(grpcCollectionModelBindingData.ModelBindingDataArray.Count() == 1); - var grpcModelBindingData = grpcCollectionModelBindingData.ModelBindingDataArray[0]; - Assert.True(grpcModelBindingData.Version == "1.1.1"); - Assert.True(grpcModelBindingData.Content.GetType() == typeof(BinaryData)); - } - - [Fact] - public void BindFunctionInputAsync_Populates_CollectionModelBindingData() - { - // Arrange - var invocationId = "5fb3a9b4-0b38-450a-9d46-35946e7edea7"; - var request = TestUtility.CreateInvocationRequest(invocationId); - - var modelBindingData = new ModelBindingData() - { - Version = "1.1.1", - Source = "blob", - Content = ByteString.CopyFromUtf8("stringText") - }; - - var collectionModelBindingData = new CollectionModelBindingData(); - collectionModelBindingData.ModelBindingData.Add(modelBindingData); - - request.InputData.Insert(0, new ParameterBinding() - { - Name = "myBlob", - Data = new TypedData() - { - CollectionModelBindingData = collectionModelBindingData - } - }); - - IInvocationFeatures invocationFeatures = _mockInvocationFeaturesFactory.Object.Create(); - var context = _mockApplication.Object.CreateContext(invocationFeatures, new CancellationTokenSource().Token); - - // Act - var functionBindingsFeature = new GrpcFunctionBindingsFeature(context, request, _mockOutputBindingsInfoProvider.Object); - - // Assert - Assert.Single(functionBindingsFeature.InputData); - - functionBindingsFeature.InputData.TryGetValue("myBlob", out object bindingData); - Assert.True(bindingData.GetType() == typeof(GrpcCollectionModelBindingData)); - var grpcCollectionModelBindingData = (GrpcCollectionModelBindingData)bindingData; - - Assert.True(grpcCollectionModelBindingData.ModelBindingDataArray.Count() == 1); - var grpcModelBindingData = grpcCollectionModelBindingData.ModelBindingDataArray[0]; - Assert.True(grpcModelBindingData.Version == "1.1.1"); - Assert.True(grpcModelBindingData.Content.GetType() == typeof(BinaryData)); - } } } diff --git a/test/FunctionMetadataGeneratorTests/FunctionMetadataGeneratorTests.cs b/test/FunctionMetadataGeneratorTests/FunctionMetadataGeneratorTests.cs index 9832840d5..9daf0e27b 100644 --- a/test/FunctionMetadataGeneratorTests/FunctionMetadataGeneratorTests.cs +++ b/test/FunctionMetadataGeneratorTests/FunctionMetadataGeneratorTests.cs @@ -170,7 +170,7 @@ public void StorageFunctions() AssertDictionary(extensions, new Dictionary { { "Microsoft.Azure.WebJobs.Extensions.Storage.Queues", "5.0.0" }, - { "Microsoft.Azure.WebJobs.Extensions.Storage.Blobs", "5.1.0-beta.1" }, + { "Microsoft.Azure.WebJobs.Extensions.Storage.Blobs", "5.0.1" }, }); void ValidateQueueTrigger(ExpandoObject b) @@ -210,7 +210,7 @@ void ValidateBlobInput(ExpandoObject b) { "Direction", "In" }, { "blobPath", "container2" }, { "Cardinality", "Many" }, - { "Properties", new Dictionary( ) { { "SupportsDeferredBinding" , "True"} } } + { "Properties", new Dictionary() } }); } @@ -225,8 +225,9 @@ void ValidateBlobTrigger(ExpandoObject b) { "Name", "blob" }, { "Type", "blobTrigger" }, { "Direction", "In" }, + { "DataType", "String"}, { "path", "container2/%file%" }, - { "Properties", new Dictionary( ) { { "SupportsDeferredBinding" , "True"} } } + { "Properties", new Dictionary() } }); } @@ -243,68 +244,6 @@ void ValidateQueueOutput(ExpandoObject b) } } - [Fact] - public void StorageFunction_SDKTypeBindings() - { - var generator = new FunctionMetadataGenerator(); - var module = ModuleDefinition.ReadModule(_thisAssembly.Location); - var typeDef = TestUtility.GetTypeDefinition(typeof(SDKTypeBindings)); - var functions = generator.GenerateFunctionMetadata(typeDef); - var extensions = generator.Extensions; - - Assert.Single(functions); - - var blobToBlob = functions.Single(p => p.Name == "BlobToBlobFunction"); - - ValidateFunction(blobToBlob, "BlobToBlobFunction", GetEntryPoint(nameof(SDKTypeBindings), nameof(SDKTypeBindings.BlobToBlob)), - b => ValidateBlobTrigger(b), - b => ValidateBlobInput(b), - b => ValidateBlobOutput(b)); - - AssertDictionary(extensions, new Dictionary - { - { "Microsoft.Azure.WebJobs.Extensions.Storage.Blobs", "5.1.0-beta.1" }, - }); - - void ValidateBlobTrigger(ExpandoObject b) - { - AssertExpandoObject(b, new Dictionary - { - { "Name", "blob" }, - { "Type", "blobTrigger" }, - { "Direction", "In" }, - { "path", "container2/%file%" }, - { "Properties", new Dictionary( ) { { "SupportsDeferredBinding" , "True"} } } - }); - } - - void ValidateBlobInput(ExpandoObject b) - { - AssertExpandoObject(b, new Dictionary - { - { "Name", "blobinput" }, - { "Type", "blob" }, - { "Direction", "In" }, - { "blobPath", "container2/%file%" }, - { "Cardinality", "One" }, - { "Properties", new Dictionary( ) { { "SupportsDeferredBinding" , "True"} } } - }); - } - - void ValidateBlobOutput(ExpandoObject b) - { - AssertExpandoObject(b, new Dictionary - { - { "Name", "$return" }, - { "Type", "blob" }, - { "Direction", "Out" }, - { "blobPath", "container1/hello.txt" }, - { "Connection", "MyOtherConnection" }, - { "Properties", new Dictionary() } - }); - } - } - [Fact] public void TimerFunction() { diff --git a/test/SdkE2ETests/Contents/functions.metadata b/test/SdkE2ETests/Contents/functions.metadata index fb401f51f..60218adc9 100644 --- a/test/SdkE2ETests/Contents/functions.metadata +++ b/test/SdkE2ETests/Contents/functions.metadata @@ -50,12 +50,11 @@ "name": "myBlob", "direction": "In", "type": "blob", + "dataType": "String", "blobPath": "test-samples/sample1.txt", "connection": "AzureWebJobsStorage", "cardinality": "One", - "properties": { - "supportsDeferredBinding": "True" - } + "properties": {} }, { "name": "Book", @@ -189,12 +188,11 @@ "name": "myBlob", "direction": "In", "type": "blob", + "dataType": "String", "blobPath": "test-samples/sample1.txt", "connection": "AzureWebJobsStorage", "cardinality": "One", - "properties": { - "supportsDeferredBinding": "True" - } + "properties": {} } ], "retry": {