Skip to content

MVC model validation in default configuration is very slow if models contain delegate properties #36919

@imb590

Description

@imb590

If a MVC model contains a delegate-typed field, then by default Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ObjectModelValidator tries to validate every field of the delegate, eventually retrieving all assembly types and going on to validate properties of those Type objects.

The following code demonstrates the problem:

using System;
using System.Net.Http;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

using var host = new WebHostBuilder()
    .UseKestrel()
    .UseUrls("http://localhost:5000")
    .ConfigureServices(s =>
    {
        s.AddLogging(l => l.AddConsole().AddSimpleConsole(c =>
        {
            c.TimestampFormat = "hh:mm:ss.fff ";
            c.SingleLine = true;
        }).SetMinimumLevel(LogLevel.Trace));
        s.AddMvc().AddControllersAsServices();
    })
    .UseStartup<Startup>()
    .Build();

await host.StartAsync();

using var client = new HttpClient();
var response = await client.GetStringAsync("http://localhost:5000?value=test");
Console.WriteLine($"Got response: {response}");
response = await client.GetStringAsync("http://localhost:5000?value=test");
Console.WriteLine($"Got response: {response}");

class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        app.UseRouting();
        app.UseEndpoints(routes =>
        {
            routes.MapControllers();
        });
    }
}

public class TestController : Controller
{
    [HttpGet("/")]
    public string Test([FromQuery]ModelWithDelegateType model)
    {
        return model.Value;
    }
}

public class ModelWithDelegateType
{
    public string Value { get; set; } = string.Empty;

    public Action Delegate { get; } = () => { };
}

The request is quite slow even for this small assembly (about 100ms on my machine), most of which is spent in Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationVisitor, as seen in the 100ms time gap in logs:

04:35:14.835 dbug: Microsoft.AspNetCore.Mvc.ModelBinding.ParameterBinder[26] Attempting to validate the bound parameter 'model' of type 'ModelWithDelegateType' ...
04:35:14.938 dbug: Microsoft.AspNetCore.Mvc.ModelBinding.ParameterBinder[27] Done attempting to validate the bound parameter 'model' of type 'ModelWithDelegateType'.

When assembly is larger, the validation takes more than a second.

This is on ASP.NET Core with SDK 5.0.205 and runtime 5.0.8.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions