web-dev-qa-db-de.com

MVC ViewModel-Beispiel

Ich habe Tutorials gemacht und versucht, bewährte Methoden für die MVC-Entwicklung zu erlernen. Das unten verwendete Design stammt von Pro ASP.Net MVC5 von Apress/Adam Freeman. Bisher läuft alles gut ... aber ich bin immer noch nicht ganz in der Lage, mit Controllern zu arbeiten. Ja, ich verstehe das Konzept von Controllern, habe aber immer noch Schwierigkeiten beim Posten und Abrufen von Methoden. Hier ist der Ablauf meiner Beispiel-MVC-Anwendung:

Mein app.Domain-Projekt

Ich habe eine Benutzertabelle in der Datenbank und verweise darauf mit Entities/Users.cs

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

namespace app.Domain.Entities
{
public class Users
{
    [Key]
    public int UserID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public DateTime CreateDate { get; set; }
    public DateTime LastLogin { get; set; }

}
}

Als nächstes habe ich ein Interface und es befindet sich Abstract/IUsersRepository.cs

using System;
using System.Collections.Generic;
using app.Domain.Entities;

namespace app.Domain.Abstract
{
public interface IUsersRepository
{
    IEnumerable<Users> Users { get; }
}
}

Im weiteren Verlauf fülle ich nun meine Entities Concrete/EFUsersRepository.cs

using System;
using System.Collections.Generic;
using app.Domain.Entities;
using app.Domain.Abstract;

namespace app.Domain.Concrete
{
public class EFUsersRepository : IUsersRepository
{
    private EFDbContext context = new EFDbContext();

    public IEnumerable<Users> Users
    {
        get { return context.Users; }
    }
}
}

Außerdem benutzt das Lehrbuch Ninject, was ich verstehe und alles ist korrekt gebunden. Ich werde diesen Code erst posten, wenn mich jemand dazu auffordert.

Hier ist meine app.WebUI-Lösung:

Das Lehrbuch führt mich durch die Erstellung eines ViewModel. Hier wird es für mich etwas unübersichtlich. Ist das ViewModel ein zusätzlicher Kanal, um die Entitäten abzurufen? Soll ich ViewModels immer mit SELECT-, UPDATE-, INSERT- und DELETE-Daten (Models/UsersViewModel.cs) erstellen, anstatt auf die Modelle selbst zu verweisen?

using System;
using System.Collections.Generic;
using app.Domain.Entities;

namespace app.WebUI.Models
{
public class UsersViewModel
{
    //public string FirstName { get; set; }
    //public string LastName { get; set; }
    //public string Email { get; set; }
    //public string City { get; set; }
    //public string State { get; set; }
    public IEnumerable<Users> Users { get; set; }
}
}

In diesem Szenario muss der Benutzer eine E-Mail eingeben. Anschließend überprüft der Controller die Datenbank auf die E-Mail. Wenn es existiert, leiten Sie zur About-Ansicht (Controllers/HomeController.cs) weiter.

using System.Linq;
using System.Web.Mvc;
using app.Domain.Abstract;
using app.WebUI.Models;


namespace app.Controllers
{
public class HomeController : Controller
{
    private IUsersRepository repository;

    public HomeController(IUsersRepository usersRepository)
    {
        this.repository = usersRepository;
    }

    [HttpGet]
    public ActionResult Index()
    {
        return View();
    }

    [HttpPost]
    public ActionResult Index()
    {
        UsersViewModel userViewModel = new UsersViewModel()
        {
            Users = repository.Users
            .Where(p => p.Email == "[email protected]")
        };
        return View("About", userViewModel);

    }

    public ActionResult About()
    {
        ViewBag.Message = "Your application description page.";
        return View();
    }

    public ActionResult Contact()
    {
        ViewBag.Message = "Your contact page.";
        return View();
    }
}
}

Und hier ist meine Ansicht (Home/Index.cshtml):

@model app.WebUI.Models.UsersViewModel

