Existe um cenário comum, que está sendo solicitado bastante nas plataformas ASP.NET MVC, que é a utilização de mais de uma model em apenas uma View, isto acontece bastante em aplicações onde uma única página faz várias ações. O cenário de resolução é o seguinte: Ou seja, criar uma única página, que exibirá os dados de duas models views diferentes (após o tutorial ficará fácil para colocar quantas models quiser). Estarei demonstrando como usar várias models em uma única view em uma plataforma ASP.NET MVC5, você poderá utilizar MVC4 sem problemas.
Antes de saltar para o “hands on” técnico deste cenário, vamos construir um pouco de compreensão conceitual de como vamos conseguir este cenário. Para fazer isso, vamos prosseguir da seguinte maneira:
- Nós temos duas models independentes Register Model & ResultSet Model
- Uma vez que conhecemos a restrição na plataforma ASP.NET MVC, ou seja, podemos apenas anexar uma única model para uma única view. Para resolver este problema iremos criar uma “Model Pai”, uma model que irá englobar as duas models já faladas anteriormente
-
Depois de combinar nossas duas models separadas em um único contexto, podemos então facilmente anexar nossa model para nossa única view. Iremos chamar esta nova model de “Common Model”
Vamos ver agora como iremos criar o padrão seguinte. Primeiramente criei um projeto chamado MultiModelSingleView.
Crie uma classe chamada LoginObj:
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace MultiModelSingleView.Models { public class LoginObj { public int Id { get; set; } public string Username { get; set; } public string Password { get; set; } } }
Agora iremos criar nossas 3 classes principais: Account, Result e Common
using System.Collections.Generic; using System.ComponentModel.DataAnnotations; namespace MultiModelSingleView.Models { public class AccountViewModel { [Display(Name = "Id")] public int Id { get; set; } [Display(Name = "Enter Username")] public string Username { get; set; } [Display(Name = "Enter Password")] public string Password { get; set; } } }
using System.Collections.Generic; using System.ComponentModel.DataAnnotations; namespace MultiModelSingleView.Models { public class ResultSetViewModel { [Display(Name = "Result")] public List<LoginObj> ResultSet { get; set; } } }
using System.Collections.Generic; using System.ComponentModel.DataAnnotations; namespace MultiModelSingleView.Models { public class CommonViewModel { public AccountViewModel AccountVM { get; set; } public ResultSetViewModel ResultSetVM { get; set; } } }
Em todos os trechos apresentados acima, criamos nossas models de acordo com a compreensão conceitual, que desenvolvemos. Crie um novo arquivo de controllet AccountController.cs sob a pasta Controller e substitua o código fornecido abaixo nele:
namespace MultiModelSingleView.Controllers { using System; using System.Globalization; using System.Linq; using System.Security.Claims; using System.Threading.Tasks; using System.Web; using System.Web.Mvc; using Microsoft.AspNet.Identity; using Microsoft.AspNet.Identity.Owin; using Microsoft.Owin.Security; using MultiModelSingleView.Models; using System.Collections.Generic; using System.IO; using System.Reflection; public class AccountController : Controller { #region Register method #region GET: /Account/Register // // GET: /Account/Register [AllowAnonymous] public ActionResult Register() { // Initialization. CommonViewModel model = new CommonViewModel(); model.AccountVM = new AccountViewModel(); model.ResultSetVM = new ResultSetViewModel(); // Get Result model.ResultSetVM.ResultSet = this.LoadData(); return View(model); } #endregion #region POST: /Account/Register // // POST: /Account/Register [HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public ActionResult Register(CommonViewModel model) { if (ModelState.IsValid) { // Inserting. this.StoreData(model.AccountVM.Username, model.AccountVM.Password); // Get Result model.ResultSetVM = new ResultSetViewModel(); model.ResultSetVM.ResultSet = this.LoadData(); } // If we got this far, something failed, redisplay form return View(model); } #endregion #endregion #region Helpers #region Load Data /// <summary> /// Load data method. /// </summary> /// <returns>Returns - Data</returns> private List<LoginObj> LoadData() { // Initialization. List<LoginObj> lst = new List<LoginObj>(); try { // Initialization. string line = string.Empty; string srcFilePath = "content/files/login_list.txt"; var rootPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase); var fullPath = Path.Combine(rootPath, srcFilePath); string filePath = new Uri(fullPath).LocalPath; StreamReader sr = new StreamReader(new FileStream(filePath, FileMode.Open, FileAccess.Read)); // Read file. while ((line = sr.ReadLine()) != null) { // Initialization. LoginObj infoObj = new LoginObj(); string[] info = line.Split(','); // Setting. infoObj.Id = Convert.ToInt32(info[0].ToString()); infoObj.Username = info[1].ToString(); infoObj.Password = info[2].ToString(); // Adding. lst.Add(infoObj); } // Closing. sr.Dispose(); sr.Close(); } catch (Exception ex) { // info. Console.Write(ex); } // info. return lst; } #endregion #region Store Data /// <summary> /// Store data method. /// </summary> private void StoreData(string username, string password) { // Initialization. LoginObj obj = new LoginObj(); try { // Setting. int idVal = this.LoadData().Select(p => p).ToList().Count > 0 ? (this.LoadData().OrderByDescending(p => p.Id).Select(p => p.Id).FirstOrDefault()) + 1 : 1; // Initialization. string line = string.Empty; string srcFilePath = "content/files/login_list.txt"; var rootPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase); var fullPath = Path.Combine(rootPath, srcFilePath); string filePath = new Uri(fullPath).LocalPath; StreamWriter sw = new StreamWriter(new FileStream(filePath, FileMode.Append, FileAccess.Write)); // Write file. string content = idVal.ToString() + "," + username + "," + password; sw.WriteLine(content); // Closing. sw.Dispose(); sw.Close(); } catch (Exception ex) { // info. Console.Write(ex); } } #endregion #endregion } }
O código dado acima cria um método LoadData(), que irá carregar os dados de um arquivo, se o arquivo contém quaisquer dados, inicialmente, o arquivo está vazio, uma vez que não registramos nenhuma conta, você pode utilizar o tipo de dados que quiser, e é bem mais recomendado utilizar algum banco de dados. Já o método StoreData() é respectivamente o método que precisamos para guardar algum dado no arquivo onde daremos resultados para visualização na view à partir do método LoadData(). Também criamos um método Register na controller que é para o tratamento da nossa model e trabalhar como “controlador” dos nossos dados.
Agora, crie um novo arquivo de view chamado Register.cshtml e substitua o código fornecido abaixo nele:
@model MultiModelSingleView.Models.CommonViewModel @{ ViewBag.Title = "Register"; } <h2>@ViewBag.Title.</h2> @using (Html.BeginForm("Register", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" })) { @Html.AntiForgeryToken() <h4>Create a new account.</h4> <hr /> @Html.ValidationSummary("", new { @class = "text-danger" }) <div class="form-group"> @Html.LabelFor(m => m.AccountVM.Username, new { @class = "col-md-2 control-label" }) <div class="col-md-10"> @Html.TextBoxFor(m => m.AccountVM.Username, new { @class = "form-control" }) </div> </div> <div class="form-group"> @Html.LabelFor(m => m.AccountVM.Password, new { @class = "col-md-2 control-label" }) <div class="col-md-10"> @Html.PasswordFor(m => m.AccountVM.Password, new { @class = "form-control" }) </div> </div> <div class="form-group"> <div class="col-md-offset-2 col-md-10"> <input type="submit" class="btn btn-default" value="Register" /> </div> </div> } <h2>Result List</h2> @if (Model.ResultSetVM.ResultSet != null) { for (int i = 0; i < Model.ResultSetVM.ResultSet.Count; i++) { <div class="row"> <div class="col-md-2"> <p>@Model.ResultSetVM.ResultSet[i].Id</p> </div> <div class="col-md-2"> <p>@Model.ResultSetVM.ResultSet[i].Username</p> </div> <div class="col-md-2"> <p>@Model.ResultSetVM.ResultSet[i].Password</p> </div> </div> } } @section Scripts { @Scripts.Render("~/bundles/jqueryval") }
No código acima, criamos uma view, que é anexada à nossa Common Model e exibe dados registrados anteriormente.
Crie um arquivo de layout de exibição padrão _Layout.cshtml em Views/Shared folder. Substituia o código dado, caso o arquivo já exista, apenas faça a sua substituição:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>@ViewBag.Title</title> @Styles.Render("~/Content/css") @Scripts.Render("~/bundles/modernizr") <!-- Font Awesome --> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css" /> </head> <body> <div class="navbar navbar-inverse navbar-fixed-top"> <div class="container"> <div class="navbar-header"> <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> </div> </div> </div> <div class="container body-content"> @RenderBody() <hr /> <footer> <center> <p><strong>Copyright © @DateTime.Now.Year - <a href="http://www.asmak9.com/">Asma's Blog</a>.</strong> All rights reserved.</p> </center> </footer> </div> @Scripts.Render("~/bundles/jquery") @Scripts.Render("~/bundles/bootstrap") @RenderSection("scripts", required: false) </body> </html>
Agora, execute o projeto e registre algumas contas, verifique o caminho do arquivo para algum local válido em sua máquina caso precise.
Conclusão
Neste artigo, você aprendeu sobre o mapeamento de várias models para uma única view em uma plataforma ASP.NET MVC5. Você também aprendeu sobre a compreensão conceitual por trás deste cenário, juntamente com a forma de alcançar esse cenário a partir da perspectiva de codificação.
Um grande abraço a todos!
Referências: asmak9