Fix InvalidCastException in DefaultModelBindingContext#8334
Conversation
BenchmarksBenchmark execution time: 2026-03-23 15:24:39 Comparing candidate commit f312de4 in PR branch Found 12 performance improvements and 7 performance regressions! Performance is the same for 254 metrics, 15 unstable metrics.
|
Execution-Time Benchmarks Report ⏱️Execution-time results for samples comparing This PR (8334) and master.
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Metric | Master (Mean ± 95% CI) | Current (Mean ± 95% CI) | Change | Status |
|---|---|---|---|---|
| .NET Framework 4.8 - Baseline | ||||
| duration | 192.99 ± (193.05 - 193.92) ms | 220.08 ± (219.39 - 220.95) ms | +14.0% | ❌⬆️ |
| .NET Framework 4.8 - Bailout | ||||
| duration | 198.21 ± (198.20 - 199.08) ms | 224.15 ± (224.05 - 225.77) ms | +13.1% | ❌⬆️ |
| .NET Framework 4.8 - CallTarget+Inlining+NGEN | ||||
| duration | 1143.86 ± (1146.37 - 1153.34) ms | 1253.26 ± (1250.85 - 1258.80) ms | +9.6% | ❌⬆️ |
Full Metrics Comparison
FakeDbCommand
| Metric | Master (Mean ± 95% CI) | Current (Mean ± 95% CI) | Change | Status |
|---|---|---|---|---|
| .NET Framework 4.8 - Baseline | ||||
| duration | 69.17 ± (69.07 - 69.36) ms | 68.50 ± (68.51 - 68.76) ms | -1.0% | ✅ |
| .NET Framework 4.8 - Bailout | ||||
| duration | 73.41 ± (73.29 - 73.59) ms | 72.63 ± (72.50 - 72.81) ms | -1.1% | ✅ |
| .NET Framework 4.8 - CallTarget+Inlining+NGEN | ||||
| duration | 1038.40 ± (1048.38 - 1059.66) ms | 1034.74 ± (1041.27 - 1050.93) ms | -0.4% | ✅ |
| .NET Core 3.1 - Baseline | ||||
| process.internal_duration_ms | 21.77 ± (21.74 - 21.80) ms | 21.80 ± (21.78 - 21.83) ms | +0.1% | ✅⬆️ |
| process.time_to_main_ms | 79.33 ± (79.17 - 79.49) ms | 79.47 ± (79.32 - 79.61) ms | +0.2% | ✅⬆️ |
| runtime.dotnet.exceptions.count | 0 ± (0 - 0) | 0 ± (0 - 0) | +0.0% | ✅ |
| runtime.dotnet.mem.committed | 10.90 ± (10.90 - 10.91) MB | 10.91 ± (10.91 - 10.92) MB | +0.1% | ✅⬆️ |
| runtime.dotnet.threads.count | 12 ± (12 - 12) | 12 ± (12 - 12) | +0.0% | ✅ |
| .NET Core 3.1 - Bailout | ||||
| process.internal_duration_ms | 21.72 ± (21.70 - 21.75) ms | 21.74 ± (21.72 - 21.77) ms | +0.1% | ✅⬆️ |
| process.time_to_main_ms | 80.56 ± (80.42 - 80.70) ms | 80.51 ± (80.36 - 80.66) ms | -0.1% | ✅ |
| runtime.dotnet.exceptions.count | 0 ± (0 - 0) | 0 ± (0 - 0) | +0.0% | ✅ |
| runtime.dotnet.mem.committed | 10.95 ± (10.94 - 10.95) MB | 10.94 ± (10.94 - 10.95) MB | -0.0% | ✅ |
| runtime.dotnet.threads.count | 13 ± (13 - 13) | 13 ± (13 - 13) | +0.0% | ✅ |
| .NET Core 3.1 - CallTarget+Inlining+NGEN | ||||
| process.internal_duration_ms | 216.36 ± (215.37 - 217.35) ms | 217.29 ± (216.38 - 218.21) ms | +0.4% | ✅⬆️ |
| process.time_to_main_ms | 467.77 ± (467.30 - 468.24) ms | 469.28 ± (468.77 - 469.80) ms | +0.3% | ✅⬆️ |
| runtime.dotnet.exceptions.count | 0 ± (0 - 0) | 0 ± (0 - 0) | +0.0% | ✅ |
| runtime.dotnet.mem.committed | 47.31 ± (47.29 - 47.34) MB | 47.32 ± (47.30 - 47.34) MB | +0.0% | ✅⬆️ |
| runtime.dotnet.threads.count | 28 ± (28 - 28) | 28 ± (28 - 28) | +0.0% | ✅⬆️ |
| .NET 6 - Baseline | ||||
| process.internal_duration_ms | 20.51 ± (20.49 - 20.54) ms | 20.55 ± (20.52 - 20.58) ms | +0.2% | ✅⬆️ |
| process.time_to_main_ms | 68.70 ± (68.57 - 68.84) ms | 69.02 ± (68.88 - 69.17) ms | +0.5% | ✅⬆️ |
| runtime.dotnet.exceptions.count | 0 ± (0 - 0) | 0 ± (0 - 0) | +0.0% | ✅ |
| runtime.dotnet.mem.committed | 10.61 ± (10.61 - 10.61) MB | 10.63 ± (10.62 - 10.63) MB | +0.1% | ✅⬆️ |
| runtime.dotnet.threads.count | 10 ± (10 - 10) | 10 ± (10 - 10) | +0.0% | ✅ |
| .NET 6 - Bailout | ||||
| process.internal_duration_ms | 20.49 ± (20.47 - 20.51) ms | 20.52 ± (20.48 - 20.56) ms | +0.1% | ✅⬆️ |
| process.time_to_main_ms | 69.55 ± (69.44 - 69.66) ms | 70.07 ± (69.93 - 70.20) ms | +0.7% | ✅⬆️ |
| runtime.dotnet.exceptions.count | 0 ± (0 - 0) | 0 ± (0 - 0) | +0.0% | ✅ |
| runtime.dotnet.mem.committed | 10.67 ± (10.66 - 10.67) MB | 10.74 ± (10.74 - 10.74) MB | +0.7% | ✅⬆️ |
| runtime.dotnet.threads.count | 11 ± (11 - 11) | 11 ± (11 - 11) | +0.0% | ✅ |
| .NET 6 - CallTarget+Inlining+NGEN | ||||
| process.internal_duration_ms | 200.96 ± (198.99 - 202.93) ms | 206.18 ± (204.01 - 208.36) ms | +2.6% | ✅⬆️ |
| process.time_to_main_ms | 468.99 ± (468.33 - 469.65) ms | 471.33 ± (470.68 - 471.98) ms | +0.5% | ✅⬆️ |
| runtime.dotnet.exceptions.count | 0 ± (0 - 0) | 0 ± (0 - 0) | +0.0% | ✅ |
| runtime.dotnet.mem.committed | 48.96 ± (48.89 - 49.02) MB | 49.00 ± (48.94 - 49.06) MB | +0.1% | ✅⬆️ |
| runtime.dotnet.threads.count | 29 ± (29 - 29) | 29 ± (29 - 29) | +0.2% | ✅⬆️ |
| .NET 8 - Baseline | ||||
| process.internal_duration_ms | 18.84 ± (18.81 - 18.88) ms | 18.86 ± (18.83 - 18.90) ms | +0.1% | ✅⬆️ |
| process.time_to_main_ms | 68.13 ± (67.99 - 68.27) ms | 68.58 ± (68.45 - 68.71) ms | +0.7% | ✅⬆️ |
| runtime.dotnet.exceptions.count | 0 ± (0 - 0) | 0 ± (0 - 0) | +0.0% | ✅ |
| runtime.dotnet.mem.committed | 7.67 ± (7.66 - 7.67) MB | 7.69 ± (7.68 - 7.69) MB | +0.3% | ✅⬆️ |
| runtime.dotnet.threads.count | 10 ± (10 - 10) | 10 ± (10 - 10) | +0.0% | ✅ |
| .NET 8 - Bailout | ||||
| process.internal_duration_ms | 18.79 ± (18.76 - 18.82) ms | 18.81 ± (18.78 - 18.83) ms | +0.1% | ✅⬆️ |
| process.time_to_main_ms | 69.30 ± (69.18 - 69.43) ms | 69.53 ± (69.41 - 69.66) ms | +0.3% | ✅⬆️ |
| runtime.dotnet.exceptions.count | 0 ± (0 - 0) | 0 ± (0 - 0) | +0.0% | ✅ |
| runtime.dotnet.mem.committed | 7.73 ± (7.73 - 7.74) MB | 7.75 ± (7.74 - 7.76) MB | +0.2% | ✅⬆️ |
| runtime.dotnet.threads.count | 11 ± (11 - 11) | 11 ± (11 - 11) | +0.0% | ✅ |
| .NET 8 - CallTarget+Inlining+NGEN | ||||
| process.internal_duration_ms | 157.58 ± (156.62 - 158.53) ms | 156.00 ± (155.09 - 156.90) ms | -1.0% | ✅ |
| process.time_to_main_ms | 448.33 ± (447.81 - 448.84) ms | 448.10 ± (447.56 - 448.64) ms | -0.1% | ✅ |
| runtime.dotnet.exceptions.count | 0 ± (0 - 0) | 0 ± (0 - 0) | +0.0% | ✅ |
| runtime.dotnet.mem.committed | 36.54 ± (36.52 - 36.56) MB | 36.55 ± (36.53 - 36.57) MB | +0.0% | ✅⬆️ |
| runtime.dotnet.threads.count | 28 ± (28 - 28) | 28 ± (28 - 28) | +0.0% | ✅⬆️ |
HttpMessageHandler
| Metric | Master (Mean ± 95% CI) | Current (Mean ± 95% CI) | Change | Status |
|---|---|---|---|---|
| .NET Framework 4.8 - Baseline | ||||
| duration | 192.99 ± (193.05 - 193.92) ms | 220.08 ± (219.39 - 220.95) ms | +14.0% | ❌⬆️ |
| .NET Framework 4.8 - Bailout | ||||
| duration | 198.21 ± (198.20 - 199.08) ms | 224.15 ± (224.05 - 225.77) ms | +13.1% | ❌⬆️ |
| .NET Framework 4.8 - CallTarget+Inlining+NGEN | ||||
| duration | 1143.86 ± (1146.37 - 1153.34) ms | 1253.26 ± (1250.85 - 1258.80) ms | +9.6% | ❌⬆️ |
| .NET Core 3.1 - Baseline | ||||
| process.internal_duration_ms | 187.52 ± (187.18 - 187.86) ms | 220.50 ± (219.45 - 221.55) ms | +17.6% | ✅⬆️ |
| process.time_to_main_ms | 80.41 ± (80.21 - 80.61) ms | 92.88 ± (92.53 - 93.22) ms | +15.5% | ✅⬆️ |
| runtime.dotnet.exceptions.count | 3 ± (3 - 3) | 3 ± (3 - 3) | +0.0% | ✅ |
| runtime.dotnet.mem.committed | 16.15 ± (16.12 - 16.17) MB | 15.80 ± (15.78 - 15.81) MB | -2.2% | ✅ |
| runtime.dotnet.threads.count | 20 ± (20 - 20) | 20 ± (20 - 20) | +1.9% | ✅⬆️ |
| .NET Core 3.1 - Bailout | ||||
| process.internal_duration_ms | 186.79 ± (186.49 - 187.08) ms | 217.87 ± (217.06 - 218.68) ms | +16.6% | ✅⬆️ |
| process.time_to_main_ms | 81.74 ± (81.61 - 81.87) ms | 93.87 ± (93.60 - 94.14) ms | +14.8% | ✅⬆️ |
| runtime.dotnet.exceptions.count | 3 ± (3 - 3) | 3 ± (3 - 3) | +0.0% | ✅ |
| runtime.dotnet.mem.committed | 16.21 ± (16.18 - 16.25) MB | 15.88 ± (15.86 - 15.90) MB | -2.0% | ✅ |
| runtime.dotnet.threads.count | 21 ± (20 - 21) | 21 ± (21 - 21) | +2.0% | ✅⬆️ |
| .NET Core 3.1 - CallTarget+Inlining+NGEN | ||||
| process.internal_duration_ms | 396.34 ± (394.50 - 398.18) ms | 427.53 ± (425.54 - 429.52) ms | +7.9% | ✅⬆️ |
| process.time_to_main_ms | 472.64 ± (472.13 - 473.15) ms | 528.06 ± (526.72 - 529.40) ms | +11.7% | ✅⬆️ |
| runtime.dotnet.exceptions.count | 3 ± (3 - 3) | 3 ± (3 - 3) | +0.0% | ✅ |
| runtime.dotnet.mem.committed | 57.66 ± (57.50 - 57.82) MB | 58.26 ± (58.22 - 58.29) MB | +1.0% | ✅⬆️ |
| runtime.dotnet.threads.count | 30 ± (30 - 30) | 30 ± (30 - 30) | +0.4% | ✅⬆️ |
| .NET 6 - Baseline | ||||
| process.internal_duration_ms | 192.44 ± (192.01 - 192.87) ms | 221.08 ± (220.37 - 221.79) ms | +14.9% | ✅⬆️ |
| process.time_to_main_ms | 69.96 ± (69.78 - 70.14) ms | 80.07 ± (79.83 - 80.31) ms | +14.4% | ✅⬆️ |
| runtime.dotnet.exceptions.count | 4 ± (4 - 4) | 4 ± (4 - 4) | +0.0% | ✅ |
| runtime.dotnet.mem.committed | 16.05 ± (15.92 - 16.19) MB | 16.15 ± (16.13 - 16.16) MB | +0.6% | ✅⬆️ |
| runtime.dotnet.threads.count | 19 ± (19 - 19) | 20 ± (20 - 20) | +4.2% | ✅⬆️ |
| .NET 6 - Bailout | ||||
| process.internal_duration_ms | 192.22 ± (191.76 - 192.68) ms | 223.48 ± (222.54 - 224.42) ms | +16.3% | ✅⬆️ |
| process.time_to_main_ms | 71.09 ± (70.93 - 71.25) ms | 81.66 ± (81.41 - 81.91) ms | +14.9% | ✅⬆️ |
| runtime.dotnet.exceptions.count | 4 ± (4 - 4) | 4 ± (4 - 4) | +0.0% | ✅ |
| runtime.dotnet.mem.committed | 16.05 ± (15.90 - 16.21) MB | 16.15 ± (16.13 - 16.17) MB | +0.6% | ✅⬆️ |
| runtime.dotnet.threads.count | 19 ± (19 - 19) | 20 ± (20 - 21) | +6.5% | ✅⬆️ |
| .NET 6 - CallTarget+Inlining+NGEN | ||||
| process.internal_duration_ms | 428.77 ± (427.15 - 430.40) ms | 498.67 ± (491.85 - 505.49) ms | +16.3% | ✅⬆️ |
| process.time_to_main_ms | 473.98 ± (473.15 - 474.81) ms | 526.41 ± (525.04 - 527.77) ms | +11.1% | ✅⬆️ |
| runtime.dotnet.exceptions.count | 4 ± (4 - 4) | 4 ± (4 - 4) | +0.0% | ✅ |
| runtime.dotnet.mem.committed | 60.25 ± (60.16 - 60.35) MB | 58.95 ± (58.86 - 59.04) MB | -2.2% | ✅ |
| runtime.dotnet.threads.count | 30 ± (30 - 30) | 31 ± (31 - 31) | +1.6% | ✅⬆️ |
| .NET 8 - Baseline | ||||
| process.internal_duration_ms | 190.28 ± (189.90 - 190.67) ms | 226.46 ± (225.17 - 227.75) ms | +19.0% | ✅⬆️ |
| process.time_to_main_ms | 69.48 ± (69.29 - 69.66) ms | 79.41 ± (79.16 - 79.67) ms | +14.3% | ✅⬆️ |
| runtime.dotnet.exceptions.count | 4 ± (4 - 4) | 4 ± (4 - 4) | +0.0% | ✅ |
| runtime.dotnet.mem.committed | 11.77 ± (11.74 - 11.80) MB | 11.41 ± (11.39 - 11.43) MB | -3.0% | ✅ |
| runtime.dotnet.threads.count | 18 ± (18 - 18) | 19 ± (19 - 19) | +4.5% | ✅⬆️ |
| .NET 8 - Bailout | ||||
| process.internal_duration_ms | 189.20 ± (188.89 - 189.50) ms | 221.34 ± (220.35 - 222.34) ms | +17.0% | ✅⬆️ |
| process.time_to_main_ms | 70.42 ± (70.30 - 70.54) ms | 80.28 ± (80.04 - 80.52) ms | +14.0% | ✅⬆️ |
| runtime.dotnet.exceptions.count | 4 ± (4 - 4) | 4 ± (4 - 4) | +0.0% | ✅ |
| runtime.dotnet.mem.committed | 11.76 ± (11.69 - 11.83) MB | 11.51 ± (11.50 - 11.53) MB | -2.1% | ✅ |
| runtime.dotnet.threads.count | 19 ± (18 - 19) | 20 ± (20 - 20) | +7.1% | ✅⬆️ |
| .NET 8 - CallTarget+Inlining+NGEN | ||||
| process.internal_duration_ms | 352.63 ± (351.38 - 353.88) ms | 466.60 ± (460.44 - 472.76) ms | +32.3% | ✅⬆️ |
| process.time_to_main_ms | 451.07 ± (450.50 - 451.63) ms | 496.46 ± (495.61 - 497.31) ms | +10.1% | ✅⬆️ |
| runtime.dotnet.exceptions.count | 4 ± (4 - 4) | 4 ± (4 - 4) | +0.0% | ✅ |
| runtime.dotnet.mem.committed | 48.54 ± (48.51 - 48.57) MB | 50.21 ± (50.11 - 50.31) MB | +3.4% | ✅⬆️ |
| runtime.dotnet.threads.count | 30 ± (30 - 30) | 30 ± (30 - 30) | +0.3% | ✅⬆️ |
Comparison explanation
Execution-time benchmarks measure the whole time it takes to execute a program, and are intended to measure the one-off costs. Cases where the execution time results for the PR are worse than latest master results are highlighted in **red**. The following thresholds were used for comparing the execution times:
- Welch test with statistical test for significance of 5%
- Only results indicating a difference greater than 5% and 5 ms are considered.
Note that these results are based on a single point-in-time result for each branch. For full results, see the dashboard.
Graphs show the p99 interval based on the mean and StdDev of the test run, as well as the mean value of the run (shown as a diamond below the graph).
Duration charts
FakeDbCommand (.NET Framework 4.8)
gantt
title Execution time (ms) FakeDbCommand (.NET Framework 4.8)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8334) - mean (69ms) : 67, 70
master - mean (69ms) : 67, 71
section Bailout
This PR (8334) - mean (73ms) : 71, 74
master - mean (73ms) : 72, 75
section CallTarget+Inlining+NGEN
This PR (8334) - mean (1,046ms) : 978, 1115
master - mean (1,054ms) : 968, 1140
FakeDbCommand (.NET Core 3.1)
gantt
title Execution time (ms) FakeDbCommand (.NET Core 3.1)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8334) - mean (107ms) : 104, 110
master - mean (107ms) : 103, 110
section Bailout
This PR (8334) - mean (108ms) : 106, 110
master - mean (108ms) : 106, 110
section CallTarget+Inlining+NGEN
This PR (8334) - mean (723ms) : 701, 746
master - mean (722ms) : 699, 744
FakeDbCommand (.NET 6)
gantt
title Execution time (ms) FakeDbCommand (.NET 6)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8334) - mean (95ms) : 92, 97
master - mean (94ms) : 91, 98
section Bailout
This PR (8334) - mean (96ms) : 94, 98
master - mean (95ms) : 93, 97
section CallTarget+Inlining+NGEN
This PR (8334) - mean (706ms) : 662, 750
master - mean (699ms) : 648, 749
FakeDbCommand (.NET 8)
gantt
title Execution time (ms) FakeDbCommand (.NET 8)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8334) - mean (94ms) : 92, 97
master - mean (94ms) : 91, 96
section Bailout
This PR (8334) - mean (95ms) : 93, 97
master - mean (95ms) : 93, 97
section CallTarget+Inlining+NGEN
This PR (8334) - mean (633ms) : 610, 656
master - mean (637ms) : 615, 658
HttpMessageHandler (.NET Framework 4.8)
gantt
title Execution time (ms) HttpMessageHandler (.NET Framework 4.8)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8334) - mean (220ms) : 209, 231
master - mean (193ms) : 189, 198
section Bailout
This PR (8334) - mean (225ms) : crit, 212, 237
master - mean (199ms) : 193, 204
section CallTarget+Inlining+NGEN
This PR (8334) - mean (1,255ms) : crit, 1196, 1314
master - mean (1,150ms) : 1100, 1200
HttpMessageHandler (.NET Core 3.1)
gantt
title Execution time (ms) HttpMessageHandler (.NET Core 3.1)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8334) - mean (324ms) : 305, 343
master - mean (276ms) : 272, 281
section Bailout
This PR (8334) - mean (322ms) : crit, 303, 342
master - mean (277ms) : 273, 281
section CallTarget+Inlining+NGEN
This PR (8334) - mean (997ms) : crit, 953, 1041
master - mean (900ms) : 865, 936
HttpMessageHandler (.NET 6)
gantt
title Execution time (ms) HttpMessageHandler (.NET 6)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8334) - mean (311ms) : 298, 323
master - mean (271ms) : 264, 277
section Bailout
This PR (8334) - mean (315ms) : crit, 294, 336
master - mean (272ms) : 266, 277
section CallTarget+Inlining+NGEN
This PR (8334) - mean (1,071ms) : crit, 950, 1191
master - mean (936ms) : 912, 960
HttpMessageHandler (.NET 8)
gantt
title Execution time (ms) HttpMessageHandler (.NET 8)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8334) - mean (318ms) : 293, 342
master - mean (269ms) : 264, 275
section Bailout
This PR (8334) - mean (313ms) : crit, 296, 330
master - mean (269ms) : 265, 273
section CallTarget+Inlining+NGEN
This PR (8334) - mean (999ms) : crit, 908, 1090
master - mean (835ms) : 804, 866
andrewlock
left a comment
There was a problem hiding this comment.
LGTM in general, thanks, though I think it creates a gap we should try to close best as we can
| } | ||
| } | ||
| else | ||
| else if (defaultModelBindingContext.ValueProvider is IList valueProviderList) |
There was a problem hiding this comment.
The only trouble here is that this adds a third branch, where we have a ValueProvider that is not an IList (which could be common), so I think in that case, we still need to run the body of this loop 🤔
In other words:
- Keep this loop
- Add another
else, e.g.else if (defaultModelBindingContext.ValueProvider.TryDuckCast(out BindingSourceValueProvider prov))etc - Refactor to reduce the duplication 😄
There was a problem hiding this comment.
Good catch! I have added this case and refactored the code. Thanks!
Summary of changes
Fix
InvalidCastExceptioninDefaultModelBindingContext_SetResult_Integration.OnMethodEndby changing theValueProviderfield in theDefaultModelBindingContextDuckCopy struct fromIListtoobject, and safe-casting toIListat the usage site.Reason for change
Customers using custom
IModelBinderimplementations that setbindingContext.ValueProviderto a non-CompositeValueProvider(i.e., anIValueProviderthat does not implementIList) trigger anInvalidCastExceptionduring DuckCopy:In standard MVC usage,
ValueProvideris always aCompositeValueProvider(which inherits fromCollection<IValueProvider>and implementsIList), so the DuckCopyCastclassIL instruction succeeds. However, when a custom model binder assigns a plainIValueProviderthat does not implementIList, the cast fails. Additionally,TryDuckCastdoes not wrapCreateInstancein a try/catch, so the exception propagates uncaught.Implementation details
Test coverage
Other details