private static ImmutableArray<PackageReference> InitializeAssemblyRegistry(FunctionMetadata metadata) { var builder = ImmutableArray<PackageReference>.Empty.ToBuilder(); string fileName = Path.Combine(Path.GetDirectoryName(metadata.Source), CSharpConstants.ProjectLockFileName); if (File.Exists(fileName)) { var jobject = JObject.Parse(File.ReadAllText(fileName)); var target = jobject.SelectTokens(string.Format(CultureInfo.InvariantCulture, "$.targets['{0}']", FrameworkTargetName)).FirstOrDefault(); if (target != null) { string nugetHome = PackageManager.GetNugetPackagesPath(); foreach (JProperty token in target) { var referenceNameParts = token.Name.Split('/'); if (referenceNameParts.Length != 2) { throw new FormatException(string.Format(CultureInfo.InvariantCulture, "The package name '{0}' is not correctly formatted.", token.Name)); } var package = new PackageReference(referenceNameParts[0], referenceNameParts[1]); var references = token.SelectTokens("$..compile").FirstOrDefault(); if (references != null) { foreach (JProperty reference in references) { if (!reference.Name.EndsWith(EmptyFolderFileMarker, StringComparison.Ordinal)) { string path = Path.Combine(nugetHome, token.Name, reference.Name); path = path.Replace('/', '\\'); if (File.Exists(path)) { package.Assemblies.Add(AssemblyName.GetAssemblyName(path), path); } } } } var frameworkAssemblies = token.SelectTokens("$..frameworkAssemblies").FirstOrDefault(); if (frameworkAssemblies != null) { foreach (var assembly in frameworkAssemblies) { string assemblyName = assembly.ToString(); package.FrameworkAssemblies.Add(new AssemblyName(assemblyName), assemblyName); } } builder.Add(package); } } } return builder.ToImmutableArray(); }
public void Generate_WithMultipleOutParameters() { string functionName = "FunctionWithOuts"; Collection<ParameterDescriptor> parameters = new Collection<ParameterDescriptor>(); parameters.Add(new ParameterDescriptor("param1", typeof(string))); parameters.Add(new ParameterDescriptor("param2", typeof(string).MakeByRefType()) { Attributes = ParameterAttributes.Out }); parameters.Add(new ParameterDescriptor("param3", typeof(string).MakeByRefType()) { Attributes = ParameterAttributes.Out }); FunctionMetadata metadata = new FunctionMetadata(); TestInvoker invoker = new TestInvoker(); FunctionDescriptor function = new FunctionDescriptor(functionName, invoker, metadata, parameters); Collection<FunctionDescriptor> functions = new Collection<FunctionDescriptor>(); functions.Add(function); // generate the Type Type functionType = FunctionGenerator.Generate("TestScriptHost", "TestFunctions", functions); // verify the generated function MethodInfo method = functionType.GetMethod(functionName); ParameterInfo[] functionParams = method.GetParameters(); // Verify that we have the correct number of parameters Assert.Equal(parameters.Count, functionParams.Length); // Verify that out parameters were correctly generated Assert.True(functionParams[1].IsOut); Assert.True(functionParams[2].IsOut); // Verify that the method is invocable method.Invoke(null, new object[] { "test", null, null }); // verify our custom invoker was called Assert.Equal(1, invoker.InvokeCount); }
public void Register(FunctionRegistrationContext context) { FunctionMetadata metadata = context.Metadata; // associate the invocation input buffer with the function _functionInputBuffers[context.Metadata.FunctionId] = context.InputBuffer; // send a load request for the registered function FunctionLoadRequest request = new FunctionLoadRequest() { FunctionId = metadata.FunctionId, Metadata = new RpcFunctionMetadata() { Name = metadata.Name, Directory = metadata.FunctionDirectory, EntryPoint = metadata.EntryPoint ?? string.Empty, ScriptFile = metadata.ScriptFile ?? string.Empty } }; foreach (var binding in metadata.Bindings) { request.Metadata.Bindings.Add(binding.Name, new BindingInfo { Direction = (BindingInfo.Types.Direction)binding.Direction, Type = binding.Type }); } Send(new StreamingMessage { FunctionLoadRequest = request }); }
public async Task FunctionDispatcherState_Default_DotNetFunctions() { RpcFunctionInvocationDispatcher functionDispatcher = GetTestFunctionDispatcher(); Assert.Equal(FunctionInvocationDispatcherState.Default, functionDispatcher.State); FunctionMetadata func1 = new FunctionMetadata() { Name = "func1", Language = "dotnet" }; var functions = new List <FunctionMetadata>() { func1 }; await functionDispatcher.InitializeAsync(functions); Assert.Equal(FunctionInvocationDispatcherState.Default, functionDispatcher.State); await functionDispatcher.InitializeAsync(functions); Assert.Equal(FunctionInvocationDispatcherState.Default, functionDispatcher.State); await functionDispatcher.InitializeAsync(functions); Assert.Equal(FunctionInvocationDispatcherState.Default, functionDispatcher.State); }
public void ValidateFunction_ThrowsOnDuplicateName() { var httpFunctions = new Dictionary <string, HttpTriggerAttribute>(); var name = "test"; // first add an http function var metadata = new FunctionMetadata(); var function = new Mock <FunctionDescriptor>(MockBehavior.Strict, name, null, metadata, null, null, null, null); var attribute = new HttpTriggerAttribute(AuthorizationLevel.Function, "get"); function.Setup(p => p.GetTriggerAttributeOrNull <HttpTriggerAttribute>()).Returns(() => attribute); ScriptHost.ValidateFunction(function.Object, httpFunctions); // add a proxy with same name metadata = new FunctionMetadata() { IsProxy = true }; function = new Mock <FunctionDescriptor>(MockBehavior.Strict, name, null, metadata, null, null, null, null); attribute = new HttpTriggerAttribute(AuthorizationLevel.Function, "get") { Route = "proxyRoute" }; function.Setup(p => p.GetTriggerAttributeOrNull <HttpTriggerAttribute>()).Returns(() => attribute); var ex = Assert.Throws <InvalidOperationException>(() => { ScriptHost.ValidateFunction(function.Object, httpFunctions); }); Assert.Equal(string.Format($"The function or proxy name '{name}' must be unique within the function app.", name), ex.Message); }
internal FunctionLoadRequest GetFunctionLoadRequest(FunctionMetadata metadata, ManagedDependencyOptions managedDependencyOptions) { FunctionLoadRequest request = new FunctionLoadRequest() { FunctionId = metadata.GetFunctionId(), Metadata = new RpcFunctionMetadata() { Name = metadata.Name, Directory = metadata.FunctionDirectory ?? string.Empty, EntryPoint = metadata.EntryPoint ?? string.Empty, ScriptFile = metadata.ScriptFile ?? string.Empty, IsProxy = false } }; if (managedDependencyOptions != null && managedDependencyOptions.Enabled) { _workerChannelLogger?.LogDebug($"Adding dependency download request to {_workerConfig.Description.Language} language worker"); request.ManagedDependencyEnabled = managedDependencyOptions.Enabled; } foreach (var binding in metadata.Bindings) { BindingInfo bindingInfo = binding.ToBindingInfo(); request.Metadata.Bindings.Add(binding.Name, bindingInfo); } return(request); }
internal void SendFunctionLoadRequest(FunctionMetadata metadata) { // send a load request for the registered function FunctionLoadRequest request = new FunctionLoadRequest() { FunctionId = metadata.FunctionId, Metadata = new RpcFunctionMetadata() { Name = metadata.Name, Directory = metadata.FunctionDirectory ?? string.Empty, EntryPoint = metadata.EntryPoint ?? string.Empty, ScriptFile = metadata.ScriptFile ?? string.Empty } }; if (_managedDependencyOptions?.Value != null && _managedDependencyOptions.Value.Enabled) { _workerChannelLogger?.LogDebug($"Adding dependency download request to {_workerConfig.Language} language worker"); request.ManagedDependencyEnabled = _managedDependencyOptions.Value.Enabled; } foreach (var binding in metadata.Bindings) { BindingInfo bindingInfo = binding.ToBindingInfo(); request.Metadata.Bindings.Add(binding.Name, bindingInfo); } SendStreamingMessage(new StreamingMessage { FunctionLoadRequest = request }); }
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.Source); 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 DotNetFunctionInvoker(ScriptHost host, FunctionMetadata functionMetadata, Collection<FunctionBinding> inputBindings, Collection<FunctionBinding> outputBindings, IFunctionEntryPointResolver functionEntryPointResolver, FunctionAssemblyLoader assemblyLoader, ICompilationServiceFactory compilationServiceFactory, ITraceWriterFactory traceWriterFactory = null) : base(host, functionMetadata, traceWriterFactory) { _metricsLogger = Host.ScriptConfig.HostConfig.GetService<IMetricsLogger>(); _functionEntryPointResolver = functionEntryPointResolver; _assemblyLoader = assemblyLoader; _metadataResolver = new FunctionMetadataResolver(functionMetadata, host.ScriptConfig.BindingProviders, TraceWriter); _compilationService = compilationServiceFactory.CreateService(functionMetadata.ScriptType, _metadataResolver); _inputBindings = inputBindings; _outputBindings = outputBindings; _triggerInputName = functionMetadata.Bindings.FirstOrDefault(b => b.IsTrigger).Name; InitializeFileWatcher(); _resultProcessor = CreateResultProcessor(); _functionLoader = new FunctionLoader<MethodInfo>(CreateFunctionTarget); _reloadScript = ReloadScript; _reloadScript = _reloadScript.Debounce(); _restorePackages = RestorePackages; _restorePackages = _restorePackages.Debounce(); }
public async Task IsFunction_ReturnsExpectedResult() { var host = TestHelpers.GetDefaultHost(o => { o.ScriptPath = TestHelpers.FunctionsTestDirectory; o.LogPath = TestHelpers.GetHostLogFileDirectory().FullName; }); await host.StartAsync(); var scriptHost = host.GetScriptHost(); var parameters = new Collection <ParameterDescriptor>(); parameters.Add(new ParameterDescriptor("param1", typeof(string))); var metadata = new FunctionMetadata(); var invoker = new TestInvoker(); var function = new FunctionDescriptor("TestFunction", invoker, metadata, parameters, null, null, null); scriptHost.Functions.Add(function); var errors = new Collection <string>(); errors.Add("A really really bad error!"); scriptHost.FunctionErrors.Add("ErrorFunction", errors); Assert.True(scriptHost.IsFunction("TestFunction")); Assert.True(scriptHost.IsFunction("ErrorFunction")); Assert.False(scriptHost.IsFunction("DoesNotExist")); Assert.False(scriptHost.IsFunction(string.Empty)); Assert.False(scriptHost.IsFunction(null)); }
internal void SendFunctionLoadRequest(FunctionRegistrationContext context) { FunctionMetadata metadata = context.Metadata; // associate the invocation input buffer with the function _functionInputBuffers[context.Metadata.FunctionId] = context.InputBuffer; // send a load request for the registered function FunctionLoadRequest request = new FunctionLoadRequest() { FunctionId = metadata.FunctionId, Metadata = new RpcFunctionMetadata() { Name = metadata.Name, Directory = metadata.FunctionDirectory ?? string.Empty, EntryPoint = metadata.EntryPoint ?? string.Empty, ScriptFile = metadata.ScriptFile ?? string.Empty } }; foreach (var binding in metadata.Bindings) { BindingInfo bindingInfo = binding.ToBindingInfo(); request.Metadata.Bindings.Add(binding.Name, bindingInfo); } SendStreamingMessage(new StreamingMessage { FunctionLoadRequest = request }); }
internal CSharpFunctionInvoker(ScriptHost host, FunctionMetadata functionMetadata, Collection<FunctionBinding> inputBindings, Collection<FunctionBinding> outputBindings, IFunctionEntryPointResolver functionEntryPointResolver, FunctionAssemblyLoader assemblyLoader) : base(host, functionMetadata) { _host = host; _functionEntryPointResolver = functionEntryPointResolver; _assemblyLoader = assemblyLoader; _metadataResolver = new FunctionMetadataResolver(functionMetadata, TraceWriter); _inputBindings = inputBindings; _outputBindings = outputBindings; _triggerInputName = GetTriggerInputName(functionMetadata); _metrics = host.ScriptConfig.HostConfig.GetService<IMetricsLogger>(); InitializeFileWatcherIfEnabled(); _resultProcessor = CreateResultProcessor(); _functionValueLoader = FunctionValueLoader.Create(CreateFunctionTarget); _reloadScript = ReloadScript; _reloadScript = _reloadScript.Debounce(); _restorePackages = RestorePackages; _restorePackages = _restorePackages.Debounce(); }
public FunctionAssemblyLoadContext(FunctionMetadata functionMetadata, Assembly functionAssembly, IFunctionMetadataResolver resolver, TraceWriter traceWriter) { _metadataResolver = resolver; _loadedAssemblies = ImmutableArray<Assembly>.Empty; _traceWriter = traceWriter; FunctionAssembly = functionAssembly; Metadata = functionMetadata; }
public FunctionMetadataResolver(FunctionMetadata metadata, TraceWriter traceWriter) { _functionMetadata = metadata; _traceWriter = traceWriter; _packageAssemblyResolver = new PackageAssemblyResolver(metadata); _privateAssembliesPath = GetBinDirectory(metadata); _scriptResolver = ScriptMetadataResolver.Default.WithSearchPaths(_privateAssembliesPath); }
internal ScriptFunctionInvoker(string scriptFilePath, ScriptHost host, FunctionMetadata functionMetadata, Collection<FunctionBinding> inputBindings, Collection<FunctionBinding> outputBindings) : base(host, functionMetadata) { _scriptFilePath = scriptFilePath; _inputBindings = inputBindings; _outputBindings = outputBindings; _metrics = host.ScriptConfig.HostConfig.GetService<IMetricsLogger>(); }
internal ScriptFunctionInvoker(string scriptFilePath, ScriptHost host, FunctionMetadata functionMetadata, Collection<FunctionBinding> inputBindings, Collection<FunctionBinding> outputBindings, ITraceWriterFactory traceWriterFactory = null) : base(host, functionMetadata, traceWriterFactory) { _scriptFilePath = scriptFilePath; _host = host; _inputBindings = inputBindings; _outputBindings = outputBindings; }
public FunctionMetadataResolver(FunctionMetadata metadata, ICollection<ScriptBindingProvider> bindingProviders, TraceWriter traceWriter) { _functionMetadata = metadata; _traceWriter = traceWriter; _packageAssemblyResolver = new PackageAssemblyResolver(metadata); _privateAssembliesPath = GetBinDirectory(metadata); _scriptResolver = ScriptMetadataResolver.Default.WithSearchPaths(_privateAssembliesPath); _extensionSharedAssemblyProvider = new ExtensionSharedAssemblyProvider(bindingProviders); }
public ICompilation GetFunctionCompilation(FunctionMetadata functionMetadata) { string code = GetFunctionSource(functionMetadata); Script<object> script = CSharpScript.Create(code, options: _metadataResolver.CreateScriptOptions(), assemblyLoader: AssemblyLoader.Value); Compilation compilation = GetScriptCompilation(script, functionMetadata); return new CSharpCompilation(compilation); }
internal void SendFunctionLoadRequest(FunctionMetadata metadata) { _workerChannelLogger.LogDebug("Sending FunctionLoadRequest for function:{functionName} with functionId:{id}", metadata.Name, metadata.FunctionId); // send a load request for the registered function SendStreamingMessage(new StreamingMessage { FunctionLoadRequest = GetFunctionLoadRequest(metadata) }); }
internal PowerShellFunctionInvoker(ScriptHost host, FunctionMetadata functionMetadata, Collection<FunctionBinding> inputBindings, Collection<FunctionBinding> outputBindings, ITraceWriterFactory traceWriterFactory = null) : base(host, functionMetadata, traceWriterFactory) { _host = host; _scriptFilePath = functionMetadata.ScriptFile; _functionName = functionMetadata.Name; _inputBindings = inputBindings; _outputBindings = outputBindings; }
public async Task FunctionDispatcherState_Initialized_RemainsInitializing(bool setException = false) { var mockRpcWorkerChannel = new Mock <IRpcWorkerChannel>(); var tcs = new TaskCompletionSource <IRpcWorkerChannel>(); Dictionary <string, TaskCompletionSource <IRpcWorkerChannel> > webhostLanguageWorkerChannels = new Dictionary <string, TaskCompletionSource <IRpcWorkerChannel> >(); Mock <IWebHostRpcWorkerChannelManager> mockWebHostChannelManager = new Mock <IWebHostRpcWorkerChannelManager>(); mockRpcWorkerChannel.Setup(a => a.StartWorkerProcessAsync(CancellationToken.None)).Returns(Task.FromResult(true)); mockRpcWorkerChannel.Setup(a => a.SetupFunctionInvocationBuffers(It.IsAny <IEnumerable <FunctionMetadata> >())); mockRpcWorkerChannel.Setup(a => a.SendFunctionLoadRequests(It.IsAny <ManagedDependencyOptions>(), It.IsAny <TimeSpan?>())); webhostLanguageWorkerChannels.Add("java", tcs); mockWebHostChannelManager.Setup(a => a.GetChannels(It.IsAny <string>())).Returns(webhostLanguageWorkerChannels); mockWebHostChannelManager.Setup(a => a.ShutdownChannelIfExistsAsync(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <Exception>())).Returns(Task.FromResult(true)); if (!setException) { tcs.SetResult(mockRpcWorkerChannel.Object); } else { tcs.SetException(new Exception()); } RpcFunctionInvocationDispatcher functionDispatcher = GetTestFunctionDispatcher(addWebhostChannel: true, mockwebHostLanguageWorkerChannelManager: mockWebHostChannelManager, runtime: RpcWorkerConstants.JavaLanguageWorkerName); FunctionMetadata func1 = new FunctionMetadata() { Name = "func1", Language = "node" }; var functions = new List <FunctionMetadata>() { func1 }; await functionDispatcher.InitializeAsync(functions); Assert.Equal(FunctionInvocationDispatcherState.Initializing, functionDispatcher.State); try { await WaitForFunctionDispactherStateInitialized(functionDispatcher); } catch (Exception) { // We don't care if this times out } if (!setException) { Assert.Equal(FunctionInvocationDispatcherState.Initialized, functionDispatcher.State); } else { Assert.Equal(FunctionInvocationDispatcherState.Initializing, functionDispatcher.State); } }
public async Task Generate_EndToEnd() { // construct our TimerTrigger attribute ([TimerTrigger("00:00:02", RunOnStartup = true)]) Collection<ParameterDescriptor> parameters = new Collection<ParameterDescriptor>(); ParameterDescriptor parameter = new ParameterDescriptor("timerInfo", typeof(TimerInfo)); ConstructorInfo ctorInfo = typeof(TimerTriggerAttribute).GetConstructor(new Type[] { typeof(string) }); PropertyInfo runOnStartupProperty = typeof(TimerTriggerAttribute).GetProperty("RunOnStartup"); CustomAttributeBuilder attributeBuilder = new CustomAttributeBuilder( ctorInfo, new object[] { "00:00:02" }, new PropertyInfo[] { runOnStartupProperty }, new object[] { true }); parameter.CustomAttributes.Add(attributeBuilder); parameters.Add(parameter); // create the FunctionDefinition FunctionMetadata metadata = new FunctionMetadata(); TestInvoker invoker = new TestInvoker(); FunctionDescriptor function = new FunctionDescriptor("TimerFunction", invoker, metadata, parameters); Collection<FunctionDescriptor> functions = new Collection<FunctionDescriptor>(); functions.Add(function); // Get the Type Attributes (in this case, a TimeoutAttribute) ScriptHostConfiguration scriptConfig = new ScriptHostConfiguration(); scriptConfig.FunctionTimeout = TimeSpan.FromMinutes(5); Collection<CustomAttributeBuilder> typeAttributes = ScriptHost.CreateTypeAttributes(scriptConfig); // generate the Type Type functionType = FunctionGenerator.Generate("TestScriptHost", "TestFunctions", typeAttributes, functions); // verify the generated function MethodInfo method = functionType.GetMethod("TimerFunction"); TimeoutAttribute timeoutAttribute = (TimeoutAttribute)functionType.GetCustomAttributes().Single(); Assert.Equal(TimeSpan.FromMinutes(5), timeoutAttribute.Timeout); Assert.True(timeoutAttribute.ThrowOnTimeout); Assert.True(timeoutAttribute.TimeoutWhileDebugging); ParameterInfo triggerParameter = method.GetParameters()[0]; TimerTriggerAttribute triggerAttribute = triggerParameter.GetCustomAttribute<TimerTriggerAttribute>(); Assert.NotNull(triggerAttribute); // start the JobHost which will start running the timer function JobHostConfiguration config = new JobHostConfiguration() { TypeLocator = new TypeLocator(functionType) }; config.UseTimers(); JobHost host = new JobHost(config); await host.StartAsync(); await Task.Delay(3000); await host.StopAsync(); // verify our custom invoker was called Assert.True(invoker.InvokeCount >= 2); }
internal void SendFunctionLoadRequest(FunctionMetadata metadata, ManagedDependencyOptions managedDependencyOptions) { _functionLoadRequestResponseEvent = _metricsLogger.LatencyEvent(MetricEventNames.FunctionLoadRequestResponse); _workerChannelLogger.LogDebug("Sending FunctionLoadRequest for function:{functionName} with functionId:{id}", metadata.Name, metadata.FunctionId); // send a load request for the registered function SendStreamingMessage(new StreamingMessage { FunctionLoadRequest = GetFunctionLoadRequest(metadata, managedDependencyOptions) }); }
public override bool TryCreate(FunctionMetadata functionMetadata, out FunctionDescriptor functionDescriptor) { functionDescriptor = null; string extension = Path.GetExtension(functionMetadata.Source).ToLower(); if (!(extension == ".js" || string.IsNullOrEmpty(extension))) { return false; } return base.TryCreate(functionMetadata, out functionDescriptor); }
internal NodeFunctionInvoker(ScriptHost host, BindingMetadata trigger, FunctionMetadata functionMetadata, Collection<FunctionBinding> inputBindings, Collection<FunctionBinding> outputBindings) : base(host, functionMetadata) { _trigger = trigger; string scriptFilePath = functionMetadata.Source.Replace('\\', '/'); _script = string.Format(CultureInfo.InvariantCulture, _functionTemplate, scriptFilePath); _inputBindings = inputBindings; _outputBindings = outputBindings; _metrics = host.ScriptConfig.HostConfig.GetService<IMetricsLogger>(); InitializeFileWatcherIfEnabled(); }
public async Task ReloadScript_WithInvalidCompilationAndMissingMethod_ReportsResults() { // Create the compilation exception we expect to throw during the reload var descriptor = new DiagnosticDescriptor(DotNetConstants.MissingFunctionEntryPointCompilationCode, "Test compilation exception", "Test compilation error", "AzureFunctions", DiagnosticSeverity.Error, true); var exception = new CompilationErrorException("Test compilation exception", ImmutableArray.Create(Diagnostic.Create(descriptor, Location.None))); // Create the invoker dependencies and setup the appropriate method to throw the exception RunDependencies dependencies = CreateDependencies(); dependencies.Compilation.Setup(c => c.GetEntryPointSignature(It.IsAny<IFunctionEntryPointResolver>())) .Throws(exception); dependencies.Compilation.Setup(c => c.EmitAndLoad(It.IsAny<CancellationToken>())) .Returns(typeof(object).Assembly); string rootFunctionsFolder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); Directory.CreateDirectory(rootFunctionsFolder); // Create a dummy file to represent our function string filePath = Path.Combine(rootFunctionsFolder, Guid.NewGuid().ToString() + ".csx"); File.WriteAllText(filePath, string.Empty); var metadata = new FunctionMetadata { ScriptFile = filePath, Name = Guid.NewGuid().ToString(), ScriptType = ScriptType.CSharp }; metadata.Bindings.Add(new BindingMetadata() { Name = "Test", Type = "ManualTrigger" }); var invoker = new DotNetFunctionInvoker(dependencies.Host.Object, metadata, new Collection<Script.Binding.FunctionBinding>(), new Collection<FunctionBinding>(), dependencies.EntrypointResolver.Object, new FunctionAssemblyLoader(string.Empty), dependencies.CompilationServiceFactory.Object, dependencies.TraceWriterFactory.Object); // Update the file to trigger a reload File.WriteAllText(filePath, string.Empty); await TestHelpers.Await(() => { return dependencies.TraceWriter.Traces.Any(t => t.Message.Contains("Compilation failed.")) && dependencies.TraceWriter.Traces.Any(t => t.Message.Contains(DotNetConstants.MissingFunctionEntryPointCompilationCode)); }); dependencies.TraceWriter.Traces.Clear(); CompilationErrorException resultException = await Assert.ThrowsAsync<CompilationErrorException>(() => invoker.GetFunctionTargetAsync()); await TestHelpers.Await(() => { return dependencies.TraceWriter.Traces.Any(t => t.Message.Contains("Function compilation error")) && dependencies.TraceWriter.Traces.Any(t => t.Message.Contains(DotNetConstants.MissingFunctionEntryPointCompilationCode)); }); }
public bool IsSupported(FunctionMetadata functionMetadata, string workerRuntime) { if (string.IsNullOrEmpty(functionMetadata.Language)) { return(false); } if (string.IsNullOrEmpty(workerRuntime)) { return(true); } return(functionMetadata.Language.Equals(workerRuntime, StringComparison.OrdinalIgnoreCase)); }
public override bool TryCreate(FunctionMetadata functionMetadata, out FunctionDescriptor functionDescriptor) { functionDescriptor = null; string extension = Path.GetExtension(functionMetadata.Source).ToLower(); if (!ScriptFunctionInvoker.IsSupportedScriptType(extension)) { return false; } return base.TryCreate(functionMetadata, out functionDescriptor); }
// TODO: Is this function still needed? Can we factor it away? private static string GetTriggerInputName(FunctionMetadata functionMetadata) { BindingMetadata triggerBinding = functionMetadata.Bindings.FirstOrDefault(b => b.IsTrigger); string triggerName = null; if (triggerBinding != null) { triggerName = triggerBinding.Name; } return triggerName ?? FunctionDescriptorProvider.DefaultInputParameterName; }
private static string GetFunctionSource(FunctionMetadata functionMetadata) { string code = null; if (File.Exists(functionMetadata.ScriptFile)) { // We use ReadAllBytes here to make sure we preserve the BOM, if present. var codeBytes = File.ReadAllBytes(functionMetadata.ScriptFile); code = Encoding.UTF8.GetString(codeBytes); } return code ?? string.Empty; }
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 static bool IsCodelessDotNetLanguageFunction(FunctionMetadata functionMetadata) { if (functionMetadata == null) { throw new ArgumentNullException(nameof(functionMetadata)); } if (functionMetadata.IsCodeless() && !string.IsNullOrEmpty(functionMetadata.Language)) { return(IsDotNetLanguageFunction(functionMetadata.Language)); } return(false); }
public void TryGetFunctionFromException_FunctionMatch() { string stack = "TypeError: Cannot read property 'is' of undefined\n" + "at Timeout._onTimeout(D:\\home\\site\\wwwroot\\HttpTriggerNode\\index.js:7:35)\n" + "at tryOnTimeout (timers.js:224:11)\n" + "at Timer.listOnTimeout(timers.js:198:5)"; Collection <FunctionDescriptor> functions = new Collection <FunctionDescriptor>(); var exception = new InvalidOperationException(stack); // no match - empty functions bool result = ScriptHost.TryGetFunctionFromException(functions, exception, out FunctionDescriptor functionResult); Assert.False(result); Assert.Null(functionResult); // no match - one non-matching function FunctionMetadata metadata = new FunctionMetadata { Name = "SomeFunction", ScriptFile = "D:\\home\\site\\wwwroot\\SomeFunction\\index.js" }; FunctionDescriptor function = new FunctionDescriptor("TimerFunction", new TestInvoker(), metadata, new Collection <ParameterDescriptor>(), null, null, null); functions.Add(function); result = ScriptHost.TryGetFunctionFromException(functions, exception, out functionResult); Assert.False(result); Assert.Null(functionResult); // match - exact metadata = new FunctionMetadata { Name = "HttpTriggerNode", ScriptFile = "D:\\home\\site\\wwwroot\\HttpTriggerNode\\index.js" }; function = new FunctionDescriptor("TimerFunction", new TestInvoker(), metadata, new Collection <ParameterDescriptor>(), null, null, null); functions.Add(function); result = ScriptHost.TryGetFunctionFromException(functions, exception, out functionResult); Assert.True(result); Assert.Same(function, functionResult); // match - different file from the same function stack = "TypeError: Cannot read property 'is' of undefined\n" + "at Timeout._onTimeout(D:\\home\\site\\wwwroot\\HttpTriggerNode\\npm\\lib\\foo.js:7:35)\n" + "at tryOnTimeout (timers.js:224:11)\n" + "at Timer.listOnTimeout(timers.js:198:5)"; exception = new InvalidOperationException(stack); result = ScriptHost.TryGetFunctionFromException(functions, exception, out functionResult); Assert.True(result); Assert.Same(function, functionResult); }
public void GivenPackagesWithAssemblyReferences_AssemblyReferencesAreResolved() { var functionMetadata = new FunctionMetadata() { Name = "TestFunction", ScriptFile = _lockFilePath, /*We just need the path from this*/ ScriptType = ScriptType.CSharp }; var assemblyResolver = new PackageAssemblyResolver(functionMetadata); string nugetHome = PackageManager.GetNugetPackagesPath(); Assert.Contains<string>(_targetAssemblyFilePath, assemblyResolver.AssemblyReferences); }
public override bool TryCreate(FunctionMetadata functionMetadata, out FunctionDescriptor functionDescriptor) { if (functionMetadata == null) { throw new ArgumentNullException("functionMetadata"); } functionDescriptor = null; if (functionMetadata.ScriptType != ScriptType.CSharp) { return false; } return base.TryCreate(functionMetadata, out functionDescriptor); }
public override bool TryCreate(FunctionMetadata functionMetadata, out FunctionDescriptor functionDescriptor) { if (functionMetadata == null) { throw new ArgumentNullException("functionMetadata"); } functionDescriptor = null; if (!ScriptFunctionInvoker.IsSupportedScriptType(functionMetadata.ScriptType)) { return false; } return base.TryCreate(functionMetadata, out functionDescriptor); }
public void ValidateFunction_NoTriggerBinding_Throws() { FunctionMetadata functionMetadata = new FunctionMetadata(); functionMetadata.Bindings.Add(new BindingMetadata { Name = "test", Type = "Blob" }); var ex = Assert.Throws<InvalidOperationException>(() => { _provider.ValidateFunction(functionMetadata); }); Assert.Equal("No trigger binding specified. A function must have a trigger input binding.", ex.Message); }
public override bool TryCreate(FunctionMetadata functionMetadata, out FunctionDescriptor functionDescriptor) { if (functionMetadata == null) { throw new ArgumentNullException("functionMetadata"); } functionDescriptor = null; // We can only handle script types supported by the current compilation service factory if (!_compilationServiceFactory.SupportedScriptTypes.Contains(functionMetadata.ScriptType)) { return false; } return base.TryCreate(functionMetadata, out functionDescriptor); }
public void GivenLockFile_PackageReferencesAreResolved() { var functionMetadata = new FunctionMetadata() { Name = "TestFunction", ScriptFile = _lockFilePath, /*We just need the path from this*/ ScriptType = ScriptType.CSharp }; var assemblyResolver = new PackageAssemblyResolver(functionMetadata); PackageReference package = assemblyResolver.Packages.Single(); Assert.Equal("Test.Package", package.Name); Assert.Equal("1.0.0", package.Version); Assert.Equal(1, package.Assemblies.Count); Assert.Equal(2, package.FrameworkAssemblies.Count); }
public void IsSingleLanguage_Returns_True() { FunctionMetadata func1 = new FunctionMetadata() { Name = "funcJs1", Language = "node" }; FunctionMetadata func2 = new FunctionMetadata() { Name = "funcJs2", Language = "node" }; IEnumerable <FunctionMetadata> functionsList = new Collection <FunctionMetadata>() { func1, func2 }; Assert.True(Utility.IsSingleLanguage(functionsList, null)); }
public async Task FunctionDispatcherState_Transitions_From_Starting_To_Initialized() { RpcFunctionInvocationDispatcher functionDispatcher = GetTestFunctionDispatcher(); FunctionMetadata func1 = new FunctionMetadata() { Name = "func1", Language = "node" }; var functions = new List <FunctionMetadata>() { func1 }; await functionDispatcher.InitializeAsync(functions); Assert.Equal(FunctionInvocationDispatcherState.Initializing, functionDispatcher.State); await WaitForFunctionDispactherStateInitialized(functionDispatcher); Assert.Equal(FunctionInvocationDispatcherState.Initialized, functionDispatcher.State); }
public void IsSingleLanguage_Returns_False() { FunctionMetadata funcJs1 = new FunctionMetadata() { Name = "funcJs1", Language = "node" }; FunctionMetadata funcPython1 = new FunctionMetadata() { Name = "funcPython1", Language = "python", }; IEnumerable <FunctionMetadata> functionsList = new Collection <FunctionMetadata>() { funcJs1, funcPython1 }; Assert.False(Utility.IsSingleLanguage(functionsList, null)); }
public void IsSingleLanguage_Returns_True_Proxy() { FunctionMetadata proxy = new FunctionMetadata() { Name = "proxy", IsProxy = true }; FunctionMetadata funcJs = new FunctionMetadata() { Name = "funcJs", Language = "node" }; IEnumerable <FunctionMetadata> functionsList = new Collection <FunctionMetadata>() { proxy, funcJs }; Assert.True(Utility.IsSingleLanguage(functionsList, null)); }
private Compilation GetScriptCompilation(Script<object> script, FunctionMetadata functionMetadata) { Compilation compilation = script.GetCompilation(); if (_optimizationLevel == OptimizationLevel.Debug) { SyntaxTree scriptTree = compilation.SyntaxTrees.FirstOrDefault(t => string.IsNullOrEmpty(t.FilePath)); var debugTree = SyntaxFactory.SyntaxTree(scriptTree.GetRoot(), encoding: UTF8WithNoBOM, path: Path.GetFileName(functionMetadata.ScriptFile), options: new CSharpParseOptions(kind: SourceCodeKind.Script)); compilation = compilation .RemoveAllSyntaxTrees() .AddSyntaxTrees(debugTree); } return compilation.WithOptions(compilation.Options.WithOptimizationLevel(_optimizationLevel)) .WithAssemblyName(FunctionAssemblyLoader.GetAssemblyNameFromMetadata(functionMetadata, compilation.AssemblyName)); }
public void ResolveAssembly_WithIndirectPrivateDependency_IsResolved() { var resolver = new FunctionAssemblyLoader("c:\\"); var metadata1 = new FunctionMetadata { Name = "Test1", Source = @"c:\testroot\test1\test.tst" }; var metadata2 = new FunctionMetadata { Name = "Test2", Source = @"c:\testroot\test2\test.tst" }; var traceWriter = new TestTraceWriter(TraceLevel.Verbose); var mockResolver = new Mock<IFunctionMetadataResolver>(); mockResolver.Setup(m => m.ResolveAssembly("MyTestAssembly.dll")) .Returns(new TestAssembly(new AssemblyName("MyTestAssembly"))); resolver.CreateOrUpdateContext(metadata1, this.GetType().Assembly, new FunctionMetadataResolver(metadata1, traceWriter), traceWriter); resolver.CreateOrUpdateContext(metadata2, this.GetType().Assembly, mockResolver.Object, traceWriter); Assembly result = resolver.ResolveAssembly(null, new System.ResolveEventArgs("MyTestAssembly.dll", new TestAssembly(new AssemblyName("MyDirectReference"), @"file:///c:/testroot/test2/bin/MyDirectReference.dll"))); Assert.NotNull(result); }
internal ScriptFunctionInvoker(string scriptFilePath, ScriptHostConfiguration config, BindingMetadata trigger, FunctionMetadata functionMetadata, bool omitInputParameter, Collection<FunctionBinding> inputBindings, Collection<FunctionBinding> outputBindings) { _scriptFilePath = scriptFilePath; _config = config; _scriptType = Path.GetExtension(_scriptFilePath).ToLower().TrimStart('.'); _inputBindings = inputBindings; _outputBindings = outputBindings; _functionName = functionMetadata.Name; _omitInputParameter = omitInputParameter; _trigger = trigger; if (config.FileLoggingEnabled) { string logFilePath = Path.Combine(_config.RootLogPath, "Function", _functionName); _fileTraceWriter = new FileTraceWriter(logFilePath, TraceLevel.Verbose); } else { _fileTraceWriter = NullTraceWriter.Instance; } }
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, 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); 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); return true; } catch (Exception) { IDisposable disposableInvoker = invoker as IDisposable; if (disposableInvoker != null) { disposableInvoker.Dispose(); } throw; } }
public async Task ShutdownChannels_DotNetFunctions() { FunctionMetadata func1 = new FunctionMetadata() { Name = "func1", Language = "dotnet" }; var functions = new List <FunctionMetadata>() { func1 }; var mockLanguageWorkerChannelManager = new Mock <IWebHostRpcWorkerChannelManager>(); RpcFunctionInvocationDispatcher functionDispatcher = GetTestFunctionDispatcher(mockwebHostLanguageWorkerChannelManager: mockLanguageWorkerChannelManager); Assert.Equal(FunctionInvocationDispatcherState.Default, functionDispatcher.State); await functionDispatcher.InitializeAsync(functions); // Wait longer than debouce action. await Task.Delay(6000); mockLanguageWorkerChannelManager.Verify(m => m.ShutdownChannelsAsync(), Times.Once); }
internal void SendFunctionLoadRequest(FunctionRegistrationContext context) { FunctionMetadata metadata = context.Metadata; // associate the invocation input buffer with the function _functionInputBuffers[context.Metadata.FunctionId] = context.InputBuffer; // send a load request for the registered function FunctionLoadRequest request = new FunctionLoadRequest() { FunctionId = metadata.FunctionId, Metadata = new RpcFunctionMetadata() { Name = metadata.Name, Directory = metadata.FunctionDirectory ?? string.Empty, EntryPoint = metadata.EntryPoint ?? string.Empty, ScriptFile = metadata.ScriptFile ?? string.Empty } }; if (_managedDependencyOptions?.Value != null) { _workerChannelLogger?.LogInformation($"Adding dependency download request to {_workerConfig.Language} language worker"); request.ManagedDependencyEnabled = _managedDependencyOptions.Value.Enabled; } foreach (var binding in metadata.Bindings) { BindingInfo bindingInfo = binding.ToBindingInfo(); request.Metadata.Bindings.Add(binding.Name, bindingInfo); } SendStreamingMessage(new StreamingMessage { FunctionLoadRequest = request }); }
/// <summary> /// Sets the type that should be directly loaded by WebJobs if using attribute based configuration (these have the "configurationSource" : "attributes" set) /// They will be indexed and invoked directly by the WebJobs SDK and skip the IL generator and invoker paths. /// </summary> private void TrySetDirectType(FunctionMetadata metadata) { if (!metadata.IsDirect()) { return; } string path = metadata.ScriptFile; var typeName = Utility.GetFullClassName(metadata.EntryPoint); Assembly assembly = FunctionAssemblyLoadContext.Shared.LoadFromAssemblyPath(path); var type = assembly.GetType(typeName); if (type != null) { metadata.Properties.Add(ScriptConstants.FunctionMetadataDirectTypeKey, type); } else { // This likely means the function.json and dlls are out of sync. Perhaps a badly generated function.json? _logger.FailedToLoadType(typeName, path); } }
public async Task FunctionDispatcherState_Transitions_From_Default_To_Initialized_To_Disposing() { RpcFunctionInvocationDispatcher functionDispatcher = GetTestFunctionDispatcher(); Assert.Equal(FunctionInvocationDispatcherState.Default, functionDispatcher.State); FunctionMetadata func1 = new FunctionMetadata() { Name = "func1", Language = "node" }; var functions = new List <FunctionMetadata>() { func1 }; await functionDispatcher.InitializeAsync(functions); Assert.Equal(FunctionInvocationDispatcherState.Initializing, functionDispatcher.State); await WaitForFunctionDispactherStateInitialized(functionDispatcher); Assert.Equal(FunctionInvocationDispatcherState.Initialized, functionDispatcher.State); functionDispatcher.Dispose(); Assert.True(functionDispatcher == null || functionDispatcher.State == FunctionInvocationDispatcherState.Disposing || functionDispatcher.State == FunctionInvocationDispatcherState.Disposed); }
public void IsSingleLanguage_FunctionsWorkerRuntime_Set_Returns_True_() { FunctionMetadata funcPython1 = new FunctionMetadata() { Name = "funcPython1", Language = "python", }; FunctionMetadata funcJs = new FunctionMetadata() { Name = "funcJs", Language = "node" }; FunctionMetadata funcCSharp1 = new FunctionMetadata() { Name = "funcCSharp1", Language = "CSharp", }; IEnumerable <FunctionMetadata> functionsList = new Collection <FunctionMetadata>() { funcPython1, funcJs, funcCSharp1 }; Assert.True(Utility.IsSingleLanguage(functionsList, "node")); }
public bool IsSupported(FunctionMetadata functionMetadata) { return(_workerConfigs.Any(config => config.Extension == Path.GetExtension(functionMetadata.ScriptFile))); }
public void ValidateFunction_ValidatesHttpRoutes() { var httpFunctions = new Dictionary <string, HttpTriggerAttribute>(); // first add an http function var metadata = new FunctionMetadata(); var function = new Mock <FunctionDescriptor>(MockBehavior.Strict, "test", null, metadata, null, null, null, null); var attribute = new HttpTriggerAttribute(AuthorizationLevel.Function, "get") { Route = "products/{category}/{id?}" }; function.Setup(p => p.GetTriggerAttributeOrNull <HttpTriggerAttribute>()).Returns(() => attribute); ScriptHost.ValidateFunction(function.Object, httpFunctions); Assert.Equal(1, httpFunctions.Count); Assert.True(httpFunctions.ContainsKey("test")); // add another for a completely different route function = new Mock <FunctionDescriptor>(MockBehavior.Strict, "test2", null, metadata, null, null, null, null); attribute = new HttpTriggerAttribute(AuthorizationLevel.Function, "get") { Route = "/foo/bar/baz/" }; function.Setup(p => p.GetTriggerAttributeOrNull <HttpTriggerAttribute>()).Returns(() => attribute); ScriptHost.ValidateFunction(function.Object, httpFunctions); Assert.Equal(2, httpFunctions.Count); Assert.True(httpFunctions.ContainsKey("test2")); // add another that varies from another only by http methods function = new Mock <FunctionDescriptor>(MockBehavior.Strict, "test3", null, metadata, null, null, null, null); attribute = new HttpTriggerAttribute(AuthorizationLevel.Function, "put", "post") { Route = "/foo/bar/baz/" }; function.Setup(p => p.GetTriggerAttributeOrNull <HttpTriggerAttribute>()).Returns(() => attribute); ScriptHost.ValidateFunction(function.Object, httpFunctions); Assert.Equal(3, httpFunctions.Count); Assert.True(httpFunctions.ContainsKey("test3")); // now try to add a function for the same route // where the http methods overlap function = new Mock <FunctionDescriptor>(MockBehavior.Strict, "test4", null, metadata, null, null, null, null); attribute = new HttpTriggerAttribute { Route = "/foo/bar/baz/" }; function.Setup(p => p.GetTriggerAttributeOrNull <HttpTriggerAttribute>()).Returns(() => attribute); var ex = Assert.Throws <InvalidOperationException>(() => { ScriptHost.ValidateFunction(function.Object, httpFunctions); }); Assert.Equal("The route specified conflicts with the route defined by function 'test2'.", ex.Message); Assert.Equal(3, httpFunctions.Count); // try to add a route under reserved admin route function = new Mock <FunctionDescriptor>(MockBehavior.Strict, "test5", null, metadata, null, null, null, null); attribute = new HttpTriggerAttribute { Route = "admin/foo/bar" }; function.Setup(p => p.GetTriggerAttributeOrNull <HttpTriggerAttribute>()).Returns(() => attribute); ex = Assert.Throws <InvalidOperationException>(() => { ScriptHost.ValidateFunction(function.Object, httpFunctions); }); Assert.Equal("The specified route conflicts with one or more built in routes.", ex.Message); // verify that empty route is defaulted to function name function = new Mock <FunctionDescriptor>(MockBehavior.Strict, "test6", null, metadata, null, null, null, null); attribute = new HttpTriggerAttribute(); function.Setup(p => p.GetTriggerAttributeOrNull <HttpTriggerAttribute>()).Returns(() => attribute); ScriptHost.ValidateFunction(function.Object, httpFunctions); Assert.Equal(4, httpFunctions.Count); Assert.True(httpFunctions.ContainsKey("test6")); Assert.Equal("test6", attribute.Route); }
public override Assembly Load(FunctionMetadata metadata, IFunctionMetadataResolver metadataResolver, ILogger logger) => FunctionAssemblyLoadContext.Shared.LoadFromAssemblyPath(AssemblyPath, true);
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 ICompilationService <IJavaScriptCompilation> CreateService(ScriptType scriptType, FunctionMetadata metadata) { switch (scriptType) { case ScriptType.Javascript: return(new RawJavaScriptCompilationService(metadata)); case ScriptType.TypeScript: return(new TypeScriptCompilationService()); default: throw new NotSupportedException(string.Format(CultureInfo.InvariantCulture, "The script type {0} is not supported by the {1}", scriptType, typeof(JavaScriptCompilationServiceFactory).Name)); } }
public abstract Assembly Load(FunctionMetadata metadata, IFunctionMetadataResolver metadataResolver, ILogger logger);
private static IFunctionMetadataResolver CreateMetadataResolver(ScriptHost host, FunctionMetadata functionMetadata, ILogger logger) { return(new FunctionMetadataResolver(functionMetadata.ScriptFile, host.ScriptConfig.BindingProviders, logger)); }
public static string GetAssemblyNameFromMetadata(FunctionMetadata metadata, string suffix) { return(AssemblyPrefix + metadata.Name + AssemblySeparator + suffix.GetHashCode().ToString()); }