C # MVC5 EF - How not to lose data after ModelState validation?

1

Below is my question if you can help. I use C # ASP.NET MVC 5 with Entity Framework.

I have classes that represent below respectively a customer registry and an e-mail registry:

public partial class Cliente
{
    [Key]
    public int ClienteId { get; set; }

    public string Nome { get; set; }

    public virtual ICollection<Email> { get; set; }
}


public partial class Email
{
    [Key]
    public int EmailId { get; set; }

    public string Email { get; set; }

    public int ClienteId { get; set; }

    public virtual Cliente  { get; set; }
}

When I create the view of the email edit page, I would like to bring the client's name (owner of the email), but not so that the user can edit it, but only so that he is sure about which email it is changing.

So, in the view I do something like:

@model Models.Cadastro.Email


//[...]


<div class="form-group">
    @Html.LabelFor(model => model.Cliente.Nome, htmlAttributes: new { @class = "control-label col-md-2" })
    <div class="col-md-10 txt_disable">
        @Html.ValueFor(model => model.Cliente.Nome)
    </div>
</div>


//[...]

So far everything works perfect, the problem is that when I click Save, if ModelState.IsValid is false, this page will return with the Customer Name blank, since the page is populated with the data from the last form and this field (Customer Name) is not part of Model Email and yes Customer Model.

What form do you suggest for me to solve this problem?

    
asked by anonymous 25.09.2017 / 17:19

1 answer

4

Well, you need to keep in mind that a web application is always stateless (or no state ) . That is, basically, the server receives a request, processes it and returns it to the client. There is no "steady stream", so to speak.

Taking this into consideration, you must have figured out what you need to do, right? Fill in the data you want to show in view before you mount it.

I'll show you two ways to do this:

1. Send the navigation property along with the model

This is probably the best way because you will not have to change a lot in your current code.

The action that processes POST should look something like this:

[HttpPost]
public ActionResult Edit(Email email)
{
    if(!ModelState.IsValid)
    {
        // Faça algo para recuperar o "cliente" desta entidade
        email.Cliente = EncontrarCliente(email);
        return View(email);
    }
}

This will cause the navigation property ( Cliente ) to be filled at the time of mounting the view .

2. Save this data to ViewBag

In view it would look something like this:

@model Models.Cadastro.Email

<div class="form-group">
    <label class="control-label col-md-2">Nome do cliente</label>
    <div class="col-md-10 txt_disable">
        @ViewBag.NomeCliente
    </div>
</div>

In controller , you need to make sure to fill this out whenever you return this view :

In action that processes GET:

[HttpGet]
public ActionResult Edit(int id)
{
    var model = db.Emails.Include(e => e.Cliente).Find(id);
    /* (^) Aqui fica o código para procurar a entidade no banco */

    ViewBag.NomeCliente = model.Cliente.Nome;

    return View(model);
}

And also in action that processes POST:

[HttpPost]
public ActionResult Edit(Email email)
{
    var cliente = EncontrarCliente(email);
    ViewBag.NomeCliente = cliente.Nome;

    if(!ModelState.IsValid)
    {
        return View(email);
    }

    // Continua...
}
    
25.09.2017 / 17:58