Mvc: Model binding on circular referenced model, cpu usage 100% and memory usage grow until die

Created on 20 Sep 2016  路  3Comments  路  Source: aspnet/Mvc

Title

_A short description of the bug that becomes the issue title_

Model binding on circular referenced model, cpu usage 100% and memory usage grow until die

Functional impact

_Does the bug result in any actual functional issue, if so, what?_

The program dies when I am using dotnet core for aspnet web application on machine with configuration as follows:

os: OS X El Capitan 10.11.6
dotnet core: .NET Command Line Tools (1.0.0-preview2-003121)

My project.json dependencies contain:

{
  ...
  "dependencies": {
    ...
    "Microsoft.AspNetCore.Mvc": "1.0.0-rc2-final",
    ...
  },
  ...
}

I have circular referenced model as follows:

public class Foo 
{
  public List<Bar> Bars { get; set; }
  public string Baz { get; set; }
}

public class Bar 
{
  public Foo Foo { get; set; }
}

my controller is

public class FooController 
{
  [HttpPost("Create")]
  [ValidateAntiForgeryToken]
  public async Task<IActionResult> Create(Foo model)
  {
    ...
  }
}

when I request with POST data

Baz=something

The program will stuck after controller constructor call. Apparently Create method invocation never happened.

I read in https://docs.asp.net/en/latest/mvc/models/model-binding.html

... It uses _reflection and recursion_ to traverse the properties of complex types looking for matches. Model binding looks for the pattern parameter_name.property_name to bind values to properties. ...

Here come our problems:

  • I dont think that traversing into property that I dont specified from request is necessary.
  • Even though it is necessary and must to do, I think the problem is on reflecting Foo and Bar and Foo and Bar so on repeatedly. IMHO, is not necessary.

I know I can use [BindNever] annotation to avoid the property never been binded.

public class Foo 
{
  [BindNever]
  public List<Bar> Bars { get; set; }
  public string Baz { get; set; }
}

But it will leave me unable to bind that property.

Do you think this issue can be resolved with slight changes on model binding mechanism for next release?

Thank you.

Minimal repro steps

_What is the smallest, simplest set of steps to reproduce the issue. If needed, provide a project that demonstrates the issue._

  1. Add two classes that have recursive reference between them.
  2. Add controller with POST action that use one of model class.
  3. Request POST to the action.
  4. Open resources information management tool (htop) and see resources usage
  5. Wait for the program to die

Expected result

_What would you expect to happen if there wasn't a bug_

The request works as usual

Actual result

_What is actually happening_

The program hang, CPU usage 100% and memory usage grows until die.

Further technical details

_Optional, details of the root cause if known_

This docs

... It uses reflection and recursion to traverse the properties of complex types looking for matches. Model binding looks for the pattern parameter_name.property_name to bind values to properties. ...

Most helpful comment

Thanks, @pranavkm. It's working now. :)

I couldn't manage to update just single Microsoft.AspNetCore.Mvc latest version (1.0.1) individually. So I did update whole dependencies to 1.0.0. And it is working now.

What I have done:

  • Update project.json
  • Run dotnet restore

My project.json is

{
  "dependencies": {
    "Microsoft.NETCore.App": {
      "version": "1.0.0",
      "type": "platform"
    },
    "Microsoft.AspNetCore.Authentication.Cookies": "1.0.0",
    "Microsoft.AspNetCore.Session": "1.0.0",
    "Microsoft.AspNetCore.Diagnostics": "1.0.0",
    "Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore": "1.0.0",
    "Microsoft.AspNetCore.Identity.EntityFrameworkCore": "1.0.0",
    "Microsoft.AspNetCore.Mvc": "1.0.1",
    "Microsoft.AspNetCore.Razor.Tools": {
      "version": "1.0.0-preview1-final",
      "type": "build"
    },
    "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
    "Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
    "Microsoft.AspNetCore.StaticFiles": "1.0.0",
    "Microsoft.EntityFrameworkCore.Sqlite": "1.0.0",
    "Microsoft.EntityFrameworkCore.Tools": {
      "version": "1.0.0-preview1-final",
      "type": "build"
    },
    "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",
    "Microsoft.Extensions.Configuration.Json": "1.0.0",
    "Microsoft.Extensions.Configuration.UserSecrets": "1.0.0",
    "Microsoft.Extensions.Logging": "1.0.0",
    "Microsoft.Extensions.Logging.Console": "1.0.0",
    "Microsoft.Extensions.Logging.Debug": "1.0.0",
    "Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0",
    "Microsoft.VisualStudio.Web.CodeGeneration.Tools": {
      "version": "1.0.0-preview2-final",
      "type": "build"
    },
    "Microsoft.VisualStudio.Web.CodeGenerators.Mvc": {
      "version": "1.0.0-preview1-final",
      "type": "build"
    },
    "MailKit" : {
      "version": "1.4.0"
    },
    "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0"

  },

  "tools": {
    "BundlerMinifier.Core": "2.0.238",
    "Microsoft.DotNet.Watcher.Tools": "1.0.0-preview2-final",
    "Microsoft.AspNetCore.Razor.Tools": "1.0.0-preview2-final",
    "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview1-final",
    "Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview1-final",
    "Microsoft.Extensions.SecretManager.Tools": "1.0.0-preview1-final",
    "Microsoft.VisualStudio.Web.CodeGeneration.Tools": {
      "version": "1.0.0-preview2-final",
      "imports": [
        "portable-net45+win8+dnxcore50",
        "portable-net45+win8"
      ]
    }

  },
...
}

All 3 comments

@reekoheek could you update to the RTM builds of Microsoft.AspNetCore.Mvc? The RC2 build which you're referencing had an issue that was fixed - https://github.com/aspnet/Mvc/issues/4666, you might be hitting it.

Thanks, @pranavkm. It's working now. :)

I couldn't manage to update just single Microsoft.AspNetCore.Mvc latest version (1.0.1) individually. So I did update whole dependencies to 1.0.0. And it is working now.

What I have done:

  • Update project.json
  • Run dotnet restore

My project.json is

{
  "dependencies": {
    "Microsoft.NETCore.App": {
      "version": "1.0.0",
      "type": "platform"
    },
    "Microsoft.AspNetCore.Authentication.Cookies": "1.0.0",
    "Microsoft.AspNetCore.Session": "1.0.0",
    "Microsoft.AspNetCore.Diagnostics": "1.0.0",
    "Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore": "1.0.0",
    "Microsoft.AspNetCore.Identity.EntityFrameworkCore": "1.0.0",
    "Microsoft.AspNetCore.Mvc": "1.0.1",
    "Microsoft.AspNetCore.Razor.Tools": {
      "version": "1.0.0-preview1-final",
      "type": "build"
    },
    "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
    "Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
    "Microsoft.AspNetCore.StaticFiles": "1.0.0",
    "Microsoft.EntityFrameworkCore.Sqlite": "1.0.0",
    "Microsoft.EntityFrameworkCore.Tools": {
      "version": "1.0.0-preview1-final",
      "type": "build"
    },
    "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",
    "Microsoft.Extensions.Configuration.Json": "1.0.0",
    "Microsoft.Extensions.Configuration.UserSecrets": "1.0.0",
    "Microsoft.Extensions.Logging": "1.0.0",
    "Microsoft.Extensions.Logging.Console": "1.0.0",
    "Microsoft.Extensions.Logging.Debug": "1.0.0",
    "Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0",
    "Microsoft.VisualStudio.Web.CodeGeneration.Tools": {
      "version": "1.0.0-preview2-final",
      "type": "build"
    },
    "Microsoft.VisualStudio.Web.CodeGenerators.Mvc": {
      "version": "1.0.0-preview1-final",
      "type": "build"
    },
    "MailKit" : {
      "version": "1.4.0"
    },
    "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0"

  },

  "tools": {
    "BundlerMinifier.Core": "2.0.238",
    "Microsoft.DotNet.Watcher.Tools": "1.0.0-preview2-final",
    "Microsoft.AspNetCore.Razor.Tools": "1.0.0-preview2-final",
    "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview1-final",
    "Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview1-final",
    "Microsoft.Extensions.SecretManager.Tools": "1.0.0-preview1-final",
    "Microsoft.VisualStudio.Web.CodeGeneration.Tools": {
      "version": "1.0.0-preview2-final",
      "imports": [
        "portable-net45+win8+dnxcore50",
        "portable-net45+win8"
      ]
    }

  },
...
}

All the tool packages such as Microsoft.EntityFrameworkCore.Tools have a 1.0.0-preview2-final version available. I'd recommend updating to this version to avoid similar tooling \ design time issues. You should be able to find and replace 1.0.0-preview1-final with 1.0.0-preview2-final in your project.

Was this page helpful?
0 / 5 - 0 ratings