question

DMur-8038 avatar image
0 Votes"
DMur-8038 asked DMur-8038 commented

asp-for does not work when using 'name=' property to pass data to controller

Hi, I'm having trouble getting my asp validation to work when I have a name attribute to pass data to my controller.

When I use the below code, my client side validation works fine, but I am not sending any data back to my controller (Because there is no name="" parameter):

             <div class="form-group">
                 <label class="font-heading" asp-for="Email" id="ContactUsEmailHeading">Email</label>
                 <input asp-for="Email" class="form-control" id="ContactUsEmailField" />
                 <span asp-validation-for="Email" class="text-danger"></span>
             </div>


When I add the name attribute to send data to the controller, the client side validation functions, but the validation messages do not display.


             <div class="form-group">
                 <label class="font-heading" asp-for="Email" id="ContactUsEmailHeading">Email</label>
                 <input asp-for="Email" name="ContactUsEmailField" class="form-control" id="ContactUsEmailField" />
                 <span asp-validation-for="Email" class="text-danger"></span>
             </div>

I thought it may be that the validation is displaying but the page is refreshing before I can see it. Upon checking, the method is not executing. So the validation is still working, just the messages are not showing.

My controller:

 [HttpPost]
 public async Task<IActionResult> SendMail(string ContactUsNameField, string ContactUsEmailField, string ContactUsSubjectField, string ContactUsMessageField, bool ContactUsTandCCheckbox)
 {
     DateTime FeedbackDateTime = DateTime.UtcNow;

     if (ModelState.IsValid)
     {
         try
         {
             await SaveContactFormEntry.saveUserEntryAsync(FeedbackDateTime, ContactUsNameField, ContactUsEmailField, ContactUsSubjectField, ContactUsMessageField, ContactUsTandCCheckbox);
         }
         catch (Exception ex)
         {
             return RedirectToAction("Help");
         }
     }

     return RedirectToAction("Help");
 }


Could someone please help me to get my validation working while also passing data to the controller?

dotnet-csharpdotnet-aspnet-core-mvc
· 2
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

The tag helper's asp-for attribute sets the element name according to the model property name. Setting the name attribute manually, like you are doing, overrides this fundamental tag helper feature. The rendered element name must match a property name within the action's input parameter. If the name attribute does not match the input parameter name then the model binder cannot map the incoming post value.

The HttpPost method, Sendemail, should have a complex type; a model input parameter not individual items.

I recommend going through a few beginning level tutorials to learn fundamental programming patterns. Once you follow standards, then validation and model binding will start working as expected.


0 Votes 0 ·

Hi @AgaveJoe. If the asp-for tag sets the name automatically, why does it not work if I remove the name tag so as not to set it manually?

0 Votes 0 ·
AgaveJoe avatar image
1 Vote"
AgaveJoe answered DMur-8038 commented

If the asp-for tag sets the name automatically, why does it not work if I remove the name tag so as not to set it manually?

Because you are not following standard MVC Core patterns and practices. I strongly recommend going through the tutorial in my first post which covers many basic concepts. I also recommend the data access tutorial. There is a lot of great information in these tutorials.

The following code sample is a minimalistic example using a Model, View, and Controller with standard model validation.


 namespace MvcDemo.Controllers
 {
     public class FromViewModel
     {
         [Required]
         public string Name { get; set; }
     }
    
     public class FormController : Controller
     {
         private readonly ILogger<FormController> _logger;
         public FormController(ILogger<FormController> logger)
         {
             _logger = logger;
         }
    
         [HttpGet]
         public IActionResult Index()
         {
             return View();
         }
    
         [HttpPost]
         public IActionResult Index(FromViewModel model)
         {
             _logger.LogInformation(model.Name);
             return View(model);
         }
    
    
     }
 }

Markup

 @model MvcDemo.Controllers.FromViewModel
    
 @{
     ViewData["Title"] = "Index";
 }
    
 <h1>Index</h1>
    
 <h4>FromViewModel</h4>
 <hr />
 <div class="row">
     <div class="col-md-4">
         <form asp-action="Index">
             <div asp-validation-summary="ModelOnly" class="text-danger"></div>
             <div class="form-group">
                 <label asp-for="Name" class="control-label"></label>
                 <input asp-for="Name" class="form-control" />
                 <span asp-validation-for="Name" class="text-danger"></span>
             </div>
             <div class="form-group">
                 <input type="submit" value="Create" class="btn btn-primary" />
             </div>
         </form>
     </div>
 </div>
    
 <div>
     <a asp-action="Index">Back to List</a>
 </div>



· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Thanks @AgaveJoe, that did it. My understanding is still not perfect, but its better than before your answer so I am going the right direction. :)

0 Votes 0 ·
RenaNi-MSFT avatar image
0 Votes"
RenaNi-MSFT answered

Hi @DMur-8038 ,

  1. asp-for="Email" will generate to html like: id="Email" name="Email" by default. If you specify the name and id, they will override the default id and name.

  2. Model binding system will bind the value by name in html.

I think an easy way is to change your backend parameter name to Email:

  public async Task<IActionResult> SendMail(string ContactUsNameField, string Email, string ContactUsSubjectField, string ContactUsMessageField, bool ContactUsTandCCheckbox)

The razor view keep like below:

 <input asp-for="Email"  class="form-control" id="ContactUsEmailField" />


If the answer is helpful, please click "Accept Answer" and upvote it.

Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


Best Regards,

Rena

5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.