I found the solution above to not work with preflight OPTIONS requests, since then only the CORS policy is evaluated, resulting in it trying to evaluate an unassigned variable.
I solved it by creating (in this example 2) Named Values, containing a comma-separated list of URLs. The Named Values are available at the time of policy evaluation and will therefore work. The reasoning behind multiple lists is that named values have a size limitation of 4096 characters (my source here is the error message in Azure portal when putting in a too-big value), which isn't very many URLs. I have opted to use CSV instead of a JSON array as the data structure in the Named Values due to the overhead that is added when dealing with JSON. I ran some benchmarks locally and the concatenation of CSV lists where approx 3 times faster with lower memory allocation and GC.
<cors>
<allowed-origins>
<origin>@{
string[] stringArray = new string[] { {{corslistcsv0}}, {{corslistcsv1}} };
string origin = context.Request.Headers.GetValueOrDefault("Origin", "");
int urlIndex = -1;
urlIndex = Array.IndexOf(stringArray, origin);
return urlIndex == -1 ? "https://urlthaticontrol.org" : origin;
}</origin>
</allowed-origins>
</cors>
Here is an example list in a Named Value:
"https://url1.com","http://url2.net","http://url3.org"