Open mattchenderson opened 1 year ago
I'm not 100% sure if this is a bug. This was an intentional implementation on the host side to "SkipDeferredBinding" if expressions are used in input or output bindings (code).
The bigger issue/bug is that expressions do not work with deferred binding period, and the workaround was to skip deferred binding for scenarios like this. I thought we had another issue tracking that, but if we do not, we can use this.
During the SDK-binding feature work, we found that expressions were not working as expected, further investigation found that there is a bug in the WebJobs SDK that is behind this. The WebJobs SDK bug needs to be addressed for expressions to work with SDK-type bindings, however it is a breaking change fix and would therefore need to be part of the next major host (v5?). This has been identified as a parity blocker.
The bug is being tracked here: https://github.com/Azure/azure-webjobs-sdk/issues/2930
The decision to skip deferred binding for this specific scenario was an intentional, and temporary, decision to unblock the release of the SDK-binding feature.
Related context:
In general, expressions are supported with SDK-types except for this one specific scenario:
If an input (or output) binding uses an expression, the trigger binding will not use ParameterBindingData (the input binding will continue to use ParameterBindingData).
In other words: the issue only occurs when a trigger binding is used with an input or output binding that uses an expression. We currently only support SDK-types for trigger bindings if none of the function's input or output bindings contain an expression.
There is a purple note about this in the public docs, but maybe it is not clear enough (cc: @mattchenderson)
Note: The broken scenarios are only for extensions that use deferred binding/SDK-types.
❌ This is broken :(
[BlobTrigger("containerA/{name}")] Stream myBlob,
[BlobInput("containerB/{name}")] Stream myOtherBlob, string name
⚠️ This is also broken (cannot use property of POCO as parameter for input binding) but only for extensions that use deferred binding for POCO types too i.e. Blob and Cosmos
[BlobTrigger("containerA/{name}")] Book myBook,
[BlobInput("containerB/{Book.Property}")] Stream myOtherBlob, string name
✅ This is OK
[BlobTrigger("containerA/{name}")] string myBlob, // string, byte[] or POCO supported
[BlobInput("containerB/{name}")] Stream myOtherBlob, string name
✅ This is OK
[BlobTrigger("containerA/{name}")] Stream myBlob, string name,
[BlobInput("containerB")] Stream[] blobs
✅ This is OK
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequest req,
[BlobInput("containerA/{Query.name}")] Stream myBlob, string name
⭐️ As mentioned above, we will keep this issue open to track that this is fixed as part of the next major host.
I was getting this error as well in a .NET 8 Isolated Blob Trigger. Cannot convert input parameter 'stream' to type 'System.IO.Stream' My issue was that even though I had added my user secrets for my blob connection string, it was not defined in my program.cs. You can also put the blob storage connection string in the local.settings.json. Here is what I added to my program.cs.
.ConfigureAppConfiguration(config => { config.AddUserSecrets<YourFunctionHere>(optional: true, reloadOnChange: false); })
Even binding to BlobClient is broken. So this doesn't work too
[BlobTrigger("containerA")] BlobClient input
This requires some additional validation to understand whether the output binding logic is currently honoring the binding data defined by the trigger expression.
Flagging this for follow up as investigation is required.
Adding additional context here -
The distinction between payload
and binding data (aka trigger metadata)
is important here. To make sure that the terminology is clear, in the below example - data
is payload and name
is trigger metadata.
[Function(nameof(CreateThumbnail))]
[BlobOutput("thumbnails/{name}-thumbnail.jpg", Connection = "AzureWebJobsStorage")]
public async Task<byte[]> Run([BlobTrigger("images/{name}", Connection = "AzureWebJobsStorage")] Stream data, string name)
This code skips deferred binding if there is any expression in Input/Output binding. The restriction makes sense for payload - if we defer it to the worker, then we can't consume it in the host. However, there shouldn't be a need for binding data to prompt consumption of the resource data.
Hence, the first ask here is to investigate if we can allow expressions for the scenario where trigger metadata is used in output binding expressions.
Trigger metadata (not payload data), if consumed in an output binding, for example, will cause consumption of the trigger payload.
This will not work:
stream
will have already been consumed and have failed to be parsed byJsonPocoConverter
. Here's the exception:If you remove the binding data reference, it will work as expected, though: