I’m working on an ASP.NET Core MVC application based on .NET 6 framework. I want to retrieve a value from my form that matches the property of a class member of my view model.
My abstract model for all my specific database entities :
public abstract class MyAbstractDatabaseEntity
{
[Column(TypeName = "bit"), Required, MaxLength(1), Unicode(false)]
public bool SafeDelete { get; set; } = false;
[Column(TypeName = "datetime")]
public DateTime CreationDate { get; set; }
[Required, MaxLength(12), Unicode(false)]
public string CreationUserID { get; set; }
[Column(TypeName = "datetime")]
public DateTime UpdateDate { get; set; }
[Required, MaxLength(12), Unicode(false)]
public string UpdateUserID { get; set; }
}
One of my specific database entities :
[Table("MyDatabaseTable")]
public class MyEntity : MyAbstractDatabaseEntity
{
[Key]
[Required]
public int ID { get; set; }
[Display(Name = "Account number"), Required, Unicode(false)]
[RegularExpression(@"^(\d )$")]
[MaxLength(11)]
public string AccountNumber { get; set; }
[Column(TypeName = "bit")]
[MaxLength(1)]
[Required]
public bool IsDraft { get; set; } = false;
}
My view model
public class MyViewModel
{
public MyEntity Entity { get; set; } = new();
public string Title { get; set; }
}
My controller
public class MyHomeController : Controller
{
// GET: MyHome/Index
public IActionResult Index()
{
MyViewModel model = new()
{
Title = "My page - Search account details"
};
return View(model);
}
// POST: MyHome/FindAccountDetails
[HttpPost, ValidateAntiForgeryToken]
public ActionResult FindBankAccountDetails(MyViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
return PartialView("_Details", model);
}
}
My view :
@using MyApplication
@model MyViewModel
<div >
<div >
<h2>@Model.Title</h2>
</div>
<div >
@using (Html.AjaxBeginForm("FindBankAccountDetails", "MyHome", new AjaxOptions
{
HttpMethod = "POST",
UpdateTargetId = "request-general-information",
InsertionMode = InsertionMode.Replace
}))
{
<div >
<label asp-for="Entity.AccountNumber" >Account number</label>
<input asp-for="Entity.AccountNumber" />
<span asp-validation-for="Entity.AccountNumber" ></span>
</div>
<button type="submit" >Search details</button>
}
</div>
</div>
<div id="request-general-information"></div>
@section Scripts {
@{
await Html.RenderPartialAsync("_ValidationScriptsPartial");
}
}
My problem: on validation, the view model is not recognized by the program. The program returns the following message in console :
Microsoft.AspNetCore.Hosting.Diagnostics: Information: Request starting HTTP/1.1 POST https://localhost:44323/MyHome/FindBankAccountDetails application/x-www-form-urlencoded; charset=UTF-8 283
Microsoft.AspNetCore.Routing.EndpointMiddleware: Information: Executing endpoint 'MyApplication.MyHomeController.FindBankAccountDetails (‘MyApplication)'
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker: Information: Route matched with {action = "FindBankAccountDetails", controller = "MyHome"}. Executing controller action with signature Microsoft.AspNetCore.Mvc.ActionResult FindBankAccountDetails(MyApplication.MyViewModel) on controller MyApplication.MyHomeController (‘MyApplication).
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker: Information: Executed action MyApplication.MyHomeController.FindBankAccountDetails (‘MyApplication) in 3.8675ms
Microsoft.AspNetCore.Routing.EndpointMiddleware: Information: Executed endpoint 'MyApplication.MyHomeController.FindBankAccountDetails (‘MyApplication)'
Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware: Error: An unhandled exception has occurred while executing the request.
System.InvalidCastException: The field of type System.Boolean must be a string, array or ICollection type.
at System.ComponentModel.DataAnnotations.MaxLengthAttribute.IsValid(Object value)
at System.ComponentModel.DataAnnotations.ValidationAttribute.IsValid(Object value, ValidationContext validationContext)
at System.ComponentModel.DataAnnotations.ValidationAttribute.GetValidationResult(Object value, ValidationContext validationContext)
at Microsoft.AspNetCore.Mvc.DataAnnotations.DataAnnotationsModelValidator.Validate(ModelValidationContext validationContext)
at Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationVisitor.ValidateNode()
at Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationVisitor.VisitSimpleType()
at Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationVisitor.VisitImplementation(ModelMetadata& metadata, String& key, Object model)
at Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationVisitor.Visit(ModelMetadata metadata, String key, Object model)
at Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationVisitor.VisitChildren(IValidationStrategy strategy)
at Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationVisitor.VisitComplexType(IValidationStrategy defaultStrategy)
at Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationVisitor.VisitImplementation(ModelMetadata& metadata, String& key, Object model)
at Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationVisitor.Visit(ModelMetadata metadata, String key, Object model)
at Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationVisitor.VisitChildren(IValidationStrategy strategy)
at Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationVisitor.VisitComplexType(IValidationStrategy defaultStrategy)
at Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationVisitor.VisitImplementation(ModelMetadata& metadata, String& key, Object model)
at Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationVisitor.Visit(ModelMetadata metadata, String key, Object model)
at Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationVisitor.Validate(ModelMetadata metadata, String key, Object model, Boolean alwaysValidateAtTopLevel, Object container)
at Microsoft.AspNetCore.Mvc.ModelBinding.ObjectModelValidator.Validate(ActionContext actionContext, ValidationStateDictionary validationState, String prefix, Object model, ModelMetadata metadata, Object container)
at Microsoft.AspNetCore.Mvc.ModelBinding.ParameterBinder.EnforceBindRequiredAndValidate(ObjectModelValidator baseObjectValidator, ActionContext actionContext, ParameterDescriptor parameter, ModelMetadata metadata, ModelBindingContext modelBindingContext, ModelBindingResult modelBindingResult, Object container)
at Microsoft.AspNetCore.Mvc.ModelBinding.ParameterBinder.BindModelAsync(ActionContext actionContext, IModelBinder modelBinder, IValueProvider valueProvider, ParameterDescriptor parameter, ModelMetadata metadata, Object value, Object container)
at Microsoft.AspNetCore.Mvc.Controllers.ControllerBinderDelegateProvider.<>c__DisplayClass0_0.<<CreateBinderDelegate>g__Bind|0>d.MoveNext()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
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.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task)
Microsoft.AspNetCore.Routing.EndpointMiddleware: Information: Executing endpoint '405 HTTP Method Not Supported'
Microsoft.AspNetCore.Routing.EndpointMiddleware: Information: Executed endpoint '405 HTTP Method Not Supported'
Microsoft.AspNetCore.Hosting.Diagnostics: Information: Request finished HTTP/1.1 POST https://localhost:44323/MyHome/FindBankAccountDetails application/x-www-form-urlencoded; charset=UTF-8 283 - 405 - text/plain 34.4795ms
The browser then presents this message: https://localhost:44323/MyHome/FindBankAccountDetails 405 (Method Not Allowed)
I can't reach FindBankAccountDetails
controller method by using breakpoints.
Why doesn't MyViewModel
view model get retrieved from FindBankAccountDetails
controller method?
Thanks for your help.
CodePudding user response:
According to documentation property [MaxLength()] specifies the maximum length of array or string. IsDraft is boolean, this is why you get InvalidCastException.
[Column(TypeName = "bit")]
[MaxLength(1)]
[Required]
public bool IsDraft { get; set; } = false;