Skip to content

MVC / Razor Pages: Verify union types work in model binding and responses #66545

@DeagleGross

Description

@DeagleGross

Verify that C# union types work correctly in MVC controllers and Razor Pages for both input (model binding) and output (response serialization), and add test coverage.

Note: MVC and Razor Pages support for unions is lower priority for .NET 11

Expected behavior

Controller action with union parameter:

[ApiController]
[Route("api/orders")]
public class OrdersController : ControllerBase
{
    [HttpPost]
    public IActionResult Create([FromBody] Command command)
    {
        return Ok();
    }
}

Controller action returning union:

[HttpGet("{id}")]
public ApiResult Get(int id)
{
    if (id <= 0) return new ApiResult(new InProgressOrder(...));
    return new ApiResult(new CompletedOrder(...));
}

Razor Page with union model binding:

public class OrderModel : PageModel
{
    [BindProperty]
    public Command Command { get; set; } // union(CreateOrder, UpdateOrder)

    public IActionResult OnPost() { ... }
}

Areas to investigate

  1. Input formatter (SystemTextJsonInputFormatter.cs):

    • Calls JsonSerializer.DeserializeAsync(stream, modelType, options) — should work via STJ's union converter
    • Verify no issues with modelType being a union type
  2. Output formatter (SystemTextJsonOutputFormatter.cs):

    • Serialization should work transparently — STJ unpacks the union and writes the case value
    • Verify the declared return type doesn't cause the serializer to skip union-specific handling
  3. Model validation:

    • If the union case value has [Required] or other validation attributes, does MVC's model validation reach into the union case?
    • Likely needs investigation — validation may only see the union wrapper, not the inner case value
  4. API Explorer (DefaultApiDescriptionProvider):

Metadata

Metadata

Assignees

Labels

area-mvcIncludes: MVC, Actions and Controllers, Localization, CORS, most templatesfeature-request

Type

No type
No fields configured for issues without a type.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions