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

Asked

Viewed 234 times

1

below 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 registration and an email registration:

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 Edit view of the email page, I would like to bring the name of the client (owner of the email), but not so that the user can edit it but just so he can be sure which email he 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 on Save, if Modelstate.Isvalid is false, this page will come back with the empty Client name, since the page is filled with the data of the last sent form and this field (Customer name) is not part of the Model Email, but part of the Model Client.

How do you suggest I solve this problem?

1 answer

4


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

Taking this into account, you’ve probably figured out what you need to do, right? Fill in the data you want to show on view before mounting it.

I’ll show you two ways to do this:

1. Send the navigation property together with the model

Probably this is the most suitable way because it will not be necessary to change much in your current code.

To action that processes the POST should be 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 make the navigation property (Cliente) is filled when mounting the view.

2. Save this data in ViewBag

In the view 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 the controller, you need to make sure to fill this out whenever you return this view:

In the action that processes the 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 the POST:

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

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

    // Continua...
}
  • Nice to meet you, LINQ! I thought about doing with Viewbag myself, but I was not really liking the idea, because on other pages I will have several of these fields to fill and I would have to change my View a lot. Now that first option worked well! Thank you!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.