Example #1
0
        public void AddsStorageOutput_FromReturnType()
        {
            FunctionContext context = GetContextWithOutputBindings(nameof(JustStorage.MyQueueOutput), nameof(JustStorage.MyBlobOutput));

            JustStorage result = new JustStorage()
            {
                MyQueueOutput = "queueStuff",
                MyBlobOutput  = "blobStuff"
            };

            context.GetBindings().InvocationResult = result;

            Assert.Empty(context.GetBindings().OutputBindingData);

            OutputBindingsMiddleware.AddOutputBindings(context);
            object returnedVal = context.GetBindings().InvocationResult;

            Assert.Null(returnedVal);
            Assert.Equal(2, context.GetBindings().OutputBindingData.Count);

            AssertDictionary(context.GetBindings().OutputBindingData, new Dictionary <string, object>()
            {
                { "MyQueueOutput", "queueStuff" },
                { "MyBlobOutput", "blobStuff" }
            });
        }
Example #2
0
        public void AddsStorageOutput_AndHttpReturn_FromReturnType()
        {
            FunctionContext context = GetContextWithOutputBindings(nameof(HttpAndStorage.MyQueueOutput), nameof(HttpAndStorage.MyBlobOutput),
                                                                   nameof(HttpAndStorage.MyHttpResponseData));
            var emptyHttp = new TestHttpResponseData(context, HttpStatusCode.OK);

            HttpAndStorage result = new HttpAndStorage()
            {
                MyQueueOutput      = "queueStuff",
                MyBlobOutput       = "blobStuff",
                MyRandomValue      = "ShouldNotAppear",
                MyHttpResponseData = emptyHttp
            };

            context.GetBindings().InvocationResult = result;

            Assert.Equal(0, context.GetBindings().OutputBindingData.Count);

            OutputBindingsMiddleware.AddOutputBindings(context);
            object returnedVal = context.GetBindings().InvocationResult;

            Assert.Null(returnedVal);
            Assert.Equal(3, context.GetBindings().OutputBindingData.Count);

            AssertDictionary(context.GetBindings().OutputBindingData, new Dictionary <string, object>()
            {
                { "MyQueueOutput", "queueStuff" },
                { "MyBlobOutput", "blobStuff" },
                { "MyHttpResponseData", emptyHttp }
            });
        }
Example #3
0
        public void SetsResult_NoBinding()
        {
            // No binding, should leave invocation result untouched
            FunctionContext context = GetContextWithOutputBindings();
            string          myData  = "abc";

            context.GetBindings().InvocationResult = myData;

            Assert.Empty(context.GetBindings().OutputBindingData);

            OutputBindingsMiddleware.AddOutputBindings(context);
            object returnedVal = context.GetBindings().InvocationResult;

            Assert.Equal("abc", returnedVal);
            Assert.Equal(0, context.GetBindings().OutputBindingData.Count);
        }
Example #4
0
        public void SetsOutput_FromMethodBinding()
        {
            // special binding to indicate the return value is set as an output binding
            FunctionContext context   = GetContextWithOutputBindings("$return");
            var             emptyHttp = new TestHttpResponseData(context, HttpStatusCode.OK);

            context.GetBindings().InvocationResult = emptyHttp;

            Assert.Empty(context.GetBindings().OutputBindingData);

            OutputBindingsMiddleware.AddOutputBindings(context);
            object returnedVal = context.GetBindings().InvocationResult;

            Assert.Equal(returnedVal, emptyHttp);
            Assert.Empty(context.GetBindings().OutputBindingData);

            AssertDictionary(context.GetBindings().OutputBindingData, new Dictionary <string, object>());
        }
Example #5
0
        public void AddsSingleOutput_FromMethodReturn()
        {
            // Special binding name indiciating return
            FunctionContext context = GetContextWithOutputBindings("$return");
            string          result  = "MyStorageData";

            context.GetBindings().InvocationResult = result;

            Assert.Empty(context.GetBindings().OutputBindingData);

            OutputBindingsMiddleware.AddOutputBindings(context);
            object returnedVal = context.GetBindings().InvocationResult;

            Assert.Equal(returnedVal, result);
            Assert.Empty(context.GetBindings().OutputBindingData);

            AssertDictionary(context.GetBindings().OutputBindingData, new Dictionary <string, object>());
        }
Example #6
0
        internal static void AddOutputBindings(FunctionContext context)
        {
            var    functionBindings = context.GetBindings();
            object?result           = functionBindings.InvocationResult;

            if (result != null)
            {
                functionBindings.OutputBindingsInfo.BindOutputInContext(context);
            }
        }
