14

I am new to Azure Durable functions and have been following the sample code in the book 'Azure Serverless Computing Cookbook' and I am stuck because the .GetInput function in my Orchestrator is return null. My Blob trigger is passing the file name as a parameter in the call to my Orchestrator. I think its calling the wrong overloaded function but not sure how to call the correct one.

await starter.StartNewAsync("CSVImport_Orchestrator", name); 
        [FunctionName("CSVImport_Orchestrator")]
        public static async Task<List<string>> RunOrchestrator([OrchestrationTrigger] IDurableOrchestrationContext context)
        {
            var outputs = new List<string>();
            string CSVFileName = context.GetInput<string>(); //<<== returns null???
            {
                List<Employee> employees = await context.CallActivityAsync<List<Employee>>("ReadCSV_AT", CSVFileName);
            }
            return outputs;
        }

        [FunctionName("CSVImportBlobTrigger")]
        public static async  void Run([BlobTrigger("import-obiee-report/{name}", Connection = "StorageConnection")]Stream myBlob, string name, [DurableClient]IDurableOrchestrationClient starter, ILogger log)
        {
            string instanceId = await starter.StartNewAsync("CSVImport_Orchestrator", name); 
            log.LogInformation($"C# Blob trigger function Processed blob\n Name:{name} \n Size: {myBlob.Length} Bytes");
        }

In advance, thank you for your help.

PKonstant
  • 834
  • 2
  • 15
  • 32

1 Answers1

18

You are calling the non-generic overload of StartAsync(string, string) where the second, string argument represents the InstanceId and not the input argument. There's also a generic overload where the second argument represents the data. You are passing a string so overload resolution sees two potential candidates. It then prefers the non-generic one since it's an exact match, thus "losing" your data.

If you really need a string for your input data you will need to specify the generic argument explicitly to force the compiler to select the correct overload:

await starter.StartAsync<string>("CSVImport_Orchestrator", name);

Now, the documentation also states that the input should be a JSON-serializeable object. Technically a string is, but I'm not sure how it plays with the orchestrator's serializer. You can instead pass a class containing your data. This has the upside that the generic argument will be properly inferred:

public class Data {
   public string Name { get; set; } 
} 

// calling 
await starter.StartAsync("CSVImport_Orchestrator", new Data { Name = name });

// using 
var csvFileName = context.GetInput<Data>()?.Name;
pinkfloydx33
  • 11,863
  • 3
  • 46
  • 63
  • I like your class idea instead. Can you explain 'public record Data(string Name)'? (It didn't compile.) – PKonstant Mar 15 '21 at 19:49
  • It's a c#9 feature called records. That line declares a class with a single public property called "Name". But as I'm responding to you I realize azure functions cannot run on net5 and even if you use the latest compiler it won't support the new features. I've updated the example to use a full class. Sorry about that – pinkfloydx33 Mar 15 '21 at 21:28
  • 1
    Using your class idea worked! Thank you very much! – PKonstant Mar 16 '21 at 13:19