private async Task ExecuteWithOutputLogsAsync(IFunctionInstance instance, IReadOnlyDictionary <string, IValueProvider> parameters, TextWriter consoleOutput, IFunctionOutputDefinition outputDefinition, IDictionary <string, ParameterLog> parameterLogCollector, CancellationToken cancellationToken) { IFunctionInvoker invoker = instance.Invoker; IReadOnlyDictionary <string, IWatcher> watches = CreateWatches(parameters); IRecurrentCommand updateParameterLogCommand = outputDefinition.CreateParameterLogUpdateCommand(watches, consoleOutput); using (ITaskSeriesTimer updateParameterLogTimer = StartParameterLogTimer(updateParameterLogCommand, _backgroundExceptionDispatcher)) { try { await ExecuteWithWatchersAsync(invoker, parameters, cancellationToken); if (updateParameterLogTimer != null) { // Stop the watches after calling IValueBinder.SetValue (it may do things that should show up in // the watches). // Also, IValueBinder.SetValue could also take a long time (flushing large caches), and so it's // useful to have watches still running. await updateParameterLogTimer.StopAsync(cancellationToken); } } finally { ValueWatcher.AddLogs(watches, parameterLogCollector); } } }
public TriggeredFunctionInstanceFactory(ITriggeredFunctionBinding <TTriggerValue> binding, IFunctionInvoker invoker, FunctionDescriptor descriptor) { _binding = binding; _invoker = invoker; _descriptor = descriptor; }
public void InvokeAsync_DelegatesToInstanceFactoryAndMethodInvoker() { // Arrange object expectedInstance = new object(); object[] expectedArguments = new object[0]; Mock <IFactory <object> > instanceFactoryMock = new Mock <IFactory <object> >(MockBehavior.Strict); instanceFactoryMock.Setup(f => f.Create()) .Returns(expectedInstance) .Verifiable(); IFactory <object> instanceFactory = instanceFactoryMock.Object; Mock <IMethodInvoker <object> > methodInvokerMock = new Mock <IMethodInvoker <object> >(MockBehavior.Strict); methodInvokerMock.Setup(i => i.InvokeAsync(expectedInstance, expectedArguments)) .Returns(Task.FromResult(0)) .Verifiable(); IMethodInvoker <object> methodInvoker = methodInvokerMock.Object; IFunctionInvoker product = CreateProductUnderTest(instanceFactory, methodInvoker); // Act product.InvokeAsync(expectedArguments).GetAwaiter().GetResult(); // Assert instanceFactoryMock.VerifyAll(); methodInvokerMock.VerifyAll(); }
public FunctionInstanceFactory(IFunctionBinding binding, IFunctionInvoker invoker, FunctionDescriptor descriptor) { _binding = binding; _invoker = invoker; _descriptor = descriptor; }
public virtual bool TryCreate(FunctionMetadata functionMetadata, out FunctionDescriptor functionDescriptor) { if (functionMetadata == null) { throw new InvalidOperationException("functionMetadata"); } functionDescriptor = null; // Default the trigger binding name if a name hasn't // been specified // TODO: Remove this logic and always require it to be explicitly // specified? foreach (var binding in functionMetadata.Bindings.Where(p => p.IsTrigger)) { if (string.IsNullOrEmpty(binding.Name)) { if (binding.Type == BindingType.HttpTrigger) { binding.Name = DefaultHttpInputParameterName; } else { binding.Name = DefaultInputParameterName; } } } // 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); string scriptFilePath = Path.Combine(Config.RootScriptPath, functionMetadata.ScriptFile); 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); return(true); } catch (Exception) { IDisposable disposableInvoker = invoker as IDisposable; if (disposableInvoker != null) { disposableInvoker.Dispose(); } throw; } }
internal static async Task InvokeAsync(IFunctionInvoker invoker, object[] invokeParameters, CancellationTokenSource timeoutTokenSource, CancellationTokenSource functionCancellationTokenSource, bool throwOnTimeout, TimeSpan timerInterval, IFunctionInstance instance) { // There are three ways the function can complete: // 1. The invokeTask itself completes first. // 2. A cancellation is requested (by host.Stop(), for example). // a. Continue waiting for the invokeTask to complete. Either #1 or #3 will occur. // 3. A timeout fires. // a. If throwOnTimeout, we throw the FunctionTimeoutException. // b. If !throwOnTimeout, wait for the task to complete. // Start the invokeTask. Task invokeTask = invoker.InvokeAsync(invokeParameters); // A task that will throw a TaskCanceledException if #2 occurs. Task shutdownTask = Task.Delay(-1, functionCancellationTokenSource.Token); // A task that will throw when either #1 or #2 occurs. Task <Task> invokeOrShutdownTask = Task.WhenAny(invokeTask, shutdownTask); // Combine #1 and #2 with a timeout task (handled by this method). bool isTimeout = await TryHandleTimeoutAsync(invokeOrShutdownTask, throwOnTimeout, timeoutTokenSource.Token, timerInterval, instance, () => functionCancellationTokenSource.Cancel()); // #2 occurred. If we're going to throwOnTimeout, watch for a timeout while we wait for invokeTask to complete. if (throwOnTimeout && !isTimeout && invokeOrShutdownTask.Result == shutdownTask) { await TryHandleTimeoutAsync(invokeTask, throwOnTimeout, timeoutTokenSource.Token, timerInterval, instance, null); } await invokeTask; }
internal static async Task InvokeAsync(IFunctionInvoker invoker, object[] invokeParameters, CancellationTokenSource timeoutTokenSource, CancellationTokenSource functionCancellationTokenSource, bool throwOnTimeout, TimeSpan timerInterval, IFunctionInstance instance) { // There are three ways the function can complete: // 1. The invokeTask itself completes first. // 2. A cancellation is requested (by host.Stop(), for example). // a. Continue waiting for the invokeTask to complete. Either #1 or #3 will occur. // 3. A timeout fires. // a. If throwOnTimeout, we throw the FunctionTimeoutException. // b. If !throwOnTimeout, wait for the task to complete. // Start the invokeTask. Task invokeTask = invoker.InvokeAsync(invokeParameters); // Combine #1 and #2 with a timeout task (handled by this method). // functionCancellationTokenSource.Token is passed to each function that requests it, so we need to call Cancel() on it // if there is a timeout. bool isTimeout = await TryHandleTimeoutAsync(invokeTask, functionCancellationTokenSource.Token, throwOnTimeout, timeoutTokenSource.Token, timerInterval, instance, () => functionCancellationTokenSource.Cancel()); // #2 occurred. If we're going to throwOnTimeout, watch for a timeout while we wait for invokeTask to complete. if (throwOnTimeout && !isTimeout && functionCancellationTokenSource.IsCancellationRequested) { await TryHandleTimeoutAsync(invokeTask, CancellationToken.None, throwOnTimeout, timeoutTokenSource.Token, timerInterval, instance, null); } await invokeTask; }
public void InvokeAsync_IfInstanceIsDisposable_DoesNotDisposeWhileTaskIsRunning() { // Arrange bool disposed = false; Mock <IDisposable> disposableMock = new Mock <IDisposable>(MockBehavior.Strict); disposableMock.Setup(d => d.Dispose()).Callback(() => { disposed = true; }); IDisposable disposable = disposableMock.Object; IFactory <object> instanceFactory = CreateStubFactory(disposable); TaskCompletionSource <object> taskSource = new TaskCompletionSource <object>(); IMethodInvoker <object> methodInvoker = CreateStubMethodInvoker(taskSource.Task); IFunctionInvoker product = CreateProductUnderTest(instanceFactory, methodInvoker); object[] arguments = new object[0]; // Act Task task = product.InvokeAsync(arguments); // Assert Assert.NotNull(task); Assert.False(disposed); taskSource.SetResult(null); task.GetAwaiter().GetResult(); }
public FunctionInstance(Guid id, Guid? parentId, ExecutionReason reason, IBindingSource bindingSource, IFunctionInvoker invoker, FunctionDescriptor functionDescriptor) { _id = id; _parentId = parentId; _reason = reason; _bindingSource = bindingSource; _invoker = invoker; _functionDescriptor = functionDescriptor; }
public FunctionInstance(Guid id, Guid?parentId, ExecutionReason reason, IBindingSource bindingSource, IFunctionInvoker invoker, FunctionDescriptor functionDescriptor) { _id = id; _parentId = parentId; _reason = reason; _bindingSource = bindingSource; _invoker = invoker; _functionDescriptor = functionDescriptor; }
private static FunctionDefinition CreateTriggeredFunctionDefinitionImpl <TTriggerValue>( ITriggerBinding triggerBinding, string parameterName, IFunctionExecutor executor, FunctionDescriptor descriptor, IReadOnlyDictionary <string, IBinding> nonTriggerBindings, IFunctionInvoker invoker, SingletonManager singletonManager) { ITriggeredFunctionBinding <TTriggerValue> functionBinding = new TriggeredFunctionBinding <TTriggerValue>(descriptor, parameterName, triggerBinding, nonTriggerBindings, singletonManager); ITriggeredFunctionInstanceFactory <TTriggerValue> instanceFactory = new TriggeredFunctionInstanceFactory <TTriggerValue>(functionBinding, invoker, descriptor); ITriggeredFunctionExecutor triggerExecutor = new TriggeredFunctionExecutor <TTriggerValue>(descriptor, executor, instanceFactory); IListenerFactory listenerFactory = new ListenerFactory(descriptor, triggerExecutor, triggerBinding); return(new FunctionDefinition(descriptor, instanceFactory, listenerFactory)); }
public void Create_ReturnsFunctionInvoker() { // Arrange _functionMethod = GetMethodInfo(nameof(DefaultFunctionInvokerFactoryTests.StaticReturnVoid)); // Act IFunctionInvoker invoker = _invokerFactory.Create(new TestFunctionDefinition()); // Assert Assert.IsType <DefaultFunctionInvoker <DefaultFunctionInvokerFactoryTests, object> >(invoker); }
public FunctionDescriptor( string name, IFunctionInvoker invoker, Collection<ParameterDescriptor> parameters, Collection<CustomAttributeBuilder> attributes) { Name = name; Invoker = invoker; Parameters = parameters; CustomAttributes = attributes; }
public FunctionInstance(Guid id, IDictionary <string, string> triggerDetails, Guid?parentId, ExecutionReason reason, IBindingSource bindingSource, IFunctionInvoker invoker, FunctionDescriptor functionDescriptor) { _id = id; _triggerDetails = triggerDetails; _parentId = parentId; _reason = reason; _bindingSource = bindingSource; _invoker = invoker; _functionDescriptor = functionDescriptor; }
internal static async Task ExecuteWithWatchersAsync(IFunctionInvoker invoker, IReadOnlyDictionary <string, IValueProvider> parameters, TextWriter consoleOutput, CancellationToken cancellationToken) { IReadOnlyList <string> parameterNames = invoker.ParameterNames; IDelayedException delayedBindingException; object[] invokeParameters = PrepareParameters(parameterNames, parameters, out delayedBindingException); if (delayedBindingException != null) { // This is done inside a watcher context so that each binding error is publish next to the binding in // the parameter status log. delayedBindingException.Throw(); } // Cancellation token is provide by invokeParameters (if the method binds to CancellationToken). await invoker.InvokeAsync(invokeParameters); // Process any out parameters and persist any pending values. // Ensure IValueBinder.SetValue is called in BindOrder. This ordering is particularly important for // ensuring queue outputs occur last. That way, all other function side-effects are guaranteed to have // occurred by the time messages are enqueued. string[] parameterNamesInBindOrder = SortParameterNamesInStepOrder(parameters); foreach (string name in parameterNamesInBindOrder) { IValueProvider provider = parameters[name]; IValueBinder binder = provider as IValueBinder; if (binder != null) { object argument = invokeParameters[GetParameterIndex(parameterNames, name)]; try { // This could do complex things that may fail. Catch the exception. await binder.SetValueAsync(argument, cancellationToken); } catch (OperationCanceledException) { throw; } catch (Exception exception) { string message = String.Format(CultureInfo.InvariantCulture, "Error while handling parameter {0} after function returned:", name); throw new InvalidOperationException(message, exception); } } } }
public void Create_ReturnsFunctionInvoker() { // Arrange MethodInfo method = GetMethodInfo("StaticReturnVoid"); IJobActivator activator = CreateDummyActivator(); // Act IFunctionInvoker invoker = FunctionInvokerFactory.Create(method, activator); // Assert Assert.IsType <FunctionInvoker <FunctionInvokerFactoryTests, object> >(invoker); }
public FunctionDescriptor( string name, IFunctionInvoker invoker, FunctionMetadata metadata, Collection <ParameterDescriptor> parameters, Collection <CustomAttributeBuilder> attributes) { Name = name; Invoker = invoker; Parameters = parameters; CustomAttributes = attributes; Metadata = metadata; }
public void Create_IfMultipleParameters_ReturnsParameterNames() { // Arrange MethodInfo method = GetMethodInfo("ParametersFooBarBaz"); IJobActivator activator = CreateDummyActivator(); // Act IFunctionInvoker invoker = FunctionInvokerFactory.Create(method, activator); // Assert Assert.NotNull(invoker); Assert.Equal((IEnumerable <string>) new string[] { "foo", "bar", "baz" }, invoker.ParameterNames); }
public void Create_IfNoParameters_ReturnsEmptyParameterNames() { // Arrange MethodInfo method = GetMethodInfo("NoParameters"); IJobActivator activator = CreateDummyActivator(); // Act IFunctionInvoker invoker = FunctionInvokerFactory.Create(method, activator); // Assert Assert.NotNull(invoker); Assert.Equal(Enumerable.Empty <string>(), invoker.ParameterNames); }
public IFunctionDefinition CreateFunctionDefinition(IReadOnlyDictionary <string, IBinding> nonTriggerBindings, IFunctionInvoker invoker, FunctionDescriptor functionDescriptor) { ITriggeredFunctionBinding <IStorageQueueMessage> functionBinding = new TriggeredFunctionBinding <IStorageQueueMessage>(_parameterName, this, nonTriggerBindings); ITriggeredFunctionInstanceFactory <IStorageQueueMessage> instanceFactory = new TriggeredFunctionInstanceFactory <IStorageQueueMessage>(functionBinding, invoker, functionDescriptor); IListenerFactory listenerFactory = new QueueListenerFactory(_queue, _queueConfiguration, _backgroundExceptionDispatcher, _messageEnqueuedWatcherSetter, _sharedContextProvider, _log, instanceFactory); return(new FunctionDefinition(instanceFactory, listenerFactory)); }
/// <summary> /// Initializes a new instance of the <see cref="SCFHost"/> class using the configuration provided. /// </summary> /// <param name="configuration">The job host configuration.</param> public SCFHost(IOptions <SCFHostOptions> options, IFunctionInvoker invoker, ILogger <SCFHost> logger, IHttpClientFactory httpFactory) { if (options == null) { throw new ArgumentNullException(nameof(options)); } _httpFactory = httpFactory; _options = options.Value; _logger = logger; _functionInvoker = invoker; _shutdownTokenSource = new CancellationTokenSource(); _stoppingTokenSource = CancellationTokenSource.CreateLinkedTokenSource(_shutdownTokenSource.Token); }
public void Create_IfInstance_UsesActivatorInstanceFactory() { // Arrange _functionMethod = GetMethodInfo(nameof(DefaultFunctionInvokerFactoryTests.InstanceReturnVoid)); // Act IFunctionInvoker invoker = _invokerFactory.Create(new TestFunctionDefinition()); // Assert Assert.IsType <DefaultFunctionInvoker <DefaultFunctionInvokerFactoryTests, object> >(invoker); var typedInvoker = (DefaultFunctionInvoker <DefaultFunctionInvokerFactoryTests, object>)invoker; Assert.IsType <DefaultFunctionActivator>(typedInvoker.FunctionActivator); }
public void Create_IfInstanceAndMethodIsInherited_UsesReflectedType() { // Arrange _functionMethod = GetMethodInfo(typeof(Subclass), nameof(Subclass.InheritedReturnVoid)); // Act IFunctionInvoker invoker = _invokerFactory.Create(new TestFunctionDefinition()); // Assert Assert.IsType <DefaultFunctionInvoker <Subclass, object> >(invoker); var typedInvoker = (DefaultFunctionInvoker <Subclass, object>)invoker; Assert.IsType <DefaultFunctionActivator>(typedInvoker.FunctionActivator); }
public IFunctionDefinition CreateFunctionDefinition(IReadOnlyDictionary <string, IBinding> nonTriggerBindings, IFunctionInvoker invoker, FunctionDescriptor functionDescriptor) { ITriggeredFunctionBinding <IStorageBlob> functionBinding = new TriggeredFunctionBinding <IStorageBlob>(_parameterName, this, nonTriggerBindings); ITriggeredFunctionInstanceFactory <IStorageBlob> instanceFactory = new TriggeredFunctionInstanceFactory <IStorageBlob>(functionBinding, invoker, functionDescriptor); IStorageBlobContainer container = _client.GetContainerReference(_path.ContainerNamePattern); IListenerFactory listenerFactory = new BlobListenerFactory(_hostIdProvider, _queueConfiguration, _backgroundExceptionDispatcher, _blobWrittenWatcherSetter, _messageEnqueuedWatcherSetter, _sharedContextProvider, _log, functionDescriptor.Id, _account, container, _path, instanceFactory); return(new FunctionDefinition(instanceFactory, listenerFactory)); }
public void Create_IfInstanceAndMethodIsInherited_UsesReflectedType() { // Arrange MethodInfo method = GetMethodInfo(typeof(Subclass), "InheritedReturnVoid"); IJobActivator activator = CreateDummyActivator(); // Act IFunctionInvoker invoker = FunctionInvokerFactory.Create(method, activator); // Assert Assert.IsType <FunctionInvoker <Subclass, object> >(invoker); FunctionInvoker <Subclass, object> typedInvoker = (FunctionInvoker <Subclass, object>)invoker; Assert.IsType <ActivatorInstanceFactory <Subclass> >(typedInvoker.InstanceFactory); }
public void Create_IfStatic_UsesNullInstanceFactory() { // Arrange MethodInfo method = GetMethodInfo("StaticReturnVoid"); IJobActivator activator = CreateDummyActivator(); // Act IFunctionInvoker invoker = FunctionInvokerFactory.Create(method, activator); // Assert Assert.IsType <FunctionInvoker <FunctionInvokerFactoryTests, object> >(invoker); FunctionInvoker <FunctionInvokerFactoryTests, object> typedInvoker = (FunctionInvoker <FunctionInvokerFactoryTests, object>)invoker; Assert.IsType <NullInstanceFactory <FunctionInvokerFactoryTests> >(typedInvoker.InstanceFactory); }
public void Create_ReturnsFunctionInvoker() { // Arrange MethodInfo method = GetMethodInfo(nameof(DefaultFunctionInvokerFactoryTests.StaticReturnVoid)); IMethodInvokerFactory methodInvokerFactory = CreateMethodInvokerFactory(); IFunctionActivator activator = CreateDummyActivator(); IFunctionInvokerFactory _invokerFactory = new DefaultFunctionInvokerFactory(methodInvokerFactory, activator); // Act IFunctionInvoker invoker = _invokerFactory.Create(method); // Assert Assert.IsType <DefaultFunctionInvoker <DefaultFunctionInvokerFactoryTests, object> >(invoker); }
private async Task ExecuteWithLoggingAsync(IFunctionInstance instance, IReadOnlyDictionary <string, IValueProvider> parameters, TraceWriter trace, ILogger logger, IFunctionOutputDefinition outputDefinition, IDictionary <string, ParameterLog> parameterLogCollector, TraceLevel functionTraceLevel, CancellationTokenSource functionCancellationTokenSource) { IFunctionInvoker invoker = instance.Invoker; IReadOnlyDictionary <string, IWatcher> parameterWatchers = null; ITaskSeriesTimer updateParameterLogTimer = null; if (functionTraceLevel >= TraceLevel.Info) { parameterWatchers = CreateParameterWatchers(parameters); IRecurrentCommand updateParameterLogCommand = outputDefinition.CreateParameterLogUpdateCommand(parameterWatchers, trace, logger); updateParameterLogTimer = StartParameterLogTimer(updateParameterLogCommand, _exceptionHandler); } try { await ExecuteWithWatchersAsync(instance, parameters, trace, logger, functionCancellationTokenSource); if (updateParameterLogTimer != null) { // Stop the watches after calling IValueBinder.SetValue (it may do things that should show up in // the watches). // Also, IValueBinder.SetValue could also take a long time (flushing large caches), and so it's // useful to have watches still running. await updateParameterLogTimer.StopAsync(functionCancellationTokenSource.Token); } } finally { if (updateParameterLogTimer != null) { ((IDisposable)updateParameterLogTimer).Dispose(); } if (parameterWatchers != null) { ValueWatcher.AddLogs(parameterWatchers, parameterLogCollector); } } }
public FunctionDescriptor( string name, IFunctionInvoker invoker, FunctionMetadata metadata, Collection <ParameterDescriptor> parameters, Collection <CustomAttributeBuilder> attributes, Collection <FunctionBinding> inputBindings, Collection <FunctionBinding> outputBindings) { Name = name; Invoker = invoker; Parameters = parameters; CustomAttributes = attributes; Metadata = metadata; InputBindings = inputBindings; OutputBindings = outputBindings; }
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 Create_IfInstanceAndMethodIsInherited_UsesReflectedType() { // Arrange MethodInfo method = GetMethodInfo(typeof(Subclass), nameof(Subclass.InheritedReturnVoid)); IMethodInvokerFactory methodInvokerFactory = CreateMethodInvokerFactory(); IFunctionActivator activator = new DefaultFunctionActivator(); IFunctionInvokerFactory _invokerFactory = new DefaultFunctionInvokerFactory(methodInvokerFactory, activator); // Act IFunctionInvoker invoker = _invokerFactory.Create(method); // Assert Assert.IsType <DefaultFunctionInvoker <Subclass, object> >(invoker); var typedInvoker = (DefaultFunctionInvoker <Subclass, object>)invoker; Assert.IsType <DefaultFunctionActivator>(typedInvoker.FunctionActivator); }
public void Create_IfInstance_UsesActivatorInstanceFactory() { // Arrange MethodInfo method = GetMethodInfo(nameof(DefaultFunctionInvokerFactoryTests.InstanceReturnVoid)); IMethodInvokerFactory methodInvokerFactory = CreateMethodInvokerFactory(); IFunctionActivator activator = new DefaultFunctionActivator(); IFunctionInvokerFactory _invokerFactory = new DefaultFunctionInvokerFactory(methodInvokerFactory, activator); // Act IFunctionInvoker invoker = _invokerFactory.Create(method); // Assert Assert.IsType <DefaultFunctionInvoker <DefaultFunctionInvokerFactoryTests, object> >(invoker); var typedInvoker = (DefaultFunctionInvoker <DefaultFunctionInvokerFactoryTests, object>)invoker; Assert.IsType <DefaultFunctionActivator>(typedInvoker.FunctionActivator); }
protected virtual Collection<ParameterDescriptor> GetFunctionParameters(IFunctionInvoker functionInvoker, FunctionMetadata functionMetadata, BindingMetadata triggerMetadata, Collection<CustomAttributeBuilder> methodAttributes, Collection<FunctionBinding> inputBindings, Collection<FunctionBinding> outputBindings) { if (functionInvoker == null) { throw new ArgumentNullException("functionInvoker"); } if (functionMetadata == null) { throw new ArgumentNullException("functionMetadata"); } if (triggerMetadata == null) { throw new ArgumentNullException("triggerMetadata"); } if (methodAttributes == null) { throw new ArgumentNullException("methodAttributes"); } ApplyMethodLevelAttributes(functionMetadata, triggerMetadata, methodAttributes); Collection<ParameterDescriptor> parameters = new Collection<ParameterDescriptor>(); ParameterDescriptor triggerParameter = CreateTriggerParameter(triggerMetadata); parameters.Add(triggerParameter); // Add a TraceWriter for logging parameters.Add(new ParameterDescriptor(ScriptConstants.SystemLogParameterName, typeof(TraceWriter))); // Add an IBinder to support the binding programming model parameters.Add(new ParameterDescriptor(ScriptConstants.SystemBinderParameterName, typeof(IBinder))); // Add ExecutionContext to provide access to InvocationId, etc. parameters.Add(new ParameterDescriptor(ScriptConstants.SystemExecutionContextParameterName, typeof(ExecutionContext))); return parameters; }
protected virtual Collection<ParameterDescriptor> GetFunctionParameters(IFunctionInvoker functionInvoker, FunctionMetadata functionMetadata, BindingMetadata triggerMetadata, Collection<CustomAttributeBuilder> methodAttributes, Collection<FunctionBinding> inputBindings, Collection<FunctionBinding> outputBindings) { if (functionInvoker == null) { throw new ArgumentNullException("functionInvoker"); } if (functionMetadata == null) { throw new ArgumentNullException("functionMetadata"); } if (triggerMetadata == null) { throw new ArgumentNullException("triggerMetadata"); } if (methodAttributes == null) { throw new ArgumentNullException("methodAttributes"); } ParameterDescriptor triggerParameter = null; switch (triggerMetadata.Type) { case BindingType.QueueTrigger: triggerParameter = ParseQueueTrigger((QueueBindingMetadata)triggerMetadata); break; case BindingType.EventHubTrigger: triggerParameter = ParseEventHubTrigger((EventHubBindingMetadata)triggerMetadata); break; case BindingType.BlobTrigger: triggerParameter = ParseBlobTrigger((BlobBindingMetadata)triggerMetadata, typeof(Stream)); break; case BindingType.ServiceBusTrigger: triggerParameter = ParseServiceBusTrigger((ServiceBusBindingMetadata)triggerMetadata); break; case BindingType.TimerTrigger: triggerParameter = ParseTimerTrigger((TimerBindingMetadata)triggerMetadata, typeof(TimerInfo)); break; case BindingType.HttpTrigger: triggerParameter = ParseHttpTrigger((HttpTriggerBindingMetadata)triggerMetadata, typeof(HttpRequestMessage)); break; case BindingType.ManualTrigger: triggerParameter = ParseManualTrigger(triggerMetadata); break; case BindingType.ApiHubTrigger: triggerParameter = ParseApiHubTrigger((ApiHubBindingMetadata)triggerMetadata, typeof(Stream)); break; } ApplyMethodLevelAttributes(functionMetadata, triggerMetadata, methodAttributes); 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))); return parameters; }
protected override Collection<ParameterDescriptor> GetFunctionParameters(IFunctionInvoker functionInvoker, FunctionMetadata functionMetadata, BindingMetadata triggerMetadata, Collection<CustomAttributeBuilder> methodAttributes, Collection<FunctionBinding> inputBindings, Collection<FunctionBinding> outputBindings) { if (functionInvoker == null) { throw new ArgumentNullException("functionInvoker"); } if (functionMetadata == null) { throw new ArgumentNullException("functionMetadata"); } if (triggerMetadata == null) { throw new ArgumentNullException("triggerMetadata"); } if (methodAttributes == null) { throw new ArgumentNullException("methodAttributes"); } var dotNetInvoker = functionInvoker as DotNetFunctionInvoker; if (dotNetInvoker == null) { throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Expected invoker of type '{0}' but received '{1}'", typeof(DotNetFunctionInvoker).Name, functionInvoker.GetType().Name)); } try { ApplyMethodLevelAttributes(functionMetadata, triggerMetadata, methodAttributes); MethodInfo functionTarget = dotNetInvoker.GetFunctionTargetAsync().Result; ParameterInfo[] parameters = functionTarget.GetParameters(); Collection<ParameterDescriptor> descriptors = new Collection<ParameterDescriptor>(); IEnumerable<FunctionBinding> bindings = inputBindings.Union(outputBindings); ParameterDescriptor descriptor = null; foreach (var parameter in parameters) { // Is it the trigger parameter? if (string.Compare(parameter.Name, triggerMetadata.Name, StringComparison.Ordinal) == 0) { ParameterDescriptor triggerParameter = CreateTriggerParameter(triggerMetadata, parameter.ParameterType); descriptors.Add(triggerParameter); } else { Type parameterType = parameter.ParameterType; bool parameterIsByRef = parameterType.IsByRef; if (parameterIsByRef) { parameterType = parameterType.GetElementType(); } descriptor = new ParameterDescriptor(parameter.Name, parameter.ParameterType); var binding = bindings.FirstOrDefault(b => string.Compare(b.Metadata.Name, parameter.Name, StringComparison.Ordinal) == 0); if (binding != null) { Collection<CustomAttributeBuilder> customAttributes = binding.GetCustomAttributes(parameter.ParameterType); if (customAttributes != null) { foreach (var customAttribute in customAttributes) { descriptor.CustomAttributes.Add(customAttribute); } } } // In the C# programming model, IsOut is set for out parameters // In the F# programming model, neither IsOut nor IsIn are set for byref parameters (which are used as out parameters). // Justification for this cariation of the programming model is that declaring 'out' parameters is (deliberately) // awkward in F#, they require opening System.Runtime.InteropServices and adding the [<Out>] attribute, and using // a byref parameter. In contrast declaring a byref parameter alone (neither labelled In nor Out) is simple enough. if (parameter.IsOut || (functionMetadata.ScriptType == ScriptType.FSharp && parameterIsByRef && !parameter.IsIn)) { descriptor.Attributes |= ParameterAttributes.Out; } descriptors.Add(descriptor); } } // Add any additional required System parameters (if they haven't already been defined by the user) if (!descriptors.Any(p => p.Type == typeof(ExecutionContext))) { // Add ExecutionContext to provide access to InvocationId, etc. descriptors.Add(new ParameterDescriptor(ScriptConstants.SystemExecutionContextParameterName, typeof(ExecutionContext))); } // If we have an HTTP trigger binding but no parameter binds to the raw HttpRequestMessage, // add it as a system parameter so it is accessible later in the pipeline. if (string.Compare(triggerMetadata.Type, "httptrigger", StringComparison.OrdinalIgnoreCase) == 0 && !descriptors.Any(p => p.Type == typeof(HttpRequestMessage))) { descriptors.Add(new ParameterDescriptor(ScriptConstants.SystemTriggerParameterName, typeof(HttpRequestMessage))); } if (TryCreateReturnValueParameterDescriptor(functionTarget.ReturnType, bindings, out descriptor)) { // If a return value binding has been specified, set up an output // binding to map it to. By convention, this is set up as the last // parameter. descriptors.Add(descriptor); } return descriptors; } catch (AggregateException exc) { if (!(exc.InnerException is CompilationErrorException)) { throw; } } catch (CompilationErrorException) { } // We were unable to compile the function to get its signature, // setup the descriptor with the default parameters methodAttributes.Clear(); return base.GetFunctionParameters(functionInvoker, functionMetadata, triggerMetadata, methodAttributes, inputBindings, outputBindings); }
public FunctionInstanceFactory(IFunctionBinding binding, IFunctionInvoker invoker, FunctionDescriptor descriptor) { _binding = binding; _invoker = invoker; _descriptor = descriptor; }
public FunctionDescriptor(string name, IFunctionInvoker invoker, FunctionMetadata metadata, Collection<ParameterDescriptor> parameters) : this(name, invoker, metadata, parameters, new Collection<CustomAttributeBuilder>()) { }
protected override Collection<ParameterDescriptor> GetFunctionParameters(IFunctionInvoker functionInvoker, FunctionMetadata functionMetadata, BindingMetadata triggerMetadata, Collection<CustomAttributeBuilder> methodAttributes, Collection<FunctionBinding> inputBindings, Collection<FunctionBinding> outputBindings) { if (functionInvoker == null) { throw new ArgumentNullException("functionInvoker"); } if (functionMetadata == null) { throw new ArgumentNullException("functionMetadata"); } if (triggerMetadata == null) { throw new ArgumentNullException("triggerMetadata"); } if (methodAttributes == null) { throw new ArgumentNullException("methodAttributes"); } var csharpInvoker = functionInvoker as CSharpFunctionInvoker; if (csharpInvoker == null) { throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Expected invoker of type '{0}' but received '{1}'", typeof(CSharpFunctionInvoker).Name, functionInvoker.GetType().Name)); } try { ApplyMethodLevelAttributes(functionMetadata, triggerMetadata, methodAttributes); MethodInfo functionTarget = csharpInvoker.GetFunctionTargetAsync().Result; ParameterInfo[] parameters = functionTarget.GetParameters(); Collection<ParameterDescriptor> descriptors = new Collection<ParameterDescriptor>(); IEnumerable<FunctionBinding> bindings = inputBindings.Union(outputBindings); bool addHttpRequestSystemParameter = false; foreach (var parameter in parameters) { // Is it the trigger parameter? if (string.Compare(parameter.Name, triggerMetadata.Name, StringComparison.Ordinal) == 0) { descriptors.Add(CreateTriggerParameterDescriptor(parameter, triggerMetadata)); if (triggerMetadata.Type == BindingType.HttpTrigger && parameter.ParameterType != typeof(HttpRequestMessage)) { addHttpRequestSystemParameter = true; } } else { Type parameterType = parameter.ParameterType; if (parameterType.IsByRef) { parameterType = parameterType.GetElementType(); } var descriptor = new ParameterDescriptor(parameter.Name, parameter.ParameterType); var binding = bindings.FirstOrDefault(b => string.Compare(b.Metadata.Name, parameter.Name, StringComparison.Ordinal) == 0); if (binding != null) { Collection<CustomAttributeBuilder> customAttributes = binding.GetCustomAttributes(); if (customAttributes != null) { foreach (var customAttribute in customAttributes) { descriptor.CustomAttributes.Add(customAttribute); } } } if (parameter.IsOut) { descriptor.Attributes |= ParameterAttributes.Out; } descriptors.Add(descriptor); } } // Add any additional common System parameters // Add ExecutionContext to provide access to InvocationId, etc. descriptors.Add(new ParameterDescriptor("context", typeof(ExecutionContext))); // If we have an HTTP trigger binding but we're not binding // to the HttpRequestMessage, require it as a system parameter if (addHttpRequestSystemParameter) { descriptors.Add(new ParameterDescriptor(ScriptConstants.DefaultSystemTriggerParameterName, typeof(HttpRequestMessage))); } return descriptors; } catch (AggregateException exc) { if (!(exc.InnerException is CompilationErrorException)) { throw; } } catch (CompilationErrorException) { } // We were unable to compile the function to get its signature, // setup the descriptor with the default parameters return base.GetFunctionParameters(functionInvoker, functionMetadata, triggerMetadata, methodAttributes, inputBindings, outputBindings); }