简体   繁体   中英

asp.net core 2.1 model binding (after submit)

I have experience with asp.net but I'm new in .net core so when I tried to perform the simple submit task I got the strange behavior. When I'm opening the view and sending some model to it the binding works fine but after i submit this form and try to return empty model or change the value of the passed model binding not working....it keep the value that was submitted.

View

 @model EmailModel


    <div class="w3-col m6 w3-panel">
        <div class="w3-large w3-margin-bottom">
            <i class="fa fa-map-marker fa-fw w3-hover-text-black w3-xlarge w3-margin-right"></i> Rzemieślnicza 26, 30-403 Kraków, POL<br>
            <i class="fa fa-phone fa-fw w3-hover-text-black w3-xlarge w3-margin-right"></i> Telefon: 667 071 064<br>
            <i class="fa fa-envelope fa-fw w3-hover-text-black w3-xlarge w3-margin-right"></i> Email: mail@mail.com<br>
        </div>
        <p>Jeżeli masz jakieś pytania, zastrzeżenia lub wątpliwości napisz do nas</p>
        <p>  <span asp-validation-for="Name" class="text-danger"></span></p>
        <p>  <span asp-validation-for="EmailTo" class="text-danger"></span></p>
        <p>  <span asp-validation-for="Phone" class="text-danger"></span></p>
        <p>  <span asp-validation-for="Subject" class="text-danger"></span></p>
        <p>  <span asp-validation-for="Text" class="text-danger"></span></p>
        @using (@Html.BeginForm("Contacts", "Home", FormMethod.Post))
        {

            <div class="w3-row-padding" style="margin:0 -16px 8px -16px">
                <div class="w3-third">

                    <input asp-for="Name" class="w3-input w3-border" type="text" placeholder="Imię i Nazwisko" required>
                </div>
                <div class="w3-third">

                    <input asp-for="EmailTo" class="w3-input w3-border" placeholder="Email" required />

                </div>
                <div class="w3-third">

                    <input asp-for="Phone" class="w3-input w3-border" type="tel" placeholder="Telefon" required />

                </div>
            </div>
            <div style="width:100%">

                <input asp-for="Subject" class="w3-input w3-border" type="text" placeholder="Temat wiadomości" required>

            </div>

            <textarea asp-for="Text" class="w3-input w3-border" type="text" placeholder="Temat wiadomości" required rows="6"></textarea>

            <button class="w3-button w3-black w3-right w3-section" type="submit">
                <i class="fa fa-paper-plane"></i> Wyślij wiadomość
            </button>
        }

</div>

Model

public class EmailModel
{
    [Required]
    [EmailAddress]
    public string EmailTo { get; set; }
    [Required]
    public string Name { get; set; }
    public string Surname { get; set; }
    [Required]
    [Phone]
    public string Phone { get; set; }
    [Required]
    public string Subject { get; set; }
    [Required]
    public string Text { get; set; }
}

Actions

   public IActionResult Contacts()
    {
        ViewData["Title"] = _translation["Contacts"];

        return View(new EmailModel() { Name = "Test" });
    }
    [HttpPost]
    public IActionResult Contacts(EmailModel model)
    {
        if(!ModelState.IsValid)
        {
            return View("Contacts", model);
        }
        try
        {
            string mailBodyhtml = "Imię i Nazwisko: " + model.Name + "<br>" + "Telefon: " + model.Phone + "<br>" + "Email: " + model.EmailTo + "<br><br>" + model.Text;
            var msg = new MailMessage("******", "******", "ZD -"+ model.Subject, mailBodyhtml);
            msg.IsBodyHtml = true;
            var smtpClient = new SmtpClient("******", 587); //if your from email address is "from@hotmail.com" then host should be "smtp.hotmail.com"
            smtpClient.UseDefaultCredentials = true;
            smtpClient.Credentials = new NetworkCredential("***", "*****"); 
            smtpClient.EnableSsl = true;
            smtpClient.Send(msg);
            Console.WriteLine("Email Sended Successfully");
        }
        catch (Exception ex)
        {
            Console.Write(ex.ToString());
        }
        model.Name = "After submit name";

        return View("Contacts" ,model);
    }
  1. On first view load Name ="Test"
  2. On before submit Name ="My submit name"
  3. After submit should be Name = "After submit name" but it's s till ="My submit name"

However after submit in the debug Model.Name ="After submit name"

The values displayed in the view come from ModelState , not the model. ModelState is composed of values from Request , ViewData / ViewBag , and finally Model . Since you've already posted, that means there's now a value for Name in Request , which will then take precedence over anything you set on your model.

While there's some hacky ways around this, the most appropriate path is to follow the PRG (Post-Redirect-Get) pattern. Essentially, after posting, you only return the view again if there's validation errors (in which case, you want the posted values to be redisplayed, so the user can make necessary corrections). Otherwise, you redirect - even if you redirect to the same action. The sheer act of redirection causes a new GET request to be issued, and has the effect of resetting the page as if it's the first load - where the values in your model will apply.

As Chris Pratt suggests, the Post-Redirect-Get pattern is appropriate.

Here is one way to achieve that (with a simplified version of your code). Store the updated model in TempData before calling RedirectToAction .

// using Newtonsoft.Json;

public IActionResult Contacts()
{
    var model = new EmailModel { Name = "Test" };

    if (TempData[nameof(EmailModel)] is string json)
    {
        model = JsonConvert.DeserializeObject<EmailModel>(json);
    }

    return View(model);
}

[HttpPost]
public IActionResult Contacts(EmailModel model)
{
    model.Name = "After submit name";
    TempData[nameof(EmailModel)] = JsonConvert.SerializeObject(model);

    return RedirectToAction("Contacts");
}

Since TempData stores data only until it's read, it is particularly appropriate for redirection.

Finaly found what I was looking for . The solution is to use ModelState.Clear();

1)

[HttpPost]
public IActionResult Contacts(EmailModel model)
{
    if(!ModelState.IsValid)
    {
        return View("Contacts", model);
    }
   ///some code
   ModelState.Clear();
    return View("Contacts", new EmailModel() );
}

And If we need to replace only partial view ( for example ajax request):

2)

[HttpPost]
public IActionResult Contacts(EmailModel model)
{
    if(!ModelState.IsValid)
    {
        return PartialView("Contacts", model);
    }
   ///some code
   ModelState.Clear();
    return PartialView("Contacts", new EmailModel() );
}

Sorce: Clear fields after success

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM