protected ParameterDescriptor ParseQueueTrigger(JObject trigger, Type triggerParameterType = null) { if (triggerParameterType == null) { triggerParameterType = typeof(string); } ConstructorInfo ctorInfo = typeof(QueueTriggerAttribute).GetConstructor(new Type[] { typeof(string) }); string queueName = (string)trigger["queueName"]; CustomAttributeBuilder attributeBuilder = new CustomAttributeBuilder(ctorInfo, new object[] { queueName }); string parameterName = (string)trigger["name"]; ParameterDescriptor triggerParameter = new ParameterDescriptor { Name = parameterName, Type = triggerParameterType, Attributes = ParameterAttributes.None, CustomAttributes = new Collection<CustomAttributeBuilder> { attributeBuilder } }; return triggerParameter; }
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); }
protected ParameterDescriptor ParseServiceBusTrigger(JObject trigger, Type triggerParameterType = null) { if (triggerParameterType == null) { triggerParameterType = typeof(string); } string queueName = (string)trigger["queueName"]; string topicName = (string)trigger["topicName"]; string subscriptionName = (string)trigger["subscriptionName"]; string accessRightsValue = (string)trigger["accessRights"]; AccessRights accessRights = AccessRights.Manage; if (!string.IsNullOrEmpty(accessRightsValue)) { AccessRights parsed; if (Enum.TryParse<AccessRights>(accessRightsValue, true, out parsed)) { accessRights = parsed; } } CustomAttributeBuilder attributeBuilder = null; if (!string.IsNullOrEmpty(topicName) && !string.IsNullOrEmpty(subscriptionName)) { ConstructorInfo ctorInfo = typeof(ServiceBusTriggerAttribute).GetConstructor(new Type[] { typeof(string), typeof(string), typeof(AccessRights) }); attributeBuilder = new CustomAttributeBuilder(ctorInfo, new object[] { topicName, subscriptionName, accessRights }); } else if (!string.IsNullOrEmpty(queueName)) { ConstructorInfo ctorInfo = typeof(ServiceBusTriggerAttribute).GetConstructor(new Type[] { typeof(string), typeof(AccessRights) }); attributeBuilder = new CustomAttributeBuilder(ctorInfo, new object[] { queueName, accessRights }); } else { throw new InvalidOperationException("Invalid servicebus trigger configuration."); } string parameterName = (string)trigger["name"]; ParameterDescriptor triggerParameter = new ParameterDescriptor { Name = parameterName, Type = triggerParameterType, Attributes = ParameterAttributes.None, CustomAttributes = new Collection<CustomAttributeBuilder> { attributeBuilder } }; return triggerParameter; }
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; }