@{
    ViewBag.Title = "Home Page";
    Layout = "~/Views/Shared/_LayoutNoMenu.cshtml";
}


@foreach (var p in Model.Users)
{ 
<div class="container">
@using (Html.BeginForm("About", "Home", FormMethod.Get, new { @class = "begin-form" }))
{
    <h1>Welcome</h1>
    <div class="required-field-block">
    <textarea rows="1" class="form-control" placeholder="Email" id="filter"></textarea>
    </div>
    <button class="btn btn-primary" type="submit">Login</button>
}
</div>
}

Irgendwelche Ratschläge zur korrekten Verwendung eines ViewModel?

18
JoshYates1980

Im Juni 2014 habe ich diese Frage gestellt, als ich MVC gelernt habe. Ab heute verstehe ich das Konzept eines Ansichtsmodells. Hoffentlich hilft dies einem anderen MVC-Anfänger:

Mein Modell, das die Datenbanktabelle darstellt:

public partial class County : Entity
{
    public int CountyID { get; set; }
    public string CountyName { get; set; }
    public string UserID { get; set; }
    public DateTime? CreatedDate { get; set; }
    public string ModifiedUserID { get; set; }
    public DateTime? ModifiedDate { get; set; }

    public virtual IList<Property> Properties { get; set; }
    public virtual DistrictOffice DistrictOffice { get; set; }
    public virtual IList<Recipient> Recipients { get; set; }
}

Es gibt zwei Eins-zu-Viele-Beziehungen und eine Eins-zu-Eins-Beziehung. Entity Framework und Abhängigkeitsinjektion. (Dies ist für die Erklärung des Ansichtsmodells nicht erforderlich.)

Zunächst erstelle ich ein Ansichtsmodell für den temporären Speicher, das vom Controller an die Ansicht übergeben wird. CountyViewModel.cs

public class CountyViewModel
{
    [HiddenInput]
    public int? CountyId { get; set; }

    [DisplayName("County Name")]
    [StringLength(25)]
    public string CountyName { get; set; }

    [DisplayName("Username")]
    [StringLength(255)]
    public string Username{ get; set; }
}

Sie haben die Flexibilität, andere Namen und Datentypen als Ihr Modell zu verwenden. Beispiel: Meine Datenbankspalte ist UserID, mein Modell ist UserID, mein Ansichtsmodell ist UserName. Sie müssen keine Daten an die Ansicht übergeben, die nicht verwendet werden (z. B. das gesamte Modell). In diesem Beispiel werden nur drei Teile des Grafschaftsmodells benötigt.

In meinem Controller deklariere ich mein Ansichtsmodell:

Ich brauche Daten:

var county = _countyService.Get(countyId);

Nächster,

CountyViewModel countyViewModel = new CountyViewModel();
countyViewModel.CountyId = county.CountyID;
countyViewModel.CountyName = county.CountyName;
countyViewModel.UserName = county.UserID;

Sie können auch folgendermaßen deklarieren:

CountyViewModel countyViewModel = new CountyViewModel
{
    CountyId = county.CountyID,
    CountyName = county.CountyName,
    UserName = county.UserID
};

Jetzt ist es Zeit, die Ansicht weiterzugeben:

return View(countyViewModel);

In der Ansicht:

@model Project.Web.ViewModels.CountyViewModel

@{
    Layout = "~/Views/Shared/_Layout.cshtml";
 }

 <div>@Model.CountyName</div>
 @Html.HiddenFor(model => model.CountyId)

 <div>
 @Html.TextBoxFor(model => model.CountyName, new { @class = "form-control" })

Hier ist ein einfaches Beispiel für die Übergabe von Daten mit einem Ansichtsmodell und die Verwendung von Dienstaufrufen an die Datenbank mit Entity Framework:

Beispiel Controller

public class PropertyController : Controller
{
    private readonly ICountyService _countyService;

    public PropertyController(ICountyService countyService)
        : base()
    {
        _countyService = countyService;
    }


    [HttpGet]
    public ActionResult NewProperty()
    {
        using (UnitOfWorkManager.NewUnitOfWork())
        {
            ListAllCountiesViewModel listAllCountyViewModel = new ListAllCountiesViewModel()
            {
                ListAllCounty = _countyService.ListOfCounties().ToList()
            };

            PropertyViewModel viewModel = new PropertyViewModel()
            {
                _listAllCountyViewModel = listAllCountyViewModel,
                _countyViewModel = new CountyViewModel(),
            };
            return View(viewModel);
        }
     }
 }

Beispiel ViewModels

public class CountyViewModel
{
    [HiddenInput]
    public int? CountyId { get; set; }

    [DisplayName("County Name")]
    [StringLength(25)]
    public string CountyName { get; set; }

    [DisplayName("County URL")]
    [StringLength(255)]
    public string URL { get; set; }
}

public class ListAllCountiesViewModel
{
    public string CountyName { get; set; }
    public IEnumerable<County> ListAllCounty { get; set; }
}

public class PropertyViewModel
{
    public ListAllCountiesViewModel _listAllCountyViewModel { get; set; }
    public CountyViewModel _countyViewModel { get; set; }
}

Beispiel Serviceschicht

public partial interface ICountyService
{
    County Get(int id);
    County GetByCompanyCountyID(int id);
    IEnumerable<County> ListOfCounties();
    void Delete(County county);
    IEnumerable<State> ListOfStates();
    void Add(County county);
    County SearchByName(string county);
}


public partial class CountyService : ICountyService
{
    private readonly ICountyRepository _countyRepository;

    public CountyService(ICountyRepository countryRepository)
    {
        _countyRepository = countryRepository;
    }

    /// <summary>
    /// Returns a county
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public County Get(int id)
    {
        return _countyRepository.Get(id);
    }

    /// <summary>
    /// Returns a county by County Id
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public County GetByCountyID(int id)
    {
        return _countyRepository.GetByMedicaidCountyID(id);
    }

    /// <summary>
    /// Returns all counties
    /// </summary>
    /// <returns></returns>
    public IEnumerable<County> ListOfCounties()
    {
        return _countyRepository.ListOfCounties();
    }

    /// <summary>
    /// Deletes a county
    /// </summary>
    /// <param name="county"></param>
    public void Delete(County county)
    {
        _countyRepository.Delete(county);
    }

    /// <summary>
    /// Return a static list of all U.S. states
    /// </summary>
    /// <returns></returns>
    public IEnumerable<State> ListOfStates()
    {
        var states = ServiceHelpers.CreateStateList(); 
        return states.ToList();
    }

    /// <summary>
    /// Add a county
    /// </summary>
    /// <param name="county"></param>
    public void Add(County county)
    {
        county.CreatedUserID = System.Web.HttpContext.Current.User.Identity.Name;
        county.CreatedDate = DateTime.Now;
        _countyRepository.Add(county);
    }

    /// <summary>
    /// Return a county by searching it's name
    /// </summary>
    /// <param name="county"></param>
    /// <returns></returns>
    public County SearchByName(string county)
    {
        return _countyRepository.SearchByName(county);
    }
}

Beispiel Repository-Ebene

public partial class CountyRepository : ICountyRepository
{
    private readonly Context _context;

    public CountyRepository(IContext context)
    {
        _context = context as Context;
    }

    public County Get(int id)
    {
        return _context.County.FirstOrDefault(x => x.CountyID == id);
    }

    public County GetByCompanyCountyID(int id)
    {
        return _context.County.FirstOrDefault(x => x.CountyID == id);
    }

    public IList<County> ListOfCounties()
    {
        return _context.County.ToList()
            .OrderBy(x => x.CountyName)  
            .ToList();
    }

    public void Delete(County county)
    {
        _context.County.Remove(county);
    }

    public County Add(County county)
    {
        _context.County.Add(county);
        return county;
    }

    public County SearchByName(string county)
    {
        return _context.County.FirstOrDefault(x => x.CountyName == county);
    }
}
25
JoshYates1980