I have a simple JavaScript helper:
window.debugOut = (content) => {
console.dir(content);
}
On the Blazor side I have this type:
public class City
{
public string CityName { get; set; }
public int Population { get; set; }
}
If I call the JavaScript debugOut and pass a List<City>, this arrives correctly on the browser side:
await Js.InvokeAsync<bool>("debugOut", new List<City> {
new City{CityName="London",Population=8000000 },
new City{CityName="Edinburgh", Population=400000 }
});

But if I use an array type instead, the browser only sees the first object:
await Js.InvokeAsync<bool>("debugOut", new City[] {
new City{CityName="London",Population=8000000 },
new City{CityName="Edinburgh", Population=400000 }
});

Serialization works correctly with an array of simple values. The problem seems to occur only with arrays of objects.
await Js.InvokeAsync<bool>("debugOut", new int[] { 1, 2, 3 });

This is because InvokeAsync accepts params object[] args, and since you're passing an array, the compiler treats it as if you want each array entry to be a separate top-level entry in args. What you want instead is for args to be an array containing only one top-level entry, which itself is your array.
This is the nature of params in C# in general. For more info, see https://stackoverflow.com/questions/36350/how-to-pass-a-single-object-to-a-params-object
To override what the compiler does here, consider casting to object, e.g.:
await Js.InvokeAsync<bool>("debugOut", (object) new City[] {
new City{CityName="London",Population=8000000 },
new City{CityName="Edinburgh", Population=400000 }
});
This will have no runtime cost and will give the parameter filling behavior you want.
Nice one, I didn't think of that. I guess I don't work with arrays much in real life :)
Most helpful comment
This is because
InvokeAsyncacceptsparams object[] args, and since you're passing an array, the compiler treats it as if you want each array entry to be a separate top-level entry inargs. What you want instead is forargsto be an array containing only one top-level entry, which itself is your array.This is the nature of
paramsin C# in general. For more info, see https://stackoverflow.com/questions/36350/how-to-pass-a-single-object-to-a-params-objectTo override what the compiler does here, consider casting to
object, e.g.:This will have no runtime cost and will give the parameter filling behavior you want.