private object TransformInput(object input, Dictionary <string, object> bindingData) { if (input is Stream) { var dataType = _bindingMetadata.DataType ?? DataType.String; FunctionBinding.ConvertStreamToValue((Stream)input, dataType, ref input); } // TODO: investigate moving POCO style binding addition to sdk Utility.ApplyBindingData(input, bindingData); return(input); }
public async Task BindAsyncCollectorAsync_JObjectCollection() { JArray values = new JArray(); for (int i = 1; i <= 3; i++) { JObject jsonObject = new JObject { { "prop1", "value1" }, { "prop2", true }, { "prop3", 123 } }; values.Add(jsonObject); } string json = values.ToString(); var results = new JArray(); var collectorMock = new Mock <IAsyncCollector <JObject> >(MockBehavior.Strict); collectorMock.Setup(p => p.AddAsync(It.IsAny <JObject>(), CancellationToken.None)) .Callback <JObject, CancellationToken>((mockObject, mockToken) => { results.Add(mockObject); }).Returns(Task.CompletedTask); var binderMock = new Mock <Binder>(MockBehavior.Strict); var attributes = new Attribute[] { new QueueAttribute("test") }; binderMock.Setup(p => p.BindAsync <IAsyncCollector <JObject> >(attributes, CancellationToken.None)).ReturnsAsync(collectorMock.Object); BindingContext bindingContext = new BindingContext { Attributes = attributes, Binder = binderMock.Object, Value = json }; await FunctionBinding.BindAsyncCollectorAsync <JObject>(bindingContext); Assert.Equal(3, results.Count); for (int i = 0; i < 3; i++) { JObject jsonObject = (JObject)results[i]; Assert.Equal("value1", (string)jsonObject["prop1"]); Assert.Equal(true, (bool)jsonObject["prop2"]); Assert.Equal(123, (int)jsonObject["prop3"]); } }
public async Task BindAsyncCollectorAsync_JObjectCollection() { JArray values = new JArray(); for (int i = 1; i <= 3; i++) { JObject jsonObject = new JObject { { "prop1", "value1" }, { "prop2", true }, { "prop3", 123 } }; values.Add(jsonObject); } string json = values.ToString(); byte[] bytes = Encoding.UTF8.GetBytes(json); MemoryStream ms = new MemoryStream(bytes); var results = new JArray(); var collectorMock = new Mock <IAsyncCollector <JObject> >(MockBehavior.Strict); collectorMock.Setup(p => p.AddAsync(It.IsAny <JObject>(), CancellationToken.None)) .Callback <JObject, CancellationToken>((mockObject, mockToken) => { results.Add(mockObject); }).Returns(Task.CompletedTask); var binderMock = new Mock <IBinderEx>(MockBehavior.Strict); QueueAttribute attribute = new QueueAttribute("test"); RuntimeBindingContext context = new RuntimeBindingContext(attribute); binderMock.Setup(p => p.BindAsync <IAsyncCollector <JObject> >(context, CancellationToken.None)).ReturnsAsync(collectorMock.Object); await FunctionBinding.BindAsyncCollectorAsync <JObject>(ms, binderMock.Object, context); Assert.Equal(3, results.Count); for (int i = 0; i < 3; i++) { JObject jsonObject = (JObject)results[i]; Assert.Equal("value1", (string)jsonObject["prop1"]); Assert.Equal(true, (bool)jsonObject["prop2"]); Assert.Equal(123, (int)jsonObject["prop3"]); } }
public void TryCreateReturnValueParameterDescriptor_NoReturnBinding_ReturnsExpectedValue() { JObject json = new JObject { { "type", "httpTrigger" }, { "name", "myInput" }, { "direction", "in" } }; FunctionBinding functionBinding = TestHelpers.CreateTestBinding(json); FunctionBinding[] bindings = new FunctionBinding[] { functionBinding }; ParameterDescriptor descriptor = null; var result = DotNetFunctionDescriptorProvider.TryCreateReturnValueParameterDescriptor(typeof(void), bindings, out descriptor); Assert.False(result); }
public virtual bool TryCreate(FunctionMetadata functionMetadata, out FunctionDescriptor functionDescriptor) { if (functionMetadata == null) { throw new InvalidOperationException("functionMetadata"); } ValidateFunction(functionMetadata); // parse the bindings Collection <FunctionBinding> inputBindings = FunctionBinding.GetBindings(Config, BindingProviders, functionMetadata.InputBindings, FileAccess.Read); Collection <FunctionBinding> outputBindings = FunctionBinding.GetBindings(Config, BindingProviders, functionMetadata.OutputBindings, FileAccess.Write); VerifyResolvedBindings(functionMetadata, inputBindings, outputBindings); BindingMetadata triggerMetadata = functionMetadata.InputBindings.FirstOrDefault(p => p.IsTrigger); string scriptFilePath = Path.Combine(Config.RootScriptPath, functionMetadata.ScriptFile ?? string.Empty); functionDescriptor = null; IFunctionInvoker invoker = null; try { invoker = CreateFunctionInvoker(scriptFilePath, triggerMetadata, functionMetadata, inputBindings, outputBindings); Collection <CustomAttributeBuilder> methodAttributes = new Collection <CustomAttributeBuilder>(); Collection <ParameterDescriptor> parameters = GetFunctionParameters(invoker, functionMetadata, triggerMetadata, methodAttributes, inputBindings, outputBindings); functionDescriptor = new FunctionDescriptor(functionMetadata.Name, invoker, functionMetadata, parameters, methodAttributes, inputBindings, outputBindings); return(true); } catch (Exception ex) { Host.Logger.LogTrace(ex, $"Creating function descriptor for function {functionMetadata.Name} failed"); IDisposable disposableInvoker = invoker as IDisposable; if (disposableInvoker != null) { disposableInvoker.Dispose(); } throw; } }
public void ReadAsCollection_StringArray() { JArray values = new JArray(); values.Add("Value1"); values.Add("Value2"); values.Add("Value3"); string json = values.ToString(); byte[] bytes = Encoding.UTF8.GetBytes(json); MemoryStream ms = new MemoryStream(bytes); var collection = FunctionBinding.ReadAsCollection(ms).Cast <JValue>().ToArray(); Assert.Equal(3, collection.Length); Assert.Equal("Value1", (string)collection[0]); Assert.Equal("Value2", (string)collection[1]); Assert.Equal("Value3", (string)collection[2]); }
public void ReadAsCollection_ObjectSingleton() { JObject jsonObject = new JObject { { "prop1", "value1" }, { "prop2", true }, { "prop3", 123 } }; string json = jsonObject.ToString(); byte[] bytes = Encoding.UTF8.GetBytes(json); MemoryStream ms = new MemoryStream(bytes); var result = FunctionBinding.ReadAsCollection(ms).Cast <JObject>().ToArray(); Assert.Equal(1, result.Length); jsonObject = (JObject)result[0]; Assert.Equal("value1", (string)jsonObject["prop1"]); Assert.Equal(true, (bool)jsonObject["prop2"]); Assert.Equal(123, (int)jsonObject["prop3"]); }
public void TryCreateReturnValueParameterDescriptor_ReturnBindingPresent_ReturnsExpectedValue() { JObject json = new JObject { { "type", "blob" }, { "name", ScriptConstants.SystemReturnParameterBindingName }, { "direction", "out" }, { "path", "foo/bar" } }; _host = new HostBuilder().ConfigureDefaultTestWebScriptHost(b => { b.AddAzureStorage(); }).Build(); FunctionBinding functionBinding = TestHelpers.CreateBindingFromHost(_host, json); FunctionBinding[] bindings = new FunctionBinding[] { functionBinding }; ParameterDescriptor descriptor = null; var result = DotNetFunctionDescriptorProvider.TryCreateReturnValueParameterDescriptor(typeof(string), bindings, out descriptor); Assert.True(result); Assert.Equal(ScriptConstants.SystemReturnParameterName, descriptor.Name); Assert.True((descriptor.Attributes & ParameterAttributes.Out) != 0); Assert.Equal(typeof(string).MakeByRefType(), descriptor.Type); Assert.Equal(1, descriptor.CustomAttributes.Count); result = DotNetFunctionDescriptorProvider.TryCreateReturnValueParameterDescriptor(typeof(Task <string>), bindings, out descriptor); Assert.True(result); Assert.Equal(ScriptConstants.SystemReturnParameterName, descriptor.Name); Assert.True((descriptor.Attributes & ParameterAttributes.Out) != 0); Assert.Equal(typeof(string).MakeByRefType(), descriptor.Type); Assert.Equal(1, descriptor.CustomAttributes.Count); // return type task means no return value result = DotNetFunctionDescriptorProvider.TryCreateReturnValueParameterDescriptor(typeof(Task), bindings, out descriptor); Assert.False(result); }
public void TryCreateReturnValueParameterDescriptor_ReturnBindingPresent_ReturnsExpectedValue() { JObject json = new JObject { { "type", "blob" }, { "name", ScriptConstants.SystemReturnParameterBindingName }, { "direction", "out" }, { "path", "foo/bar" } }; FunctionBinding functionBinding = TestHelpers.CreateTestBinding(json); FunctionBinding[] bindings = new FunctionBinding[] { functionBinding }; ParameterDescriptor descriptor = null; var result = DotNetFunctionDescriptorProvider.TryCreateReturnValueParameterDescriptor(typeof(string), bindings, out descriptor); Assert.True(result); Assert.Equal(ScriptConstants.SystemReturnParameterName, descriptor.Name); Assert.True((descriptor.Attributes & ParameterAttributes.Out) != 0); Assert.Equal(typeof(string).MakeByRefType(), descriptor.Type); Assert.Equal(1, descriptor.CustomAttributes.Count); result = DotNetFunctionDescriptorProvider.TryCreateReturnValueParameterDescriptor(typeof(Task <string>), bindings, out descriptor); Assert.True(result); Assert.Equal(ScriptConstants.SystemReturnParameterName, descriptor.Name); Assert.True((descriptor.Attributes & ParameterAttributes.Out) != 0); Assert.Equal(typeof(string).MakeByRefType(), descriptor.Type); Assert.Equal(1, descriptor.CustomAttributes.Count); var ex = Assert.Throws <InvalidOperationException>(() => { DotNetFunctionDescriptorProvider.TryCreateReturnValueParameterDescriptor(typeof(Task), bindings, out descriptor); }); Assert.Equal($"{ScriptConstants.SystemReturnParameterBindingName} cannot be bound to return type {typeof(Task).Name}.", ex.Message); }
private Dictionary <string, object> CreateScriptExecutionContext(object input, DataType dataType, Binder 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 } }; if (!string.IsNullOrEmpty(_entryPoint)) { context["entryPoint"] = _entryPoint; } // 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); } ApplyBindingData(bindDataInput, binder); // normalize the bindingData object passed into Node // we must convert values to types supported by Edge // marshalling as needed Dictionary <string, object> normalizedBindingData = new Dictionary <string, object>(); foreach (var pair in binder.BindingData) { var value = pair.Value; if (value != null && !IsEdgeSupportedType(value.GetType())) { value = value.ToString(); } normalizedBindingData[pair.Key] = value; } context["bindingData"] = normalizedBindingData; // 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); }
private async Task <IReadOnlyDictionary <string, IValueProvider> > BindCoreAsync(ValueBindingContext context, object value, IDictionary <string, object> parameters) { Dictionary <string, IValueProvider> valueProviders = new Dictionary <string, IValueProvider>(); IValueProvider triggerProvider; IReadOnlyDictionary <string, object> bindingData; try { ITriggerData triggerData = await _triggerBinding.BindAsync(value, context); triggerProvider = triggerData.ValueProvider; bindingData = triggerData.BindingData; } catch (OperationCanceledException) { throw; } catch (Exception exception) { triggerProvider = new BindingExceptionValueProvider(_triggerParameterName, exception); bindingData = null; } valueProviders.Add(_triggerParameterName, triggerProvider); BindingContext bindingContext = FunctionBinding.NewBindingContext(context, bindingData, parameters); // Bind Singleton if specified SingletonAttribute singletonAttribute = SingletonManager.GetFunctionSingletonOrNull(_descriptor.Method, isTriggered: true); if (singletonAttribute != null) { string boundScopeId = _singletonManager.GetBoundScopeId(singletonAttribute.ScopeId, bindingData); IValueProvider singletonValueProvider = new SingletonValueProvider(_descriptor.Method, boundScopeId, context.FunctionInstanceId.ToString(), singletonAttribute, _singletonManager); valueProviders.Add(SingletonValueProvider.SingletonParameterName, singletonValueProvider); } foreach (KeyValuePair <string, IBinding> item in _nonTriggerBindings) { string name = item.Key; IBinding binding = item.Value; IValueProvider valueProvider; try { if (parameters != null && parameters.ContainsKey(name)) { valueProvider = await binding.BindAsync(parameters[name], context); } else { valueProvider = await binding.BindAsync(bindingContext); } } catch (OperationCanceledException) { throw; } catch (Exception exception) { valueProvider = new BindingExceptionValueProvider(name, exception); } valueProviders.Add(name, valueProvider); } return(valueProviders); }
public virtual bool TryCreate(FunctionMetadata functionMetadata, out FunctionDescriptor functionDescriptor) { functionDescriptor = null; if (functionMetadata.IsDisabled) { return(false); } // parse the bindings Collection <FunctionBinding> inputBindings = FunctionBinding.GetBindings(Config, functionMetadata.InputBindings, FileAccess.Read); Collection <FunctionBinding> outputBindings = FunctionBinding.GetBindings(Config, functionMetadata.OutputBindings, FileAccess.Write); BindingMetadata triggerMetadata = functionMetadata.InputBindings.FirstOrDefault(p => p.IsTrigger); BindingType triggerType = triggerMetadata.Type; string triggerParameterName = triggerMetadata.Name; bool triggerNameSpecified = true; if (string.IsNullOrEmpty(triggerParameterName)) { // default the name to simply 'input' triggerMetadata.Name = triggerParameterName = "input"; triggerNameSpecified = false; } Collection <CustomAttributeBuilder> methodAttributes = new Collection <CustomAttributeBuilder>(); ParameterDescriptor triggerParameter = null; bool omitInputParameter = false; switch (triggerType) { case BindingType.QueueTrigger: triggerParameter = ParseQueueTrigger((QueueBindingMetadata)triggerMetadata); break; case BindingType.BlobTrigger: triggerParameter = ParseBlobTrigger((BlobBindingMetadata)triggerMetadata); break; case BindingType.ServiceBusTrigger: triggerParameter = ParseServiceBusTrigger((ServiceBusBindingMetadata)triggerMetadata); break; case BindingType.TimerTrigger: omitInputParameter = true; triggerParameter = ParseTimerTrigger((TimerBindingMetadata)triggerMetadata, typeof(TimerInfo)); break; case BindingType.HttpTrigger: if (!triggerNameSpecified) { triggerMetadata.Name = triggerParameterName = "req"; } triggerParameter = ParseHttpTrigger((HttpBindingMetadata)triggerMetadata, methodAttributes, typeof(HttpRequestMessage)); break; case BindingType.ManualTrigger: triggerParameter = ParseManualTrigger(triggerMetadata, methodAttributes); break; } Collection <ParameterDescriptor> parameters = new Collection <ParameterDescriptor>(); triggerParameter.IsTrigger = true; parameters.Add(triggerParameter); // Add a TraceWriter for logging parameters.Add(new ParameterDescriptor("log", typeof(TraceWriter))); // Add an IBinder to support the binding programming model parameters.Add(new ParameterDescriptor("binder", typeof(IBinder))); // Add ExecutionContext to provide access to InvocationId, etc. parameters.Add(new ParameterDescriptor("context", typeof(ExecutionContext))); string scriptFilePath = Path.Combine(Config.RootScriptPath, functionMetadata.Source); IFunctionInvoker invoker = CreateFunctionInvoker(scriptFilePath, triggerMetadata, functionMetadata, omitInputParameter, inputBindings, outputBindings); functionDescriptor = new FunctionDescriptor(functionMetadata.Name, invoker, functionMetadata, parameters, methodAttributes); return(true); }
private async Task <IReadOnlyDictionary <string, IValueProvider> > BindCoreAsync(ValueBindingContext context, object value, IDictionary <string, object> parameters) { Dictionary <string, IValueProvider> valueProviders = new Dictionary <string, IValueProvider>(); IValueProvider triggerProvider; IReadOnlyDictionary <string, object> bindingData; IValueBinder triggerReturnValueProvider = null; try { ITriggerData triggerData = await _triggerBinding.BindAsync(value, context); triggerProvider = triggerData.ValueProvider; bindingData = triggerData.BindingData; triggerReturnValueProvider = (triggerData as TriggerData)?.ReturnValueProvider; } catch (OperationCanceledException) { throw; } catch (Exception exception) { triggerProvider = new BindingExceptionValueProvider(_triggerParameterName, exception); bindingData = null; } valueProviders.Add(_triggerParameterName, triggerProvider); // Bind Singleton if specified SingletonAttribute singletonAttribute = SingletonManager.GetFunctionSingletonOrNull(_descriptor, isTriggered: true); if (singletonAttribute != null) { string boundScopeId = _singletonManager.GetBoundScopeId(singletonAttribute.ScopeId, bindingData); IValueProvider singletonValueProvider = new SingletonValueProvider(_descriptor, boundScopeId, context.FunctionInstanceId.ToString(), singletonAttribute, _singletonManager); valueProviders.Add(SingletonValueProvider.SingletonParameterName, singletonValueProvider); } BindingContext bindingContext = FunctionBinding.NewBindingContext(context, bindingData, parameters); foreach (KeyValuePair <string, IBinding> item in _nonTriggerBindings) { string name = item.Key; IBinding binding = item.Value; IValueProvider valueProvider; try { if (parameters != null && parameters.ContainsKey(name)) { valueProvider = await binding.BindAsync(parameters[name], context); } else { valueProvider = await binding.BindAsync(bindingContext); } } catch (OperationCanceledException) { throw; } catch (Exception exception) { valueProvider = new BindingExceptionValueProvider(name, exception); } valueProviders.Add(name, valueProvider); } // Triggers can optionally process the return values of functions. They do so by declaring // a "$return" key in their binding data dictionary and mapping it to an IValueBinder. // An explicit return binding takes precedence over an implicit trigger binding. if (!valueProviders.ContainsKey(FunctionIndexer.ReturnParamName)) { if (triggerReturnValueProvider != null) { valueProviders.Add(FunctionIndexer.ReturnParamName, triggerReturnValueProvider); } } return(valueProviders); }
public void AcceptFunction(FunctionBinding function) { AddInvocable(function); }
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); }
public ArgumentChecks() { _aDelegate = ExceptionBuilder; _aParameterInfo = _aMethodInfo.GetParameters()[0]; _aFunctionBinding = new ReflectionFunctionBinding(_aMethodInfo, null, false); }
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 static ArgumentException FunctionWithSameNameAndSignatureAlreadyInCollection(string paramName, FunctionBinding functionBinding) { if (paramName == null) { throw new ArgumentNullException("paramName"); } if (functionBinding == null) { throw new ArgumentNullException("functionBinding"); } StringBuilder sb = new StringBuilder(); sb.Append(functionBinding.Name); sb.Append("("); FormattingHelpers.FormatTypeList(functionBinding.GetParameterTypes()); sb.Append(")"); string signature = sb.ToString(); string message = String.Format(CultureInfo.CurrentCulture, Resources.FunctionWithSameNameAndSignatureAlreadyInCollection, signature); return(new ArgumentException(message, paramName)); }