Azure / Azure/azure-functions-dotnet-worker
`BlobOutputAttribute` formats path with quoted string values
- Dominant language
- C#
- Stars
- 466
- Forks
- 215
- Avg merge
- 3d 10h
- Merged PRs (30d)
- 7
Description
### Description
When an Azure Function uses `BlobOutputAttribute` with a formatted path that gets mapped from a string argument that is passed into the function, the string value is unnecessarily serialized as JSON with double quotes.
This function is a step in an orchestrator function and doesn't have a `BlobTriggerAttribute` or `BlobInputAttribute`, so this could have something to do with those facts.
The value that is passed into the function is the correct unquoted string value that one would expect when the same string was passed in as the `object? input` argument to `TaskOrchestratorContext.CallActivityAsync()`.
So it seems like when that gets mapped to the formatted values in the path provided to `BlobOutputAttribute`, the value gets serialized, even though it is already a string.
The documentation here: https://learn.microsoft.com/en-us/azure/azure-functions/functions-bindings-storage-blob-output?tabs=python-v2%2Cisolated-process%2Cnodejs-v4&pivots=programming-language-csharp
But it seems like this documentation and/or the code are mixing up the concept of the path to the blob and the blob content. If the path is being formatted with some argument that has been passed into the function being run, then I can't think of why that argument's value should ever be serialized. That is especially true if it is already a string.
It seems like the path itself should always only get formatted using `ToString()` or the normal mechanism involve format providers/string conversions and so on, at least when formatting "direct" argument values with no property.
### Steps to reproduce
```csharp
[Function(nameof(SomeBlobFunction))]
[BlobOutput("container/{source}-output.json")]
public async Task SomeBlobFunction([ActivityTrigger] string source, FunctionContext executionContext)
{
// ...
}
```
If the argument source has a value of "SomeSource" (no double quote literals in the string) then the return value of the above function will be output to `$"container/"SomeSource"-output.json"`, and include double quotes presumably because the CLR string was, for some reason, serialized to a JSON string, even though it is being used in the path itself and the blob content comes from the return value.
I just tested this by passing a complex object into the function and using the argument name in the path and it does, indeed, get serialized to JSON into the path.
So something like this:
```csharp
// elsewhere:
public class SomeDataSource
{
public string Name { get; set; }
public string Url { get; set; }
}
[Function(nameof(SomeBlobFunction))]
[BlobOutput("container/{source}-output.json")]
public async Task SomeBlobFunction([ActivityTrigger] SomeDataSource source, FunctionContext executionContext)
{
// ...
}
```
Will write to a blob file named "container/{ \\"Name\": \\"the data source name\\", \\"Url\\": \\"the url\\" }-output.json" which does not seem like correct behavior.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with the provided SomeBlobFunction reproduction and trace how BlobOutputAttribute formats the path from the ActivityTrigger argument. Verify the resulting path for a direct string and a complex object, with completion marked by path values no longer being unexpectedly JSON-serialized or quoted.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- azure, csharp
- Domain
- backend, cloud
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 58/100