[mono][wasm] BadImageFormatException "Method has no body" when calling static abstract interface member through generic type parameter
- Dominant language
- C#
- Stars
- 18.3k
- Forks
- 5.6k
- PR merge metrics
- PR metrics pending
Description
## Description
Calling a `static abstract` interface member through a generic type parameter throws `System.BadImageFormatException: Method has no body` in the Mono WASM interpreter. The same code works correctly on CoreCLR.
This appears to be a regression or gap related to #65384, which was fixed for the JIT path but may not cover the WASM interpreter when the static abstract member uses explicit interface implementation.
## Reproduction Steps
1. Create a Blazor WebAssembly (standalone) app targeting `net10.0`
2. Add the following types:
```csharp
public interface IApiClient
{
static abstract string BasePath { get; }
}
public interface IFooClient : IApiClient
{
static string IApiClient.BasePath => "api/foo";
}
public static class GenericCaller
{
public static void PrintBasePath() where T : class, IApiClient
{
var path = T.BasePath; // throws BadImageFormatException
Console.WriteLine($"BasePath resolved to: {path}");
}
}
```
3. Call `GenericCaller.PrintBasePath()` from `Program.cs`
4. Run in the browser
### Minimal repro project
WasmStaticAbstractRepro.csproj
```xml
net10.0
enable
enable
```
Program.cs
```csharp
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using WasmStaticAbstractRepro;
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add("#app");
builder.RootComponents.Add("head::after");
try
{
GenericCaller.PrintBasePath();
Console.WriteLine("SUCCESS: Static abstract dispatch worked.");
}
catch (Exception ex)
{
Console.WriteLine($"FAILED: {ex.GetType().Name}: {ex.Message}");
}
await builder.Build().RunAsync();
public interface IApiClient
{
static abstract string BasePath { get; }
}
public interface IFooClient : IApiClient
{
static string IApiClient.BasePath => "api/foo";
}
public static class GenericCaller
{
public static void PrintBasePath() where T : class, IApiClient
{
var path = T.BasePath;
Console.WriteLine($"BasePath resolved to: {path}");
}
}
```
App.razor, _Imports.razor, wwwroot/index.html
```razor
@* App.razor *@
WASM Static Abstract Repro
Check the browser console (F12) for results.
```
```razor
@* _Imports.razor *@
@using Microsoft.AspNetCore.Components.Web
```
```html
WASM Static Abstract Repro
```
## Expected behavior
`T.BasePath` resolves to the explicit interface implementation and prints `"api/foo"`.
## Actual behavior
```
FAILED: BadImageFormatException: Method has no body
```
Without a try-catch, the error surfaces as `AggregateException_ctor_DefaultMessage (Method has no body)` in the browser console (because `UseSystemResourceKeys` is `true` in the WASM runtime config, making the error message particularly hard to diagnose).
## Workaround
Avoid dispatching the static abstract member through the generic type parameter. Pass the value as a regular parameter instead:
```csharp
public static void PrintBasePath(string basePath) where T : class
{
Console.WriteLine($"BasePath resolved to: {basePath}");
}
PrintBasePath("api/foo");
```
## Configuration
- .NET SDK: 10.0.103
- Runtime: 10.0.3
- Microsoft.NET.Sdk.WebAssembly.Pack: 10.0.3
- OS: macOS (Darwin 25.3.0, arm64)
- Browser: Reproduces in both Safari and Chromium (Edge)
- Blazor WebAssembly standalone (no AOT, no hosted model)
Contributor guide
Assessment
This issue has not been assessed yet.