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 TestInvoker invoker = new TestInvoker(); FunctionDescriptor function = new FunctionDescriptor("TimerFunction", invoker, 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("TimerFunction"); 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); }
public override bool TryCreate(FunctionFolderInfo functionFolderInfo, out FunctionDescriptor functionDescriptor) { functionDescriptor = null; // name might point to a single file, or a module string extension = Path.GetExtension(functionFolderInfo.Source).ToLower(); if (!(extension == ".js" || string.IsNullOrEmpty(extension))) { return false; } // parse the bindings JObject bindings = (JObject)functionFolderInfo.Configuration["bindings"]; JArray inputs = (JArray)bindings["input"]; Collection<Binding> inputBindings = Binding.GetBindings(inputs, FileAccess.Read); JArray outputs = (JArray)bindings["output"]; Collection<Binding> outputBindings = Binding.GetBindings(outputs, FileAccess.Write); JObject trigger = (JObject)inputs.FirstOrDefault(p => ((string)p["type"]).ToLowerInvariant().EndsWith("trigger")); string triggerType = (string)trigger["type"]; string triggerParameterName = (string)trigger["name"]; if (string.IsNullOrEmpty(triggerParameterName)) { // default the name to simply 'input' trigger["name"] = triggerParameterName = "input"; } NodeFunctionInvoker invoker = new NodeFunctionInvoker(triggerParameterName, functionFolderInfo.Source, inputBindings, outputBindings); ParameterDescriptor triggerParameter = null; switch (triggerType) { case "queueTrigger": triggerParameter = ParseQueueTrigger(trigger); break; case "blobTrigger": triggerParameter = ParseBlobTrigger(trigger); break; case "serviceBusTrigger": triggerParameter = ParseServiceBusTrigger(trigger); break; case "timerTrigger": triggerParameter = ParseTimerTrigger(trigger, typeof(TimerInfo)); break; case "webHookTrigger": triggerParameter = ParseWebHookTrigger(trigger); break; } Collection<ParameterDescriptor> parameters = new Collection<ParameterDescriptor>(); 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))); functionDescriptor = new FunctionDescriptor(functionFolderInfo.Name, invoker, parameters); return true; }
public abstract bool TryCreate(FunctionFolderInfo functionFolderInfo, out FunctionDescriptor functionDescriptor);
public abstract bool TryCreate(JObject function, out FunctionDescriptor functionDescriptor);
public override bool TryCreate(JObject function, out FunctionDescriptor functionDescriptor) { functionDescriptor = null; string name = (string)function["name"]; if (string.IsNullOrEmpty(name)) { // if a method name isn't explicitly provided, derive it // from the script file name string source = (string)function["source"]; name = Path.GetFileNameWithoutExtension(source); } MethodInfo method = FindMethod(name); if (method == null) { throw new InvalidOperationException(string.Format("Unable to bind to method '{0}'", name)); } MethodInvoker invoker = new MethodInvoker(method); JObject trigger = (JObject)function["trigger"]; string triggerType = (string)trigger["type"]; // TODO: match based on name? Or is positional convention OK? ParameterInfo[] sourceParameters = invoker.Target.GetParameters(); ParameterInfo targetTriggerParameter = sourceParameters[0]; Type triggerParameterType = targetTriggerParameter.ParameterType; string parameterName = (string)trigger["name"]; if (string.IsNullOrEmpty(parameterName)) { // default the name to the actual source parameter name trigger["name"] = targetTriggerParameter.Name; } ParameterDescriptor triggerParameter = null; switch (triggerType) { case "queue": triggerParameter = ParseQueueTrigger(trigger, triggerParameterType); break; case "blob": triggerParameter = ParseBlobTrigger(trigger, triggerParameterType); break; case "serviceBus": triggerParameter = ParseServiceBusTrigger(trigger, triggerParameterType); break; case "timer": triggerParameter = ParseTimerTrigger(trigger, triggerParameterType); break; case "webHook": triggerParameter = ParseWebHookTrigger(trigger, typeof(HttpRequestMessage)); break; } Collection<ParameterDescriptor> parameters = new Collection<ParameterDescriptor>(); parameters.Add(triggerParameter); // now add any additional parameters found on the source method // TODO: restrict to certain types only? foreach (ParameterInfo sourceParameter in sourceParameters.Skip(1)) { ParameterDescriptor parameter = new ParameterDescriptor { Name = sourceParameter.Name, Type = sourceParameter.ParameterType }; parameters.Add(parameter); } functionDescriptor = new FunctionDescriptor { Name = name, Invoker = invoker, Parameters = parameters }; return true; }