[dotnet] Loading of satellite assemblies (localized resources) fails
TLDR: AppContext.GetData("PLATFORM_RESOURCE_ROOTS") is not set the same as real Lambda runtime, so there is some difference between how the dotnet hosting environment is set up.
--
When running using aws-sam-cli via your (excellent) Docker image, compared to running on real AWS, our content localization fails. I think I've tracked this down to how assembly loading works when running inside this container's mock bootstrap.
We are following the standard localization procedure for an MVC Core 2.1 application, which is to say we've done the steps from these docs.
As a result, we end up having the following shape of artifacts from our build/publish, with resource dlls in culture-code folders:
WebApplication.dll
en/WebApplication.resources.dll
de/WebApplication.resources.dll
So far pretty normal, it just doesn't successfully output localized strings when running under the lambci bootstrap, and a bit of digging showed it was failing to load the resource binaries at all.
Research leads me to the following MS documentation on assembly loading algorithms: https://docs.microsoft.com/en-us/dotnet/core/dependency-loading/loading-resources https://docs.microsoft.com/en-us/dotnet/core/dependency-loading/default-probing#satellite-resource-assembly-probing
The interesting behaviour here being:
Satellite (resource) assembly probing To find a satellite assembly for a specific culture, construct a set of file paths.
For each path in PLATFORM_RESOURCE_ROOTS and then APP_PATHS, append the CultureInfo.Name string, a directory separator, the AssemblyName.Name string, and the extension '.dll'.
If any matching file exists, attempt to load and return it.
To test this, I logged out the relevant probing properties using AppContext.GetData().
Results on lambci/lambda:dotnetcore2.1:
PLATFORM_RESOURCE_ROOTS = ""
APP_PATHS = (null)
Results on real AWS Lambda:
PLATFORM_RESOURCE_ROOTS = "/var/task"
APP_PATHS = (null)
This is consistent with the localization behaviour I've seen and the documentation on the assembly loading algorithm. Since the path is missing from PLATFORM_RESOURCE_ROOTS, dotnet fails to discover the satellite assemblies and as a result localization fails.
Would love a solution to this – would be very happy for a PR that sets this correctly
Would AppDomain.CurrentDomain.SetData("PLATFORM_RESOURCE_ROOTS", "/var/task") do it I wonder?