Skip to content

GenerateCheckBox throws an exception if the URL parameter cannot be parsed to a boolean #64739

@waiwaing

Description

@waiwaing

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

If DefaultHtmlGenerator.GenerateCheckBox is called, and isChecked is null, then ASP.NET Core will try to take the value from the ModelState, parse it as a boolean, and use that to populate the checkbox's value. However, if the value in the ModelState cannot be parsed as a boolean, then ASP.NET Core throws a FormatException.

Expected Behavior

It is surprising that this can cause a FormatException to be thrown, since invalid user input is expected to be discarded when the model is initially bound. I would expect that if the input cannot be parsed, the checkbox is not set. If this is expected behaviour, guidance from the .NET team as to how a developer should handle this would be welcome.

Steps To Reproduce

Repo: https://github.com/waiwaing/aspnet-checkbox-exception

  1. Open http://localhost:5105/Example/Edit?MyBool=false - note page renders correctly
  2. Open http://localhost:5105/Example/Edit?MyBool=falsse - note exception is thrown

Exceptions (if any)

 System.FormatException: falsse is not a valid value for Boolean.
       ---> System.FormatException: String 'falsse' was not recognized as a valid Boolean.
         at System.Boolean.Parse(ReadOnlySpan`1 value)
         at System.Boolean.Parse(String value)
         at System.ComponentModel.BooleanConverter.ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, Object value)
         --- End of inner exception stack trace ---
         at System.ComponentModel.BooleanConverter.ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, Object value)
         at Microsoft.AspNetCore.Mvc.ModelBinding.ModelBindingHelper.ConvertSimpleType(Object value, Type destinationType, CultureInfo culture)
         at Microsoft.AspNetCore.Mvc.ModelBinding.ModelBindingHelper.UnwrapPossibleArrayType(Object value, Type destinationType, CultureInfo culture)
         at Microsoft.AspNetCore.Mvc.ModelBinding.ModelBindingHelper.ConvertTo(Object value, Type type, CultureInfo culture)
         at Microsoft.AspNetCore.Mvc.ViewFeatures.DefaultHtmlGenerator.GetModelStateValue(ViewContext viewContext, String key, Type destinationType)
         at Microsoft.AspNetCore.Mvc.ViewFeatures.DefaultHtmlGenerator.GenerateInput(ViewContext viewContext, InputType inputType, ModelExplorer modelExplorer, String expression, Object value, Boolean useViewData, Boolean isChecked, Boolean setId, Boolean isExplicitValue, String format, IDictionary`2 htmlAttributes)
         at Microsoft.AspNetCore.Mvc.ViewFeatures.DefaultHtmlGenerator.GenerateCheckBox(ViewContext viewContext, ModelExplorer modelExplorer, String expression, Nullable`1 isChecked, Object htmlAttributes)
         at Microsoft.AspNetCore.Mvc.ViewFeatures.HtmlHelper.GenerateCheckBox(ModelExplorer modelExplorer, String expression, Nullable`1 isChecked, Object htmlAttributes)
         at Microsoft.AspNetCore.Mvc.ViewFeatures.HtmlHelper`1.CheckBoxFor(Expression`1 expression, Object htmlAttributes)
         at Microsoft.AspNetCore.Mvc.Rendering.HtmlHelperInputExtensions.CheckBoxFor[TModel](IHtmlHelper`1 htmlHelper, Expression`1 expression)
         at AspNetCoreGeneratedDocument.Views_Example_Edit.ExecuteAsync()
         at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageCoreAsync(IRazorPage page, ViewContext context)
         at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageAsync(IRazorPage page, ViewContext context, Boolean invokeViewStarts)
         at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderAsync(ViewContext context)
         at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, String contentType, Nullable`1 statusCode)
         at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, String contentType, Nullable`1 statusCode)
         at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ActionContext actionContext, IView view, ViewDataDictionary viewData, ITempDataDictionary tempData, String contentType, Nullable`1 statusCode)
         at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor.ExecuteAsync(ActionContext context, ViewResult result)
         at Microsoft.AspNetCore.Mvc.ViewResult.ExecuteResultAsync(ActionContext context)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeResultAsync>g__Logged|22_0(ResourceInvoker invoker, IActionResult result)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResultFilterAsync>g__Awaited|30_0[TFilter,TFilterAsync](ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters()
      --- End of stack trace from previous location ---
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
      --- End of stack trace from previous location ---
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
         at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
         at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
         at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)

.NET Version

10.0.100

Anything else?

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

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

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions