I have an ASP.NET Razor Pages project with a partial view that uses a tuple type for its model. One of the tuple elements uses an interface as its type. When the partial view is called using an object whose type is the interface, it works. But when it's called using a class that implements the interface, it throws an exception.
I've create a simplified repo that reproduces this error.
The project defines an interface with a class implementation:
public interface ISampleInterface
{
int Value { get; }
}
public class ImplementationClass : ISampleInterface
{
public int Value => 5;
}
In the Page, I can create objects whose type is either the interface or the class implementing the interface:
public class IndexModel : PageModel
{
// type is the interface
public ISampleInterface InterfaceInstance { get; } = new ImplementationClass();
// type is an implementation of the interface
public ImplementationClass ClassInstance { get; } = new ImplementationClass();
public void OnGet() { }
}
Then there's a partial view that uses a tuple including the interface as its model:
@model (ISampleInterface Sample, int Number)
<p>Sample value: @Model.Sample.Value </p>
<p>Unrelated number: @Model.Number </p>
But when referencing the partial view, the interface-typed object can be used, while the class-typed object throws an exception:
<!-- This works: -->
<partial name="_SampleTuplePartial" model="(Model.InterfaceInstance, 1)" />
<!-- This throws an exception: -->
<partial name="_SampleTuplePartial" model="(Model.ClassInstance, 1)" />
The first partial tag renders as expected, but the second partial tag throws this exception:
InvalidOperationException: The model item passed into the ViewDataDictionary is of type 'System.ValueTuple2[ImplementationClass,System.Int32]', but this ViewDataDictionary instance requires a model item of type 'System.ValueTuple2[ISampleInterface,System.Int32]'.
Both objects implement the interface, so why does the second one throw an exception?
This only happens when the model is a tuple. A partial view with just the interface as the model can be used with either type of object:
@model ISampleInterface
<p>Sample value: @Model.Value</p>
<partial name="_SampleInterfacePartial" model="Model.InterfaceInstance" />
<partial name="_SampleInterfacePartial" model="Model.ClassInstance" />