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);
}
Name ="Test"
Name ="My submit name"
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.