Exemplo n.º 1
0
        protected override async Task InvokeCore(object[] parameters, FunctionInvocationContext context)
        {
            string scriptHostArguments;

            switch (Metadata.ScriptType)
            {
            case ScriptType.WindowsBatch:
                scriptHostArguments = string.Format("/c \"{0}\"", _scriptFilePath);
                await ExecuteScriptAsync("cmd", scriptHostArguments, parameters, context);

                break;

            case ScriptType.Python:
                // Passing -u forces stdout to be unbuffered so we can log messages as they happen.
                scriptHostArguments = string.Format("-u \"{0}\"", _scriptFilePath);
                await ExecuteScriptAsync("python.exe", scriptHostArguments, parameters, context);

                break;

            case ScriptType.PHP:
                scriptHostArguments = string.Format("\"{0}\"", _scriptFilePath);
                await ExecuteScriptAsync("php.exe", scriptHostArguments, parameters, context);

                break;

            case ScriptType.Bash:
                scriptHostArguments = string.Format("\"{0}\"", _scriptFilePath);
                string bashPath = ResolveBashPath();
                await ExecuteScriptAsync(bashPath, scriptHostArguments, parameters, context);

                break;
            }
        }
 protected override async Task InvokeCore(object[] parameters, FunctionInvocationContext context)
 {
     string scriptHostArguments;
     switch (Metadata.ScriptType)
     {
         case ScriptType.WindowsBatch:
             scriptHostArguments = string.Format("/c \"{0}\"", _scriptFilePath);
             await ExecuteScriptAsync("cmd", scriptHostArguments, parameters, context);
             break;
         case ScriptType.Python:
             // Passing -u forces stdout to be unbuffered so we can log messages as they happen.
             scriptHostArguments = string.Format("-u \"{0}\"", _scriptFilePath);
             await ExecuteScriptAsync("python.exe", scriptHostArguments, parameters, context);
             break;
         case ScriptType.PHP:
             scriptHostArguments = string.Format("\"{0}\"", _scriptFilePath);
             await ExecuteScriptAsync("php.exe", scriptHostArguments, parameters, context);
             break;
         case ScriptType.Bash:
             scriptHostArguments = string.Format("\"{0}\"", _scriptFilePath);
             string bashPath = ResolveBashPath();
             await ExecuteScriptAsync(bashPath, scriptHostArguments, parameters, context);
             break;
     }
 }
        protected override async Task <object> InvokeCore(object[] parameters, FunctionInvocationContext context)
        {
            string invocationId = context.ExecutionContext.InvocationId.ToString();

            // TODO: fix extensions and remove
            object triggerValue = TransformInput(parameters[0], context.Binder.BindingData);
            var    triggerInput = (_trigger.Name, _trigger.DataType ?? DataType.String, triggerValue);
            var    inputs = new[] { triggerInput }.Concat(await BindInputsAsync(context.Binder));

            ScriptInvocationContext invocationContext = new ScriptInvocationContext()
            {
                FunctionMetadata      = Metadata,
                BindingData           = context.Binder.BindingData,
                ExecutionContext      = context.ExecutionContext,
                Inputs                = inputs,
                ResultSource          = new TaskCompletionSource <ScriptInvocationResult>(),
                AsyncExecutionContext = System.Threading.ExecutionContext.Capture(),

                // TODO: link up cancellation token to parameter descriptors
                CancellationToken = CancellationToken.None,
                Logger            = context.Logger
            };

            ScriptInvocationResult result;

            _invocationBuffer.Post(invocationContext);
            result = await invocationContext.ResultSource.Task;

            await BindOutputsAsync(triggerValue, context.Binder, result);

            return(result.Return);
        }
        protected override async Task InvokeCore(object[] parameters, FunctionInvocationContext context)
        {
            object input = parameters[0];
            string invocationId = context.ExecutionContext.InvocationId.ToString();

            object convertedInput = ConvertInput(input);
            Utility.ApplyBindingData(convertedInput, context.Binder.BindingData);
            Dictionary<string, object> bindingData = context.Binder.BindingData;
            bindingData["InvocationId"] = invocationId;

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

            string functionInstanceOutputPath = Path.Combine(Path.GetTempPath(), "Functions", "Binding", invocationId);
            await ProcessInputBindingsAsync(convertedInput, functionInstanceOutputPath, context.Binder, _inputBindings, _outputBindings, bindingData, environmentVariables);

            InitializeEnvironmentVariables(environmentVariables, functionInstanceOutputPath, input, _outputBindings, context.ExecutionContext);

            var userTraceWriter = CreateUserTraceWriter(context.TraceWriter);
            PSDataCollection<ErrorRecord> errors = await InvokePowerShellScript(environmentVariables, userTraceWriter);

            await ProcessOutputBindingsAsync(functionInstanceOutputPath, _outputBindings, input, context.Binder, bindingData);

            ErrorRecord error = errors.FirstOrDefault();
            if (error != null)
            {
                throw new RuntimeException("PowerShell script error", error.Exception, error);
            }
        }
Exemplo n.º 5
0
        protected override async Task <object> InvokeCore(object[] parameters, FunctionInvocationContext context)
        {
            MethodInfo function = await GetFunctionTargetAsync(isInvocation : true);

            // Separate system parameters from the actual method parameters
            object[] originalParameters   = parameters;
            int      actualParameterCount = function.GetParameters().Length;

            parameters = parameters.Take(actualParameterCount).ToArray();

            object result = function.Invoke(null, parameters);

            // after the function executes, we have to copy values back into the original
            // array to ensure object references are maintained (since we took a copy above)
            for (int i = 0; i < parameters.Length; i++)
            {
                originalParameters[i] = parameters[i];
            }

            // unwrap the task
            if (result is Task)
            {
                result = await((Task)result).ContinueWith(t => GetTaskResult(t), TaskContinuationOptions.ExecuteSynchronously);
            }

            return(result);
        }
        protected override async Task InvokeCore(object[] parameters, FunctionInvocationContext context)
        {
            object requestObj = (parameters != null && parameters.Any()) ? parameters[0] : null;

            if (requestObj == null || !(requestObj is HttpRequestMessage))
            {
                throw new Exception("Could not find parameter of type HttpRequestMessage while executing a Proxy Request");
            }

            await _proxyClient.Execute(requestObj as HttpRequestMessage, context.Logger);
        }
 private static IDisposable BeginFunctionScope(FunctionInvocationContext context)
 {
     // Node captures the AsyncLocal value of the first invocation, which means that logs
     // are correlated incorrectly. Here we'll overwrite that value with the correct value
     // immediately before logging.
     return(context.Logger.BeginScope(
                new Dictionary <string, object>
     {
         ["MS_FunctionName"] = context.ExecutionContext.FunctionName,
         ["MS_FunctionInvocationId"] = context.ExecutionContext.InvocationId.ToString()
     }));
 }
        protected override async Task <object> InvokeCore(object[] parameters, FunctionInvocationContext context)
        {
            HttpRequest requestObj = parameters?.FirstOrDefault() as HttpRequest;

            if (requestObj == null)
            {
                throw new Exception("Could not find parameter of type HttpRequest while executing a Proxy Request");
            }

            await _proxyClient.Execute(requestObj, context.Logger);

            return(requestObj.HttpContext.Items[ScriptConstants.AzureFunctionsHttpResponseKey]);
        }
Exemplo n.º 9
0
        protected override async Task <object> InvokeCore(object[] parameters, FunctionInvocationContext context)
        {
            // Need to wait for at least one language worker process to be initialized before accepting invocations
            if (!IsDispatcherReady())
            {
                await DelayUntilFunctionDispatcherInitializedOrShutdown();
            }

            var    bindingData  = context.Binder.BindingData;
            object triggerValue = TransformInput(parameters[0], bindingData);
            var    triggerInput = (_bindingMetadata.Name, _bindingMetadata.DataType ?? DataType.String, triggerValue);
            IEnumerable <(string, DataType, object)> inputs = new[] { triggerInput };

            if (_inputBindings.Count > 1)
            {
                var nonTriggerInputs = await BindInputsAsync(context.Binder);

                inputs = inputs.Concat(nonTriggerInputs);
            }

            var invocationContext = new ScriptInvocationContext
            {
                FunctionMetadata      = Metadata,
                BindingData           = bindingData,
                ExecutionContext      = context.ExecutionContext,
                Inputs                = inputs,
                ResultSource          = new TaskCompletionSource <ScriptInvocationResult>(),
                AsyncExecutionContext = System.Threading.ExecutionContext.Capture(),
                Traceparent           = Activity.Current?.Id,
                Tracestate            = Activity.Current?.TraceStateString,
                Attributes            = Activity.Current?.Tags,

                // TODO: link up cancellation token to parameter descriptors
                CancellationToken = CancellationToken.None,
                Logger            = context.Logger
            };

            string invocationId = context.ExecutionContext.InvocationId.ToString();

            _logger.LogTrace($"Sending invocation id:{invocationId}");
            await _functionDispatcher.InvokeAsync(invocationContext);

            var result = await invocationContext.ResultSource.Task;

            await BindOutputsAsync(triggerValue, context.Binder, result);

            return(result.Return);
        }
Exemplo n.º 10
0
        protected override async Task InvokeCore(object[] parameters, FunctionInvocationContext context)
        {
            object   input        = parameters[0];
            string   invocationId = context.ExecutionContext.InvocationId.ToString();
            DataType dataType     = _trigger.DataType ?? DataType.String;

            var userTraceWriter        = CreateUserTraceWriter(context.TraceWriter);
            var scriptExecutionContext = CreateScriptExecutionContext(input, dataType, userTraceWriter, context);
            var bindingData            = (Dictionary <string, object>)scriptExecutionContext["bindingData"];

            await ProcessInputBindingsAsync(context.Binder, scriptExecutionContext, bindingData);

            object functionResult = await ScriptFunc(scriptExecutionContext);

            await ProcessOutputBindingsAsync(_outputBindings, input, context.Binder, bindingData, scriptExecutionContext, functionResult);
        }
        internal async Task ExecuteScriptAsync(string path, string arguments, object[] invocationParameters, FunctionInvocationContext context)
        {
            object input = invocationParameters[0];
            string invocationId = context.ExecutionContext.InvocationId.ToString();

            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, context.ExecutionContext);

            object convertedInput = ConvertInput(input);
            Utility.ApplyBindingData(convertedInput, context.Binder.BindingData);
            Dictionary<string, object> bindingData = context.Binder.BindingData;
            bindingData["InvocationId"] = invocationId;

            await ProcessInputBindingsAsync(convertedInput, functionInstanceOutputPath, context.Binder, _inputBindings, _outputBindings, bindingData, environmentVariables);

            Process process = CreateProcess(path, workingDirectory, arguments, environmentVariables);
            var userTraceWriter = CreateUserTraceWriter(context.TraceWriter);
            process.OutputDataReceived += (s, e) =>
            {
                if (e.Data != null)
                {
                    userTraceWriter.Info(e.Data);
                }
            };

            var tcs = new TaskCompletionSource<object>();
            process.Exited += (sender, args) =>
            {
                tcs.TrySetResult(null);
            };

            process.Start();
            process.BeginOutputReadLine();

            await tcs.Task;

            if (process.ExitCode != 0)
            {
                string error = process.StandardError.ReadToEnd();
                throw new ApplicationException(error);
            }

            await ProcessOutputBindingsAsync(functionInstanceOutputPath, _outputBindings, input, context.Binder, bindingData);
        }
        private static FunctionInvocationContext GetContextFromParameters(object[] parameters, FunctionMetadata metadata)
        {
            ExecutionContext functionExecutionContext = null;
            Binder           binder = null;
            ILogger          logger = null;

            for (var i = 0; i < parameters.Length; i++)
            {
                switch (parameters[i])
                {
                case ExecutionContext fc:
                    functionExecutionContext ??= fc;
                    break;

                case Binder b:
                    binder ??= b;
                    break;

                case ILogger l:
                    logger ??= l;
                    break;
                }
            }

            // We require the ExecutionContext, so this will throw if one is not found.
            if (functionExecutionContext == null)
            {
                throw new ArgumentException("Function ExecutionContext was not found");
            }

            functionExecutionContext.FunctionDirectory = metadata.FunctionDirectory;
            functionExecutionContext.FunctionName      = metadata.Name;

            FunctionInvocationContext context = new FunctionInvocationContext
            {
                ExecutionContext = functionExecutionContext,
                Binder           = binder,
                Logger           = logger
            };

            return(context);
        }
        protected override async Task<object> InvokeCore(object[] parameters, FunctionInvocationContext context)
        {
            MethodInfo function = await GetFunctionTargetAsync(isInvocation: true);

            // Separate system parameters from the actual method parameters
            object[] originalParameters = parameters;
            int actualParameterCount = function.GetParameters().Length;
            parameters = parameters.Take(actualParameterCount).ToArray();

            object result = await _methodInvoker.InvokeAsync(null, parameters);

            // after the function executes, we have to copy values back into the original
            // array to ensure object references are maintained (since we took a copy above)
            for (int i = 0; i < parameters.Length; i++)
            {
                originalParameters[i] = parameters[i];
            }

            return result;
        }
Exemplo n.º 14
0
        protected override async Task InvokeCore(object[] parameters, FunctionInvocationContext context)
        {
            // Separate system parameters from the actual method parameters
            object[]   originalParameters = parameters;
            MethodInfo function           = await GetFunctionTargetAsync();

            int actualParameterCount = function.GetParameters().Length;

            object[] systemParameters = parameters.Skip(actualParameterCount).ToArray();
            parameters = parameters.Take(actualParameterCount).ToArray();

            parameters = ProcessInputParameters(parameters);

            object result = function.Invoke(null, parameters);

            // after the function executes, we have to copy values back into the original
            // array to ensure object references are maintained (since we took a copy above)
            for (int i = 0; i < parameters.Length; i++)
            {
                originalParameters[i] = parameters[i];
            }

            if (result is Task)
            {
                result = await((Task)result).ContinueWith(t => GetTaskResult(t), TaskContinuationOptions.ExecuteSynchronously);
            }

            if (result != null)
            {
                _resultProcessor(function, parameters, systemParameters, result);
            }

            // if a return value binding was specified, copy the return value
            // into the output binding slot (by convention the last parameter)
            var returnValueBinding = Metadata.Bindings.SingleOrDefault(p => p.IsReturn);

            if (returnValueBinding != null && !(returnValueBinding is IResultProcessingBinding))
            {
                originalParameters[originalParameters.Length - 1] = result;
            }
        }
Exemplo n.º 15
0
        private static FunctionInvocationContext GetContextFromParameters(object[] parameters, FunctionMetadata metadata)
        {
            // We require the ExecutionContext, so this will throw if one is not found.
            ExecutionContext functionExecutionContext = parameters.OfType <ExecutionContext>().First();

            functionExecutionContext.FunctionDirectory = metadata.FunctionDirectory;
            functionExecutionContext.FunctionName      = metadata.Name;

            // These may not be present, so null is okay.
            Binder  binder = parameters.OfType <Binder>().FirstOrDefault();
            ILogger logger = parameters.OfType <ILogger>().FirstOrDefault();

            FunctionInvocationContext context = new FunctionInvocationContext
            {
                ExecutionContext = functionExecutionContext,
                Binder           = binder,
                Logger           = logger
            };

            return(context);
        }
        protected override async Task InvokeCore(object[] parameters, FunctionInvocationContext context)
        {
            // Ensure we're properly initialized
            await _initializer.Value.ConfigureAwait(false);

            object   input        = parameters[0];
            string   invocationId = context.ExecutionContext.InvocationId.ToString();
            DataType dataType     = _trigger.DataType ?? DataType.String;

            var userTraceWriter        = CreateUserTraceWriter(context.TraceWriter);
            var scriptExecutionContext = await CreateScriptExecutionContextAsync(input, dataType, userTraceWriter, context).ConfigureAwait(false);

            var bindingData = (Dictionary <string, object>)scriptExecutionContext["bindingData"];

            await ProcessInputBindingsAsync(context.Binder, scriptExecutionContext, bindingData);

            ScriptFunc function = await GetFunctionTargetAsync();

            object functionResult = await function(scriptExecutionContext);

            await ProcessOutputBindingsAsync(_outputBindings, input, context.Binder, bindingData, scriptExecutionContext, functionResult);
        }
Exemplo n.º 17
0
        protected override async Task <object> InvokeCore(object[] parameters, FunctionInvocationContext context)
        {
            // Need to wait for atleast one language worker process to be initialized before accepting invocations
            await DelayUntilFunctionDispatcherInitialized();

            string invocationId = context.ExecutionContext.InvocationId.ToString();

            // TODO: fix extensions and remove
            object triggerValue = TransformInput(parameters[0], context.Binder.BindingData);
            var    triggerInput = (_bindingMetadata.Name, _bindingMetadata.DataType ?? DataType.String, triggerValue);
            var    inputs = new[] { triggerInput }.Concat(await BindInputsAsync(context.Binder));

            ScriptInvocationContext invocationContext = new ScriptInvocationContext()
            {
                FunctionMetadata      = Metadata,
                BindingData           = context.Binder.BindingData, // This has duplicates too (of type DefaultHttpRequest). Needs to be removed after verifying this can indeed be constructed by the workers from the rest of the data being passed (https://github.com/Azure/azure-functions-host/issues/4735).
                ExecutionContext      = context.ExecutionContext,
                Inputs                = inputs,
                ResultSource          = new TaskCompletionSource <ScriptInvocationResult>(),
                AsyncExecutionContext = System.Threading.ExecutionContext.Capture(),
                Traceparent           = Activity.Current?.Id,
                Attributes            = Activity.Current?.Tags,

                // TODO: link up cancellation token to parameter descriptors
                CancellationToken = CancellationToken.None,
                Logger            = context.Logger
            };

            ScriptInvocationResult result;

            _logger.LogDebug($"Sending invocation id:{invocationId}");
            await _functionDispatcher.InvokeAsync(invocationContext);

            result = await invocationContext.ResultSource.Task;

            await BindOutputsAsync(triggerValue, context.Binder, result);

            return(result.Return);
        }
Exemplo n.º 18
0
        protected override async Task <object> InvokeCore(object[] parameters, FunctionInvocationContext context)
        {
            // Need to wait for atleast one language worker process to be initialized before accepting invocations
            await DelayUntilFunctionDispatcherInitialized();

            string invocationId = context.ExecutionContext.InvocationId.ToString();

            // TODO: fix extensions and remove
            object triggerValue = TransformInput(parameters[0], context.Binder.BindingData);
            var    triggerInput = (_bindingMetadata.Name, _bindingMetadata.DataType ?? DataType.String, triggerValue);
            var    inputs = new[] { triggerInput }.Concat(await BindInputsAsync(context.Binder));

            ScriptInvocationContext invocationContext = new ScriptInvocationContext()
            {
                FunctionMetadata      = Metadata,
                BindingData           = context.Binder.BindingData,
                ExecutionContext      = context.ExecutionContext,
                Inputs                = inputs,
                ResultSource          = new TaskCompletionSource <ScriptInvocationResult>(),
                AsyncExecutionContext = System.Threading.ExecutionContext.Capture(),

                // TODO: link up cancellation token to parameter descriptors
                CancellationToken = CancellationToken.None,
                Logger            = context.Logger
            };

            ScriptInvocationResult result;

            _logger.LogDebug($"Sending invocation id:{invocationId}");
            await _functionDispatcher.InvokeAsync(invocationContext);

            result = await invocationContext.ResultSource.Task;

            await BindOutputsAsync(triggerValue, context.Binder, result);

            return(result.Return);
        }
Exemplo n.º 19
0
 protected abstract Task InvokeCore(object[] parameters, FunctionInvocationContext context);
Exemplo n.º 20
0
        public async Task Invoke(object[] parameters)
        {
            // We require the ExecutionContext, so this will throw if one is not found.
            ExecutionContext functionExecutionContext = parameters.OfType <ExecutionContext>().First();

            PopulateExecutionContext(functionExecutionContext);

            // These may not be present, so null is okay.
            TraceWriter functionTraceWriter = parameters.OfType <TraceWriter>().FirstOrDefault();
            Binder      binder       = parameters.OfType <Binder>().FirstOrDefault();
            ILogger     logger       = parameters.OfType <ILogger>().FirstOrDefault();
            string      invocationId = functionExecutionContext.InvocationId.ToString();

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

            _metrics.BeginEvent(startedEvent);
            var invokeLatencyEvent  = LogInvocationMetrics(_metrics, Metadata);
            var invocationStopWatch = new Stopwatch();

            invocationStopWatch.Start();

            try
            {
                string startMessage = $"Function started (Id={invocationId})";
                TraceWriter.Info(startMessage);
                Logger?.LogInformation(startMessage);

                FunctionInvocationContext context = new FunctionInvocationContext
                {
                    ExecutionContext = functionExecutionContext,
                    Binder           = binder,
                    TraceWriter      = functionTraceWriter,
                    Logger           = logger
                };

                await InvokeCore(parameters, context);

                invocationStopWatch.Stop();
                LogFunctionResult(startedEvent, true, invocationId, invocationStopWatch.ElapsedMilliseconds);
            }
            catch (AggregateException ex)
            {
                ExceptionDispatchInfo exInfo = null;

                // If there's only a single exception, rethrow it by itself
                Exception singleEx = ex.Flatten().InnerExceptions.SingleOrDefault();
                if (singleEx != null)
                {
                    exInfo = ExceptionDispatchInfo.Capture(singleEx);
                }
                else
                {
                    exInfo = ExceptionDispatchInfo.Capture(ex);
                }

                invocationStopWatch.Stop();
                LogFunctionResult(startedEvent, false, invocationId, invocationStopWatch.ElapsedMilliseconds);
                exInfo.Throw();
            }
            catch
            {
                invocationStopWatch.Stop();
                LogFunctionResult(startedEvent, false, invocationId, invocationStopWatch.ElapsedMilliseconds);
                throw;
            }
            finally
            {
                if (startedEvent != null)
                {
                    _metrics.EndEvent(startedEvent);
                }
                if (invokeLatencyEvent != null)
                {
                    _metrics.EndEvent(invokeLatencyEvent);
                }
            }
        }
        private async Task <Dictionary <string, object> > CreateScriptExecutionContextAsync(object input, DataType dataType, TraceWriter traceWriter, FunctionInvocationContext invocationContext)
        {
            // create a TraceWriter wrapper that can be exposed to Node.js
            var log = (ScriptFunc)(p =>
            {
                var logData = (IDictionary <string, object>)p;
                string message = (string)logData["msg"];
                if (message != null)
                {
                    try
                    {
                        TraceLevel level = (TraceLevel)logData["lvl"];
                        var evt = new TraceEvent(level, message);

                        // Node captures the AsyncLocal value of the first invocation, which means that logs
                        // are correlated incorrectly. Here we'll overwrite that value with the correct value
                        // immediately before logging.
                        using (invocationContext.Logger.BeginScope(
                                   new Dictionary <string, object>
                        {
                            ["MS_FunctionInvocationId"] = invocationContext.ExecutionContext.InvocationId
                        }))
                        {
                            // TraceWriter already logs to ILogger
                            traceWriter.Trace(evt);
                        }
                    }
                    catch (ObjectDisposedException)
                    {
                        // if a function attempts to write to a disposed
                        // TraceWriter. Might happen if a function tries to
                        // log after calling done()
                    }
                }

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

            var bindings = new Dictionary <string, object>();
            var bind     = (ScriptFunc)(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 executionContext = new Dictionary <string, object>
            {
                ["invocationId"]      = invocationContext.ExecutionContext.InvocationId,
                ["functionName"]      = invocationContext.ExecutionContext.FunctionName,
                ["functionDirectory"] = invocationContext.ExecutionContext.FunctionDirectory,
            };

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

            if (!string.IsNullOrEmpty(_entryPoint))
            {
                context["_entryPoint"] = _entryPoint;
            }

            // convert the request to a json object
            if (input is HttpRequestMessage request)
            {
                var requestObject = await CreateRequestObjectAsync(request).ConfigureAwait(false);

                input = requestObject;

                // If this is a WebHook function, the input should be the
                // request body
                var httpTrigger = _inputBindings.OfType <ExtensionBinding>().SingleOrDefault(p => p.Metadata.IsTrigger)?
                                  .Attributes.OfType <HttpTriggerAttribute>().SingleOrDefault();
                if (httpTrigger != null && !string.IsNullOrEmpty(httpTrigger.WebHookType))
                {
                    requestObject.TryGetValue("body", out input);
                }

                // 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)
            {
                // TODO: Need to generalize this model rather than hardcode
                // so other extensions can also express their Node.js object model
                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);
            }

            Utility.ApplyBindingData(input, invocationContext.Binder.BindingData);

            var bindingData = NormalizeBindingData(invocationContext.Binder.BindingData);

            bindingData["invocationId"] = invocationContext.ExecutionContext.InvocationId.ToString();
            context["bindingData"]      = bindingData;

            // 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);

            context.Add("_triggerType", _trigger.Type);

            return(context);
        }
        public async Task Invoke(object[] parameters)
        {
            // We require the ExecutionContext, so this will throw if one is not found.
            ExecutionContext functionExecutionContext = parameters.OfType<ExecutionContext>().First();

            // These may not be present, so null is okay.
            TraceWriter functionTraceWriter = parameters.OfType<TraceWriter>().FirstOrDefault();
            Binder binder = parameters.OfType<Binder>().FirstOrDefault();

            string invocationId = functionExecutionContext.InvocationId.ToString();

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

            LogInvocationMetrics(_metrics, Metadata.Bindings);

            try
            {
                TraceWriter.Info($"Function started (Id={invocationId})");

                FunctionInvocationContext context = new FunctionInvocationContext
                {
                    ExecutionContext = functionExecutionContext,
                    Binder = binder,
                    TraceWriter = functionTraceWriter
                };

                await InvokeCore(parameters, context);

                TraceWriter.Info($"Function completed (Success, Id={invocationId})");
            }
            catch (AggregateException ex)
            {
                ExceptionDispatchInfo exInfo = null;

                // If there's only a single exception, rethrow it by itself
                Exception singleEx = ex.Flatten().InnerExceptions.SingleOrDefault();
                if (singleEx != null)
                {
                    exInfo = ExceptionDispatchInfo.Capture(singleEx);
                }
                else
                {
                    exInfo = ExceptionDispatchInfo.Capture(ex);
                }

                LogFunctionFailed(startedEvent, "Failure", invocationId);
                exInfo.Throw();
            }
            catch
            {
                LogFunctionFailed(startedEvent, "Failure", invocationId);
                throw;
            }
            finally
            {
                if (startedEvent != null)
                {
                    _metrics.EndEvent(startedEvent);
                }
            }
        }
 protected override Task InvokeCore(object[] parameters, FunctionInvocationContext context)
 {
     throw new NotImplementedException();
 }
Exemplo n.º 24
0
        private Dictionary <string, object> CreateScriptExecutionContext(object input, DataType dataType, TraceWriter traceWriter, FunctionInvocationContext invocationContext)
        {
            // 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)
                {
                    try
                    {
                        traceWriter.Info(text);
                    }
                    catch (ObjectDisposedException)
                    {
                        // if a function attempts to write to a disposed
                        // TraceWriter. Might happen if a function tries to
                        // log after calling done()
                    }
                }

                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", invocationContext.ExecutionContext.InvocationId },
                { "log", log },
                { "bindings", bindings },
                { "bind", bind }
            };

            if (!string.IsNullOrEmpty(_entryPoint))
            {
                context["_entryPoint"] = _entryPoint;
            }

            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;
                }

                // 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))
                {
                    requestObject.TryGetValue("body", out input);
                }

                // 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)
            {
                // TODO: Need to generalize this model rather than hardcode
                // so other extensions can also express their Node.js object model
                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);
            }

            Utility.ApplyBindingData(input, invocationContext.Binder.BindingData);
            var bindingData = NormalizeBindingData(invocationContext.Binder.BindingData);

            bindingData["invocationId"] = invocationContext.ExecutionContext.InvocationId.ToString();
            context["bindingData"]      = bindingData;

            // 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);

            context.Add("_triggerType", _trigger.Type);

            return(context);
        }
 protected abstract Task InvokeCore(object[] parameters, FunctionInvocationContext context);
        public async Task Invoke(object[] parameters)
        {
            // We require the ExecutionContext, so this will throw if one is not found.
            ExecutionContext functionExecutionContext = parameters.OfType <ExecutionContext>().First();

            // These may not be present, so null is okay.
            TraceWriter functionTraceWriter = parameters.OfType <TraceWriter>().FirstOrDefault();
            Binder      binder = parameters.OfType <Binder>().FirstOrDefault();

            string invocationId = functionExecutionContext.InvocationId.ToString();

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

            _metrics.BeginEvent(startedEvent);

            LogInvocationMetrics(_metrics, Metadata.Bindings);

            try
            {
                TraceWriter.Info($"Function started (Id={invocationId})");

                FunctionInvocationContext context = new FunctionInvocationContext
                {
                    ExecutionContext = functionExecutionContext,
                    Binder           = binder,
                    TraceWriter      = functionTraceWriter
                };

                await InvokeCore(parameters, context);

                TraceWriter.Info($"Function completed (Success, Id={invocationId})");
            }
            catch (AggregateException ex)
            {
                ExceptionDispatchInfo exInfo = null;

                // If there's only a single exception, rethrow it by itself
                Exception singleEx = ex.Flatten().InnerExceptions.SingleOrDefault();
                if (singleEx != null)
                {
                    exInfo = ExceptionDispatchInfo.Capture(singleEx);
                }
                else
                {
                    exInfo = ExceptionDispatchInfo.Capture(ex);
                }

                LogFunctionFailed(startedEvent, "Failure", invocationId);
                exInfo.Throw();
            }
            catch
            {
                LogFunctionFailed(startedEvent, "Failure", invocationId);
                throw;
            }
            finally
            {
                if (startedEvent != null)
                {
                    _metrics.EndEvent(startedEvent);
                }
            }
        }
 protected override Task InvokeCore(object[] parameters, FunctionInvocationContext context)
 {
     throw new NotImplementedException();
 }
        public async Task Invoke(object[] parameters)
        {
            FunctionInvocationContext context = GetContextFromParameters(parameters, Metadata);

            await InvokeCore(parameters, context);
        }
Exemplo n.º 29
0
        internal async Task ExecuteScriptAsync(string path, string arguments, object[] invocationParameters, FunctionInvocationContext context)
        {
            object input        = invocationParameters[0];
            string invocationId = context.ExecutionContext.InvocationId.ToString();

            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, context.ExecutionContext);

            object convertedInput = ConvertInput(input);

            Utility.ApplyBindingData(convertedInput, context.Binder.BindingData);
            Dictionary <string, object> bindingData = context.Binder.BindingData;

            bindingData["InvocationId"] = invocationId;

            await ProcessInputBindingsAsync(convertedInput, functionInstanceOutputPath, context.Binder, _inputBindings, _outputBindings, bindingData, environmentVariables);

            Process process         = CreateProcess(path, workingDirectory, arguments, environmentVariables);
            var     userTraceWriter = CreateUserTraceWriter(context.TraceWriter);

            process.OutputDataReceived += (s, e) =>
            {
                if (e.Data != null)
                {
                    // the user's TraceWriter will automatically log to ILogger as well
                    userTraceWriter.Info(e.Data);
                }
            };

            var tcs = new TaskCompletionSource <object>();

            process.Exited += (sender, args) =>
            {
                tcs.TrySetResult(null);
            };

            process.Start();
            process.BeginOutputReadLine();

            await tcs.Task;

            if (process.ExitCode != 0)
            {
                string error = process.StandardError.ReadToEnd();
                throw new ApplicationException(error);
            }

            await ProcessOutputBindingsAsync(functionInstanceOutputPath, _outputBindings, input, context.Binder, bindingData);
        }
        protected override async Task InvokeCore(object[] parameters, FunctionInvocationContext context)
        {
            // Separate system parameters from the actual method parameters
            object[] originalParameters = parameters;
            MethodInfo function = await GetFunctionTargetAsync();

            int actualParameterCount = function.GetParameters().Length;
            object[] systemParameters = parameters.Skip(actualParameterCount).ToArray();
            parameters = parameters.Take(actualParameterCount).ToArray();

            parameters = ProcessInputParameters(parameters);

            object result = function.Invoke(null, parameters);

            // after the function executes, we have to copy values back into the original
            // array to ensure object references are maintained (since we took a copy above)
            for (int i = 0; i < parameters.Length; i++)
            {
                originalParameters[i] = parameters[i];
            }

            if (result is Task)
            {
                result = await ((Task)result).ContinueWith(t => GetTaskResult(t), TaskContinuationOptions.ExecuteSynchronously);
            }

            if (result != null)
            {
                _resultProcessor(function, parameters, systemParameters, result);
            }

            // if a return value binding was specified, copy the return value
            // into the output binding slot (by convention the last parameter)
            var returnValueBinding = Metadata.Bindings.SingleOrDefault(p => p.IsReturn);
            if (returnValueBinding != null && !(returnValueBinding is IResultProcessingBinding))
            {
                originalParameters[originalParameters.Length - 1] = result;
            }
        }