4

I'm not able to bind an input parameter of type blob to either string/TextReader without using the [BlobAttribute] in a C# implementation (not CSX).

The error I'm getting is:

Microsoft.Azure.WebJobs.Host: Error indexing method 'Functions.Harvester'. 
Microsoft.Azure.WebJobs.Host: Cannot bind parameter 'configReader' to type 
TextReader. Make sure the parameter Type is supported by the binding. If 
you're using binding extensions (e.g. ServiceBus, Timers, etc.) make sure 
you've called the registration method for the extension(s) in your startup 
code (e.g. config.UseServiceBus(), config.UseTimers(), etc.).

function.config:

"bindings": [
    {
      "type": "timerTrigger",
      "schedule": "0 */5 * * * *",
      "useMonitor": true,
      "runOnStartup": false,
      "direction": "in",
      "name": "myTimer"
    },
    {
      "type": "blob",
      "name": "configReader",
      "path": "secured/app.config.json",
      "connection": "XXX",
      "direction": "in"
    }
  ],

Function signature (NOT BINDING configReader):

[FunctionName("Harvester")]
 public static async Task Run(
   [TimerTrigger("0 */5 * * * *")]TimerInfo myTimer,
   TraceWriter log,
   TextReader configReader)

This would work though (BINDING configReader:

[FunctionName("Harvester")]
 public static async Task Run(
   [TimerTrigger("0 */5 * * * *")]TimerInfo myTimer,
   TraceWriter log,
   [Blob("secured/app.config.json", FileAccess.Read)]TextReader configReader)

Any idea on how to get it working without specifying the blob path in BlobAttribute. I'd ideally keep the Blob config outside of the code, that way my function would become more portable.

6
  • Are you using VS 2017 tooling? If you are, can you check in the output folder for a folder called Harvester that contains a function.json file. Can you check if it has a property called configurationSource and what value it has? Commented Aug 22, 2017 at 16:15
  • I'm using VS2017 tooling, checked the file but there's no such property called configurationSource. Were you by any chance referring to configReader? If so, that's as described in my original question (btw the listing above comes from the azure UI). Commented Aug 22, 2017 at 16:38
  • no, configurationSource is a new property that was introduced with the 2017 tooling to tell the function runtime to use attributes vs config file. Can you check the version of `` in your csproj? the latest is 1.0.2, though note that this should put configurationSource to be attributes, you'll need to change that to config to tell the runtime to use the config instead of the attributes. Then you'll need to include that json file in your project Commented Aug 22, 2017 at 17:02
  • Your question was about the Microsoft.NET.Sdk.Functions package, and indeed I was on 1.0.0-alpha3. Switched to 1.0.2 and the configurationSrouce got rendered. Thanks for that! If I include the JSON file in the project, does it need to point to the location in my output folder (bin\Debug...)? I've included it as a file in my source tree, but it still generates configurationSource: 'attributes' Commented Aug 22, 2017 at 17:20
  • 1
    Thanks for sharing that, I can confirm it works as expected. Please escalate your comment as an answer and I'll feedback as such. Thanks! Commented Aug 22, 2017 at 19:08

1 Answer 1

6

The issue turned out to be with the latest runtime supporting a new property (configurationSource) in function.json

This tells the runtime to use either config (which is function.json) or C# attributes for function config.

essentially allowing you to either define your function like this

Now you can either define your function as

[FunctionName("Harvester")]
public static async Task Run(
    [TimerTrigger]TimerInfo myTimer,
    TraceWriter log,
    TextReader configReader)
{
}

along with a function.json that looks like this

{
  "generatedBy": "Microsoft.NET.Sdk.Functions-1.0.0.0",
  "configurationSource": "config",
  "bindings": [
    {
      "type": "timerTrigger",
      "schedule": "0 */5 * * * *",
      "useMonitor": true,
      "runOnStartup": false,
      "direction": "in",
      "name": "myTimer"
    },
    {
      "type": "blob",
      "name": "configReader",
      "path": "secured/app.config.json",
      "connection": "XXX",
      "direction": "in"
    }
  ],
  "disabled": false,
  "scriptFile": "...",
  "entryPoint": "..."
}

or like this

[FunctionName("Harvester")]
public static async Task Run(
    [TimerTrigger("0 */5 * * * *")]TimerInfo myTimer,
    TraceWriter log,
    [Blob("secured/app.config.json", FileAccess.Read)]TextReader configReader)
{
}

with a simpler config like this

{
  "generatedBy": "Microsoft.NET.Sdk.Functions-1.0.0.0",
  "configurationSource": "attributes",
  "bindings": [
    {
      "type": "timerTrigger",
      "name": "myTimer"
    },
  ],
  "scriptFile": "...",
  "entryPoint": "..."
}

note the value of configurationSource in both examples.

The tooling for Visual Studio 2017 does the latter by default. If you wanna change your function.json to include all your config and change the configurationSource you will need to include the file in your project and mark it as always copy. This GIF shows how to do that.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.