Example #7
0
        public object?[] BindFunctionInput(FunctionContext context)
        {
            if (_inputBound)
            {
                throw new InvalidOperationException("Duplicate binding call detected. " +
                                                    $"Input parameters can only be bound to arguments once. Use the {nameof(InputArguments)} property to inspect values.");
            }

            _parameterValues = new object?[context.FunctionDefinition.Parameters.Length];
            _inputBound      = true;

            List <string>?errors = null;

            for (int i = 0; i < _parameterValues.Length; i++)
            {
                FunctionParameter param = context.FunctionDefinition.Parameters[i];

                IFunctionBindingsFeature functionBindings = context.GetBindings();

                // Check InputData first, then TriggerMetadata
                if (!functionBindings.InputData.TryGetValue(param.Name, out object?source))
                {
                    functionBindings.TriggerMetadata.TryGetValue(param.Name, out source);
                }

                var converterContext = new DefaultConverterContext(param, source, context);

                if (TryConvert(converterContext, out object?target))
                {
                    _parameterValues[i] = target;
                }
                else if (source is not null)
                {
                    // Don't initialize this list unless we have to
                    if (errors is null)
                    {
                        errors = new List <string>();
                    }

                    errors.Add($"Cannot convert input parameter '{param.Name}' to type '{param.Type.FullName}' from type '{source.GetType().FullName}'.");
                }
            }

            // found errors
            if (errors is not null)
            {
                throw new FunctionInputConverterException($"Error converting {errors.Count} input parameters for Function '{context.FunctionDefinition.Name}': {string.Join(Environment.NewLine, errors)}");
            }

            return(_parameterValues);
        }
Example #8
0
        public override void BindOutputInContext(FunctionContext context)
        {
            var    functionBindings = context.GetBindings();
            object?result           = functionBindings.InvocationResult;

            if (result is not null)
            {
                AddResultToOutputBindings(functionBindings.OutputBindingData, result);

                // Because this context had property output bindings,
                // any invocation result was tranformed to output bindings, so the invocation result
                // would now be null.
                functionBindings.InvocationResult = null;
            }
        }
Example #9
0
        public async Task ExecuteAsync(FunctionContext context)
        {
            var invoker = _invokerCache.GetOrAdd(context.FunctionId,
                                                 _ => _invokerFactory.Create(context.FunctionDefinition));

            object?instance            = invoker.CreateInstance(context.InstanceServices);
            var    modelBindingFeature = context.Features.Get <IModelBindingFeature>();

            object?[] inputArguments;
            if (modelBindingFeature is null)
            {
                Log.ModelBindingFeatureUnavailable(_logger, context);
                inputArguments = new object?[context.FunctionDefinition.Parameters.Length];
            }
            else
            {
                inputArguments = modelBindingFeature.BindFunctionInput(context);
            }

            context.GetBindings().InvocationResult = await invoker.InvokeAsync(instance, inputArguments);
        }
        public async ValueTask <object?[]> BindFunctionInputAsync(FunctionContext context)
        {
            if (_inputBound)
            {
                throw new InvalidOperationException("Duplicate binding call detected. " +
                                                    $"Input parameters can only be bound to arguments once. Use the {nameof(InputArguments)} property to inspect values.");
            }

            _parameterValues = new object?[context.FunctionDefinition.Parameters.Length];
            _inputBound      = true;

            var inputConversionFeature = context.Features.Get <IInputConversionFeature>();

            if (inputConversionFeature == null)
            {
                throw new InvalidOperationException("Input conversion feature is missing.");
            }

            List <string>?errors = null;

            for (int i = 0; i < _parameterValues.Length; i++)
            {
                FunctionParameter param = context.FunctionDefinition.Parameters[i];

                IFunctionBindingsFeature functionBindings = context.GetBindings();

                // Check InputData first, then TriggerMetadata
                if (!functionBindings.InputData.TryGetValue(param.Name, out object?source))
                {
                    functionBindings.TriggerMetadata.TryGetValue(param.Name, out source);
                }

                IReadOnlyDictionary <string, object> properties = ImmutableDictionary <string, object> .Empty;

                // Pass info about specific input converter type defined for this parameter, if present.
                if (param.Properties.TryGetValue(PropertyBagKeys.ConverterType, out var converterTypeAssemblyFullName))
                {
                    properties = new Dictionary <string, object>()
                    {
                        { PropertyBagKeys.ConverterType, converterTypeAssemblyFullName }
                    };
                }

                var converterContext = _converterContextFactory.Create(param.Type, source, context, properties);

                var bindingResult = await inputConversionFeature.ConvertAsync(converterContext);

                if (bindingResult.Status == ConversionStatus.Succeeded)
                {
                    _parameterValues[i] = bindingResult.Value;
                }
                else if (bindingResult.Status == ConversionStatus.Failed && source is not null)
                {
                    // Don't initialize this list unless we have to
                    errors ??= new List <string>();

                    errors.Add(
                        $"Cannot convert input parameter '{param.Name}' to type '{param.Type.FullName}' from type '{source.GetType().FullName}'. Error:{bindingResult.Error}");
                }
            }

            // found errors
            if (errors is not null)
            {
                throw new FunctionInputConverterException(
                          $"Error converting {errors.Count} input parameters for Function '{context.FunctionDefinition.Name}': {string.Join(Environment.NewLine, errors)}");
            }

            return(_parameterValues);
        }