Azure Functions + System.Text.JSON Deserialize exception
If you run into a System.IO.FileNotFoundException exception from the Azure Function when it is deserializing JSON with System.Text.Json to your class, make sure you are not using System.Text.Json 5.0.2.
Issue
FileNotFoundException: Could not load file or assembly 'System.Text.Encodings.Web, Version=5.0.0.0, Culture=neutral
Fix
Downgrade to System.Text.Json 5.0.1.
Project description
The issue was found while moving code from a working .NET Framework 4.6.1 web api project into a .NET Core 3.1 class library, which is called from an Azure Function 3. The deserialization happens in the class library. The manual and automated testing described in the post were both local to my development machine, not on the Azure Cloud.
Initially it was tested by the Azure Function manually. Later, as I thought the issue was about the JSON returned, I added automated programmatic tests to call into the class library in a separate test project. The test project worked so the issue had to be the Azure Function runtime or its dependencies.
Before unit tests
Before the unit test, I knew the FileNotFound exception was a symptom but I assumed the real problem was the JSON being deserialized. The deserialization code went from the HTTP response content directly to a stream wrapped in the deserialization code, so it immediately threw without seeing, in the Visual Studio 2019 debugger, what JSON was returned.
Adding unit tests
I broke apart the response from the deserialization. That allowed me to see the JSON and create unit tests. When I realized the JSON was deserializable from unit tests, I thought it was something about how the debugger was compensating for the text. There could be some difference between the raw text in the unit test and the text processed by the Azure Function. Adding my Debug.Write statements between maual and automated testing runs showed that the text was the same and that the problem was still with deserialization.
At this point, I assumed it was a runtime issue but thought it was something about the HTTP call and how it was creating the JSON.
Offload deserialization to a queue
As a bonus, breaking up the JSON fetch from the deserialization allows the system to offload the deserialization and downstream tasks to a queue. In that architecture, where an Azure Function timeout isn't at risk for the caller, I could add as much data cleaning as needed in future sprints.
The runtime problem
Now that tests could deserialize, the hunt was on for the runtime problem. The JSON deserialization worked in .NET 4.6.1 Framework with Newtonsoft deserialization but not the Azure Function with System.Text.Json. At this point, searching the Internet led to several issues about System.Text.Json in Azure Functions. Downgrading the library to 5.0.1 was the listed fix.
Other problems
Before the unit tests, other things tried:
* Downloaded and setup the Fusion logger to look for mismatched dependencies - nothing turned up with that.
* Tried to add a lock around the code to see into the function call, because it was in an async loop. The thought was this was some missed async handling somewhere that was showing up here. The lock in .NET Core was cumbersome and unfamiliar and wasn't blocking when I wanted it to so I stopped going down that rabbit hole.