コード例 #1
0
        internal static async Task BindAsyncCollectorAsync <T>(Stream stream, IBinderEx binder, RuntimeBindingContext runtimeContext)
        {
            IAsyncCollector <T> collector = await binder.BindAsync <IAsyncCollector <T> >(runtimeContext);

            // first read the input stream as a collection
            ICollection <JToken> values = ReadAsCollection(stream);

            // convert values as necessary and add to the collector
            foreach (var value in values)
            {
                object converted = null;
                if (typeof(T) == typeof(string))
                {
                    converted = value.ToString();
                }
                else if (typeof(T) == typeof(JObject))
                {
                    converted = (JObject)value;
                }
                else
                {
                    throw new ArgumentException("Unsupported collection type.");
                }

                await collector.AddAsync((T)converted);
            }
        }
コード例 #2
0
        protected static Dictionary<string, string> GetBindingData(object value, IBinderEx binder, Collection<FunctionBinding> inputBindings, Collection<FunctionBinding> outputBindings)
        {
            Dictionary<string, string> bindingData = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

            // If there are any parameters in the bindings,
            // get the binding data. In dynamic script cases we need
            // to parse this POCO data ourselves - it won't be in the existing
            // binding data because all the POCO binders require strong
            // typing
            if (outputBindings.Any(p => p.HasBindingParameters) ||
                inputBindings.Any(p => p.HasBindingParameters))
            {
                // First apply any existing binding data. Any additional binding
                // data coming from the message will take precedence
                ApplyAmbientBindingData(binder, bindingData);

                try
                {
                    // if the input value is a JSON string, extract additional
                    // binding data from it
                    string json = value as string;
                    if (!string.IsNullOrEmpty(json) && Utility.IsJson(json))
                    {
                        // parse the object skipping any nested objects (binding data
                        // only includes top level properties)
                        JObject parsed = JObject.Parse(json);
                        var additionalBindingData = parsed.Children<JProperty>()
                            .Where(p => p.Value.Type != JTokenType.Object)
                            .ToDictionary(p => p.Name, p => (string)p);

                        if (additionalBindingData != null)
                        {
                            foreach (var item in additionalBindingData)
                            {
                                if (item.Value != null)
                                {
                                    bindingData[item.Key] = item.Value.ToString();
                                }
                            }
                        }
                    }
                }
                catch
                {
                    // it's not an error if the incoming message isn't JSON
                    // there are cases where there will be output binding parameters
                    // that don't bind to JSON properties
                }
            }

            return bindingData;
        }
コード例 #3
0
        protected static Dictionary <string, string> GetBindingData(object value, IBinderEx binder, Collection <FunctionBinding> inputBindings, Collection <FunctionBinding> outputBindings)
        {
            Dictionary <string, string> bindingData = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);

            // If there are any parameters in the bindings,
            // get the binding data. In dynamic script cases we need
            // to parse this POCO data ourselves - it won't be in the existing
            // binding data because all the POCO binders require strong
            // typing
            if (outputBindings.Any(p => p.HasBindingParameters) ||
                inputBindings.Any(p => p.HasBindingParameters))
            {
                // First apply any existing binding data. Any additional binding
                // data coming from the message will take precedence
                ApplyAmbientBindingData(binder, bindingData);

                try
                {
                    // if the input value is a JSON string, extract additional
                    // binding data from it
                    string json = value as string;
                    if (!string.IsNullOrEmpty(json) && Utility.IsJson(json))
                    {
                        // parse the object skipping any nested objects (binding data
                        // only includes top level properties)
                        JObject parsed = JObject.Parse(json);
                        var     additionalBindingData = parsed.Children <JProperty>()
                                                        .Where(p => p.Value.Type != JTokenType.Object)
                                                        .ToDictionary(p => p.Name, p => (string)p);

                        if (additionalBindingData != null)
                        {
                            foreach (var item in additionalBindingData)
                            {
                                if (item.Value != null)
                                {
                                    bindingData[item.Key] = item.Value.ToString();
                                }
                            }
                        }
                    }
                }
                catch
                {
                    // it's not an error if the incoming message isn't JSON
                    // there are cases where there will be output binding parameters
                    // that don't bind to JSON properties
                }
            }

            return(bindingData);
        }
コード例 #4
0
        internal static async Task BindStreamAsync(Stream stream, FileAccess access, IBinderEx binder, RuntimeBindingContext runtimeContext)
        {
            Stream boundStream = await binder.BindAsync <Stream>(runtimeContext);

            if (access == FileAccess.Write)
            {
                await stream.CopyToAsync(boundStream);
            }
            else
            {
                await boundStream.CopyToAsync(stream);
            }
        }
コード例 #5
0
        /// <summary>
        /// We need to merge the ambient binding data that already exists in the IBinder
        /// with our binding data. We have to do this rather than relying solely on
        /// IBinder.BindAsync because we need to include any POCO values we get from parsing
        /// JSON bodies, etc.
        /// TEMP: We might find a better way to do this in the future, perhaps via core
        /// SDK changes.
        /// </summary>
        protected static void ApplyAmbientBindingData(IBinderEx binder, IDictionary <string, string> bindingData)
        {
            var ambientBindingData = binder.BindingContext.BindingData;

            if (ambientBindingData != null)
            {
                // apply the binding data to ours
                foreach (var item in ambientBindingData)
                {
                    if (item.Value != null)
                    {
                        bindingData[item.Key] = item.Value.ToString();
                    }
                }
            }
        }
コード例 #6
0
        /// <summary>
        /// Get the binding data. In dynamic script cases we need
        /// to parse this POCO data ourselves - it won't be in the existing
        /// binding data because all the POCO binders require strong
        /// typing
        /// </summary>
        protected static Dictionary <string, string> GetBindingData(object value, IBinderEx binder)
        {
            // First apply any existing binding data. Any additional binding
            // data coming from the message will take precedence
            Dictionary <string, string> bindingData = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);

            ApplyAmbientBindingData(binder, bindingData);

            try
            {
                // if the input value is a JSON string, extract additional
                // binding data from it
                string json = value as string;
                if (!string.IsNullOrEmpty(json) && Utility.IsJson(json))
                {
                    // parse the object skipping any nested objects (binding data
                    // only includes top level properties)
                    JObject parsed = JObject.Parse(json);
                    var     additionalBindingData = parsed.Children <JProperty>()
                                                    .Where(p => p.Value.Type != JTokenType.Object)
                                                    .ToDictionary(p => p.Name, p => (string)p);

                    if (additionalBindingData != null)
                    {
                        foreach (var item in additionalBindingData)
                        {
                            if (item.Value != null)
                            {
                                bindingData[item.Key] = item.Value.ToString();
                            }
                        }
                    }
                }
            }
            catch
            {
                // it's not an error if the incoming message isn't JSON
                // there are cases where there will be output binding parameters
                // that don't bind to JSON properties
            }

            return(bindingData);
        }
コード例 #7
0
        public override async Task Invoke(object[] parameters)
        {
            object           input       = parameters[0];
            TraceWriter      traceWriter = (TraceWriter)parameters[1];
            IBinderEx        binder      = (IBinderEx)parameters[2];
            ExecutionContext functionExecutionContext = (ExecutionContext)parameters[3];
            string           invocationId             = functionExecutionContext.InvocationId.ToString();

            FunctionStartedEvent startedEvent = new FunctionStartedEvent(functionExecutionContext.InvocationId, Metadata);

            _metrics.BeginEvent(startedEvent);

            try
            {
                TraceWriter.Verbose(string.Format("Function started (Id={0})", invocationId));

                var scriptExecutionContext = CreateScriptExecutionContext(input, traceWriter, TraceWriter, functionExecutionContext);

                Dictionary <string, string> bindingData = GetBindingData(input, binder, _inputBindings, _outputBindings);
                bindingData["InvocationId"]           = invocationId;
                scriptExecutionContext["bindingData"] = bindingData;

                await ProcessInputBindingsAsync(binder, scriptExecutionContext, bindingData);

                object functionResult = await ScriptFunc(scriptExecutionContext);

                await ProcessOutputBindingsAsync(_outputBindings, input, binder, bindingData, scriptExecutionContext, functionResult);

                TraceWriter.Verbose(string.Format("Function completed (Success, Id={0})", invocationId));
            }
            catch
            {
                startedEvent.Success = false;
                TraceWriter.Verbose(string.Format("Function completed (Failure, Id={0})", invocationId));
                throw;
            }
            finally
            {
                _metrics.EndEvent(startedEvent);
            }
        }
コード例 #8
0
        private async Task ProcessInputBindingsAsync(IBinderEx binder, Dictionary <string, object> executionContext, Dictionary <string, string> bindingData)
        {
            var bindings = (Dictionary <string, object>)executionContext["bindings"];

            // create an ordered array of all inputs and add to
            // the execution context. These will be promoted to
            // positional parameters
            List <object> inputs = new List <object>();

            inputs.Add(bindings[_trigger.Name]);

            var nonTriggerInputBindings = _inputBindings.Where(p => !p.Metadata.IsTrigger);

            foreach (var inputBinding in nonTriggerInputBindings)
            {
                string stringValue = null;
                using (MemoryStream stream = new MemoryStream())
                {
                    BindingContext bindingContext = new BindingContext
                    {
                        Binder      = binder,
                        BindingData = bindingData,
                        Value       = stream
                    };
                    await inputBinding.BindAsync(bindingContext);

                    stream.Seek(0, SeekOrigin.Begin);
                    StreamReader sr = new StreamReader(stream);
                    stringValue = sr.ReadToEnd();
                }

                // if the input is json, try converting to an object
                object convertedValue = stringValue;
                convertedValue = TryConvertJsonToObject(stringValue);

                bindings.Add(inputBinding.Metadata.Name, convertedValue);
                inputs.Add(convertedValue);
            }

            executionContext["inputs"] = inputs;
        }
コード例 #9
0
        private static async Task ProcessOutputBindingsAsync(string functionInstanceOutputPath, Collection <FunctionBinding> outputBindings,
                                                             object input, IBinderEx binder, Dictionary <string, string> bindingData)
        {
            if (outputBindings == null)
            {
                return;
            }

            try
            {
                foreach (var outputBinding in outputBindings)
                {
                    string filePath = System.IO.Path.Combine(functionInstanceOutputPath, outputBinding.Metadata.Name);
                    if (File.Exists(filePath))
                    {
                        using (FileStream stream = File.OpenRead(filePath))
                        {
                            BindingContext bindingContext = new BindingContext
                            {
                                TriggerValue = input,
                                Binder       = binder,
                                BindingData  = bindingData,
                                Value        = stream
                            };
                            await outputBinding.BindAsync(bindingContext);
                        }
                    }
                }
            }
            finally
            {
                // clean up the output directory
                if (outputBindings.Any() && Directory.Exists(functionInstanceOutputPath))
                {
                    Directory.Delete(functionInstanceOutputPath, recursive: true);
                }
            }
        }
コード例 #10
0
        private async Task ProcessInputBindingsAsync(IBinderEx binder, Dictionary <string, object> executionContext, Dictionary <string, string> bindingData)
        {
            var bindings = (Dictionary <string, object>)executionContext["bindings"];

            // create an ordered array of all inputs and add to
            // the execution context. These will be promoted to
            // positional parameters
            List <object> inputs = new List <object>();

            inputs.Add(bindings[_trigger.Name]);

            var nonTriggerInputBindings = _inputBindings.Where(p => !p.Metadata.IsTrigger);

            foreach (var inputBinding in nonTriggerInputBindings)
            {
                BindingContext bindingContext = new BindingContext
                {
                    Binder      = binder,
                    BindingData = bindingData,
                    DataType    = inputBinding.Metadata.DataType ?? DataType.String
                };
                await inputBinding.BindAsync(bindingContext);

                // Perform any JSON to object conversions if the
                // value is JSON or a JToken
                object value = bindingContext.Value;
                object converted;
                if (TryConvertJson(bindingContext.Value, out converted))
                {
                    value = converted;
                }

                bindings.Add(inputBinding.Metadata.Name, value);
                inputs.Add(value);
            }

            executionContext["inputs"] = inputs;
        }
コード例 #11
0
        private static async Task ProcessOutputBindingsAsync(Collection <FunctionBinding> outputBindings, object input, IBinderEx binder,
                                                             Dictionary <string, string> bindingData, Dictionary <string, object> scriptExecutionContext, object functionResult)
        {
            if (outputBindings == null)
            {
                return;
            }

            // if the function returned binding values via the function result,
            // apply them to context.bindings
            var bindings = (Dictionary <string, object>)scriptExecutionContext["bindings"];
            IDictionary <string, object> functionOutputs = functionResult as IDictionary <string, object>;

            if (functionOutputs != null)
            {
                foreach (var output in functionOutputs)
                {
                    bindings[output.Key] = output.Value;
                }
            }

            foreach (FunctionBinding binding in outputBindings)
            {
                // get the output value from the script
                object value = null;
                if (bindings.TryGetValue(binding.Metadata.Name, out value) && value != null)
                {
                    if (value.GetType() == typeof(ExpandoObject) ||
                        (value is Array && value.GetType() != typeof(byte[])))
                    {
                        value = JsonConvert.SerializeObject(value);
                    }

                    BindingContext bindingContext = new BindingContext
                    {
                        TriggerValue = input,
                        Binder       = binder,
                        BindingData  = bindingData,
                        Value        = value
                    };
                    await binding.BindAsync(bindingContext);
                }
            }
        }
コード例 #12
0
        internal async Task ExecuteScriptAsync(string path, string arguments, object[] invocationParameters)
        {
            object           input       = invocationParameters[0];
            TraceWriter      traceWriter = (TraceWriter)invocationParameters[1];
            IBinderEx        binder      = (IBinderEx)invocationParameters[2];
            ExecutionContext functionExecutionContext = (ExecutionContext)invocationParameters[3];
            string           invocationId             = functionExecutionContext.InvocationId.ToString();

            FunctionStartedEvent startedEvent = new FunctionStartedEvent(functionExecutionContext.InvocationId, Metadata);

            _metrics.BeginEvent(startedEvent);

            // perform any required input conversions
            object convertedInput = input;

            if (input != null)
            {
                HttpRequestMessage request = input as HttpRequestMessage;
                if (request != null)
                {
                    // TODO: Handle other content types? (E.g. byte[])
                    if (request.Content != null && request.Content.Headers.ContentLength > 0)
                    {
                        convertedInput = ((HttpRequestMessage)input).Content.ReadAsStringAsync().Result;
                    }
                }
            }

            TraceWriter.Info(string.Format("Function started (Id={0})", invocationId));

            string workingDirectory           = Path.GetDirectoryName(_scriptFilePath);
            string functionInstanceOutputPath = Path.Combine(Path.GetTempPath(), "Functions", "Binding", invocationId);

            Dictionary <string, string> environmentVariables = new Dictionary <string, string>();

            InitializeEnvironmentVariables(environmentVariables, functionInstanceOutputPath, input, _outputBindings, functionExecutionContext);

            Dictionary <string, string> bindingData = GetBindingData(convertedInput, binder);

            bindingData["InvocationId"] = invocationId;

            await ProcessInputBindingsAsync(convertedInput, functionInstanceOutputPath, binder, bindingData, environmentVariables);

            // TODO
            // - put a timeout on how long we wait?
            // - need to periodically flush the standard out to the TraceWriter
            Process process = CreateProcess(path, workingDirectory, arguments, environmentVariables);

            process.Start();
            process.WaitForExit();

            bool failed = process.ExitCode != 0;

            startedEvent.Success = !failed;
            _metrics.EndEvent(startedEvent);

            if (failed)
            {
                startedEvent.Success = false;

                TraceWriter.Error(string.Format("Function completed (Failure, Id={0})", invocationId));

                string error = process.StandardError.ReadToEnd();
                throw new ApplicationException(error);
            }

            string output = process.StandardOutput.ReadToEnd();

            TraceWriter.Info(output);
            traceWriter.Info(output);

            await ProcessOutputBindingsAsync(functionInstanceOutputPath, _outputBindings, input, binder, bindingData);

            TraceWriter.Info(string.Format("Function completed (Success, Id={0})", invocationId));
        }
コード例 #13
0
        private async Task ProcessInputBindingsAsync(object input, string functionInstanceOutputPath, IBinderEx binder, Dictionary <string, string> bindingData, Dictionary <string, string> environmentVariables)
        {
            // if there are any input or output bindings declared, set up the temporary
            // output directory
            if (_outputBindings.Count > 0 || _inputBindings.Any())
            {
                Directory.CreateDirectory(functionInstanceOutputPath);
            }

            // process input bindings
            foreach (var inputBinding in _inputBindings)
            {
                string filePath = System.IO.Path.Combine(functionInstanceOutputPath, inputBinding.Metadata.Name);
                using (FileStream stream = File.OpenWrite(filePath))
                {
                    // If this is the trigger input, write it directly to the stream.
                    // The trigger binding is a special case because it is early bound
                    // rather than late bound as is the case with all the other input
                    // bindings.
                    if (inputBinding.Metadata.IsTrigger)
                    {
                        if (input is string)
                        {
                            using (StreamWriter sw = new StreamWriter(stream))
                            {
                                await sw.WriteAsync((string)input);
                            }
                        }
                        else if (input is byte[])
                        {
                            byte[] bytes = input as byte[];
                            await stream.WriteAsync(bytes, 0, bytes.Length);
                        }
                        else if (input is Stream)
                        {
                            Stream inputStream = input as Stream;
                            await inputStream.CopyToAsync(stream);
                        }
                    }
                    else
                    {
                        // invoke the input binding
                        BindingContext bindingContext = new BindingContext
                        {
                            Binder      = binder,
                            BindingData = bindingData,
                            DataType    = DataType.Stream,
                            Value       = stream
                        };
                        await inputBinding.BindAsync(bindingContext);
                    }
                }

                environmentVariables[inputBinding.Metadata.Name] = Path.Combine(functionInstanceOutputPath, inputBinding.Metadata.Name);
            }
        }
コード例 #14
0
        private static async Task ProcessOutputBindingsAsync(Collection <FunctionBinding> outputBindings, object input, IBinderEx binder,
                                                             Dictionary <string, string> bindingData, Dictionary <string, object> scriptExecutionContext, object functionResult)
        {
            if (outputBindings == null)
            {
                return;
            }

            // if the function returned binding values via the function result,
            // apply them to context.bindings
            var bindings = (Dictionary <string, object>)scriptExecutionContext["bindings"];
            IDictionary <string, object> functionOutputs = functionResult as IDictionary <string, object>;

            if (functionOutputs != null)
            {
                foreach (var output in functionOutputs)
                {
                    bindings[output.Key] = output.Value;
                }
            }

            foreach (FunctionBinding binding in outputBindings)
            {
                // get the output value from the script
                // we support primatives (int, string, object) as well as arrays of these
                object value = null;
                if (bindings.TryGetValue(binding.Metadata.Name, out value))
                {
                    // we only support strings, objects, or arrays of those (not primitive types like int)
                    if (value.GetType() == typeof(ExpandoObject) ||
                        value is Array)
                    {
                        value = JsonConvert.SerializeObject(value);
                    }

                    if (!(value is string))
                    {
                        throw new InvalidOperationException(string.Format("Invalid value specified for binding '{0}'", binding.Metadata.Name));
                    }

                    byte[] bytes = Encoding.UTF8.GetBytes((string)value);
                    using (MemoryStream ms = new MemoryStream(bytes))
                    {
                        BindingContext bindingContext = new BindingContext
                        {
                            Input       = input,
                            Binder      = binder,
                            BindingData = bindingData,
                            Value       = ms
                        };
                        await binding.BindAsync(bindingContext);
                    }
                }
            }
        }
コード例 #15
0
        private async Task ProcessInputBindingsAsync(object input, string functionInstanceOutputPath, IBinderEx binder, Dictionary<string, string> bindingData, Dictionary<string, string> environmentVariables)
        {
            // if there are any input or output bindings declared, set up the temporary
            // output directory
            if (_outputBindings.Count > 0 || _inputBindings.Any())
            {
                Directory.CreateDirectory(functionInstanceOutputPath);
            }

            // process input bindings
            foreach (var inputBinding in _inputBindings)
            {
                string filePath = System.IO.Path.Combine(functionInstanceOutputPath, inputBinding.Metadata.Name);
                using (FileStream stream = File.OpenWrite(filePath))
                {
                    // If this is the trigger input, write it directly to the stream.
                    // The trigger binding is a special case because it is early bound
                    // rather than late bound as is the case with all the other input
                    // bindings.
                    if (inputBinding.Metadata.IsTrigger)
                    {
                        if (input is string)
                        {
                            using (StreamWriter sw = new StreamWriter(stream))
                            {
                                await sw.WriteAsync((string)input);
                            }
                        }
                        else if (input is byte[])
                        {
                            byte[] bytes = input as byte[];
                            await stream.WriteAsync(bytes, 0, bytes.Length);
                        }
                        else if (input is Stream)
                        {
                            Stream inputStream = input as Stream;
                            await inputStream.CopyToAsync(stream);
                        }
                    }
                    else
                    {
                        // invoke the input binding
                        BindingContext bindingContext = new BindingContext
                        {
                            Binder = binder,
                            BindingData = bindingData,
                            Value = stream
                        };
                        await inputBinding.BindAsync(bindingContext);
                    }
                }

                environmentVariables[inputBinding.Metadata.Name] = Path.Combine(functionInstanceOutputPath, inputBinding.Metadata.Name);
            }
        }
コード例 #16
0
        private static async Task ProcessOutputBindingsAsync(string functionInstanceOutputPath, Collection<FunctionBinding> outputBindings,
            object input, IBinderEx binder, Dictionary<string, string> bindingData)
        {
            if (outputBindings == null)
            {
                return;
            }

            try
            {
                foreach (var outputBinding in outputBindings)
                {
                    string filePath = System.IO.Path.Combine(functionInstanceOutputPath, outputBinding.Metadata.Name);
                    if (File.Exists(filePath))
                    {
                        using (FileStream stream = File.OpenRead(filePath))
                        {
                            BindingContext bindingContext = new BindingContext
                            {
                                Input = input,
                                Binder = binder,
                                BindingData = bindingData,
                                Value = stream
                            };
                            await outputBinding.BindAsync(bindingContext);
                        }
                    }
                }
            }
            finally
            {
                // clean up the output directory
                if (outputBindings.Any() && Directory.Exists(functionInstanceOutputPath))
                {
                    Directory.Delete(functionInstanceOutputPath, recursive: true);
                }
            }
        }
コード例 #17
0
        private static async Task ProcessOutputBindingsAsync(Collection<FunctionBinding> outputBindings, object input, IBinderEx binder, 
            Dictionary<string, string> bindingData, Dictionary<string, object> scriptExecutionContext, object functionResult)
        {
            if (outputBindings == null)
            {
                return;
            }

            // if the function returned binding values via the function result,
            // apply them to context.bindings
            var bindings = (Dictionary<string, object>)scriptExecutionContext["bindings"];
            IDictionary<string, object> functionOutputs = functionResult as IDictionary<string, object>;
            if (functionOutputs != null)
            {
                foreach (var output in functionOutputs)
                {
                    bindings[output.Key] = output.Value;
                }
            }

            foreach (FunctionBinding binding in outputBindings)
            {
                // get the output value from the script
                // we support primatives (int, string, object) as well as arrays of these
                object value = null;
                if (bindings.TryGetValue(binding.Metadata.Name, out value))
                {
                    // we only support strings, objects, or arrays of those (not primitive types like int)
                    if (value.GetType() == typeof(ExpandoObject) ||
                        value is Array)
                    {
                        value = JsonConvert.SerializeObject(value);
                    }

                    if (!(value is string))
                    {
                        throw new InvalidOperationException(string.Format("Invalid value specified for binding '{0}'", binding.Metadata.Name));
                    }

                    byte[] bytes = Encoding.UTF8.GetBytes((string)value);
                    using (MemoryStream ms = new MemoryStream(bytes))
                    {
                        BindingContext bindingContext = new BindingContext
                        {
                            Input = input,
                            Binder = binder,
                            BindingData = bindingData,
                            Value = ms
                        };
                        await binding.BindAsync(bindingContext);
                    }
                }
            }
        }
コード例 #18
0
        private async Task ProcessInputBindingsAsync(IBinderEx binder, Dictionary<string, object> executionContext, Dictionary<string, string> bindingData)
        {
            var bindings = (Dictionary<string, object>)executionContext["bindings"];

            // create an ordered array of all inputs and add to
            // the execution context. These will be promoted to
            // positional parameters
            List<object> inputs = new List<object>();
            inputs.Add(bindings[_trigger.Name]);

            var nonTriggerInputBindings = _inputBindings.Where(p => !p.Metadata.IsTrigger);
            foreach (var inputBinding in nonTriggerInputBindings)
            {
                string stringValue = null;
                using (MemoryStream stream = new MemoryStream())
                {
                    BindingContext bindingContext = new BindingContext
                    {
                        Binder = binder,
                        BindingData = bindingData,
                        Value = stream
                    };
                    await inputBinding.BindAsync(bindingContext);

                    stream.Seek(0, SeekOrigin.Begin);
                    StreamReader sr = new StreamReader(stream);
                    stringValue = sr.ReadToEnd();
                }

                // if the input is json, try converting to an object
                object convertedValue = stringValue;
                convertedValue = TryConvertJsonToObject(stringValue);

                bindings.Add(inputBinding.Metadata.Name, convertedValue);
                inputs.Add(convertedValue);
            }

            executionContext["inputs"] = inputs;
        }
コード例 #19
0
        private Dictionary <string, object> CreateScriptExecutionContext(object input, DataType dataType, IBinderEx binder, TraceWriter traceWriter, TraceWriter fileTraceWriter, ExecutionContext functionExecutionContext)
        {
            // create a TraceWriter wrapper that can be exposed to Node.js
            var log = (Func <object, Task <object> >)(p =>
            {
                string text = p as string;
                if (text != null)
                {
                    traceWriter.Info(text);
                    fileTraceWriter.Info(text);
                }

                return(Task.FromResult <object>(null));
            });

            var bindings = new Dictionary <string, object>();
            var bind     = (Func <object, Task <object> >)(p =>
            {
                IDictionary <string, object> bindValues = (IDictionary <string, object>)p;
                foreach (var bindValue in bindValues)
                {
                    bindings[bindValue.Key] = bindValue.Value;
                }
                return(Task.FromResult <object>(null));
            });

            var context = new Dictionary <string, object>()
            {
                { "invocationId", functionExecutionContext.InvocationId },
                { "log", log },
                { "bindings", bindings },
                { "bind", bind }
            };

            // This is the input value that we will use to extract binding data.
            // Since binding data extraction is based on JSON parsing, in the
            // various conversions below, we set this to the appropriate JSON
            // string when possible.
            object bindDataInput = input;

            if (input is HttpRequestMessage)
            {
                // convert the request to a json object
                HttpRequestMessage request = (HttpRequestMessage)input;
                string             rawBody = null;
                var requestObject          = CreateRequestObject(request, out rawBody);
                input = requestObject;

                if (rawBody != null)
                {
                    requestObject["rawBody"] = rawBody;
                    bindDataInput            = rawBody;
                }

                // If this is a WebHook function, the input should be the
                // request body
                HttpTriggerBindingMetadata httpBinding = _trigger as HttpTriggerBindingMetadata;
                if (httpBinding != null &&
                    !string.IsNullOrEmpty(httpBinding.WebHookType))
                {
                    input = requestObject["body"];

                    // make the entire request object available as well
                    // this is symmetric with context.res which we also support
                    context["req"] = requestObject;
                }
            }
            else if (input is TimerInfo)
            {
                TimerInfo timerInfo   = (TimerInfo)input;
                var       inputValues = new Dictionary <string, object>()
                {
                    { "isPastDue", timerInfo.IsPastDue }
                };
                if (timerInfo.ScheduleStatus != null)
                {
                    inputValues["last"] = timerInfo.ScheduleStatus.Last.ToString("s", CultureInfo.InvariantCulture);
                    inputValues["next"] = timerInfo.ScheduleStatus.Next.ToString("s", CultureInfo.InvariantCulture);
                }
                input = inputValues;
            }
            else if (input is Stream)
            {
                FunctionBinding.ConvertStreamToValue((Stream)input, dataType, ref input);
            }

            context["bindingData"] = GetBindingData(bindDataInput, binder);

            // if the input is json, try converting to an object or array
            object converted;

            if (TryConvertJson(input, out converted))
            {
                input = converted;
            }

            bindings.Add(_trigger.Name, input);

            return(context);
        }
コード例 #20
0
 /// <summary>
 /// We need to merge the ambient binding data that already exists in the IBinder
 /// with our binding data. We have to do this rather than relying solely on
 /// IBinder.BindAsync because we need to include any POCO values we get from parsing
 /// JSON bodies, etc.
 /// TEMP: We might find a better way to do this in the future, perhaps via core
 /// SDK changes.
 /// </summary>
 protected static void ApplyAmbientBindingData(IBinderEx binder, IDictionary<string, string> bindingData)
 {
     var ambientBindingData = binder.BindingContext.BindingData;
     if (ambientBindingData != null)
     {
         // apply the binding data to ours
         foreach (var item in ambientBindingData)
         {
             if (item.Value != null)
             {
                 bindingData[item.Key] = item.Value.ToString();
             }
         }
     }
 }