Ответ - да.Конечно.Почему бы и нет?Это займет всего около 1% вашего кода!
Подумайте об этом:
Цель ViewModel - это контейнер для отправки данных в представление.
Таким образом, он может «формировать» данные, отправляемые в представление, которые могут не соответствовать вашей доменной модели.Например, если Thingies имеет 50 свойств (или столбцов в таблице ...), вам может понадобиться только 3 из этих свойств.
Для предоставления данных формы я использую класс «Сервис».Например, StatusService (связанный интерфейсом для разрешения DI, например, IStatusService).Таким образом, класс Service получает экземпляры ваших репозиториев, предоставляет методы для использования в ваших контроллерах и специальные свойства только для чтения, которые создают ваши ViewModels для упаковки данных для представлений.
Используя этот способДелая вещи, вы можете легко увидеть, что усилия, которые идут на написание ViewModel, бесполезны.С точки зрения строк кода, вероятно, 1 процент.
Хотите доказательства?
Посмотрите на следующее:
Типичным контроллером будет:
Контроллер:
// ПРИМЕЧАНИЕ. ИСПОЛЬЗОВАНИЕ: service.ViewModel
namespace ES.eLearningFE.Areas.Admin.Controllers
{
public partial class StepEditorController : Controller
{
IStepEditorService service;
public StepEditorController(IStepEditorService service)
{
this.service = service;
}
[HttpGet]
public virtual ActionResult List(int IdCourse)
{
service.CourseId = IdCourse;
return View(service.Steps());
}
[HttpGet]
public virtual ActionResult Edit(int IdCourse, int IdStep)
{
service.CourseId = IdCourse;
service.CurrentStepId = IdStep;
return View(service.ViewModel);
}
[HttpPost]
public virtual ActionResult Edit(CourseStep step)
{
service.CourseId = step.CourseId;
service.CurrentStepId = step.CourseStepId;
service.CourseId = step.CourseId;
try
{
UpdateModel(service.CurrentStep);
service.Save();
return RedirectToAction(Actions.Edit(step.CourseId, step.CourseStepId));
}
catch
{
// Refactor notice : empty catch block : Return errors!
}
return View(service.ViewModel);
}
[HttpGet]
public virtual ActionResult New(int IdCourse)
{
service.CourseId = IdCourse;
return View(service.ViewModel);
}
[HttpPost]
public virtual ActionResult New(CourseStep step)
{
service.CourseId = step.CourseId;
if (ModelState.IsValid)
{
service.AddStep(step);
try
{
service.Save();
service.CurrentStepId = step.CourseStepId;
return View(Views.Edit, service.ViewModel);
}
catch
{
// Refactor notice : empty catch block : Return errors!
}
}
return View(service.ViewModel);
}
}
}
Служба:
Класс службы будет выглядеть следующим образом:
// ЗАМЕЧАНИЕ СЛЕДУЮЩЕЙ СОБСТВЕННОСТИ: public StepEditorVM ViewModel
namespace ES.eLearning.Domain.Services.Admin
{
public class SqlStepEditorService : IStepEditorService
{
DataContext db;
public SqlStepEditorService(DbDataContextFactory contextFactory)
{
db = contextFactory.Make();
CoursesRepository = new SqlRepository<Course>(db);
StepsRepository = new SqlRepository<CourseStep>(db);
}
#region IStepEditorService Members
public StepEditorVM ViewModel
{
get
{
if (CurrentStep != null)
{
return new StepEditorVM
{
CurrentStep = this.CurrentStep,
Steps = this.Steps()
};
}
else // New Step
{
return new StepEditorVM
{
CurrentStep = new CourseStep(),
Steps = this.Steps()
};
}
}
}
public CourseStep CurrentStep
{
get
{
return FindStep(CurrentStepId, CourseId);
}
}
// Refactor notice : Expose Steps with a CourseId parameter, instead of reading from the CourseId property?
public List<CourseStep> Steps()
{
if (CourseId == null) throw new ApplicationException("Cannot get Steps [CourseId == null]");
return (from cs in StepsRepository.Query where cs.CourseId == CourseId select cs).ToList();
}
// Refactor notice : Pattern for dealing with null input parameters
public int ? CourseId { get; set; }
public int ? CurrentStepId { get; set; }
public CourseStep FindStep(int ? StepId, int ? CourseId)
{
// Refactor notice : Pattern for dealing with null input parameters
if (CourseId == null) throw new ApplicationException("Cannot Find Step [CourseId == null]");
if (CurrentStepId == null) throw new ApplicationException("Cannot Find Step [StepId == null]");
try
{
return (from cs in StepsRepository.Query where ((cs.CourseStepId == StepId) && (cs.CourseId == CourseId)) select cs).First();
}
catch
{
return null;
}
}
public void AddStep(CourseStep step)
{
StepsRepository.Add(step);
}
public void DeleteStep(CourseStep step)
{
StepsRepository.Delete(step);
}
public void Clear()
{
CurrentStepId = null;
CourseId = null;
}
public void Save()
{
db.SubmitChanges();
}
#endregion
#region Repositories
private IRepository<Course> CoursesRepository
{
get;
set;
}
private IRepository<CourseStep> StepsRepository
{
get;
set;
}
#endregion
}
}
Интерфейс:
И интерфейс будет выглядеть так:
namespace ES.eLearning.Domain.Services.Interfaces
{
public interface IStepEditorService
{
StepEditorVM ViewModel { get; }
CourseStep CurrentStep { get; }
List<CourseStep> Steps();
int ? CourseId { get; set; }
int ? CurrentStepId { get; set; }
CourseStep FindStep(int ? StepId, int ? CourseId);
void AddStep(CourseStep step);
void DeleteStep(CourseStep step);
void Clear();
void Save();
}
}
Класс ViewModel:
И, наконец, сам класс ViewModel:
namespace ES.eLearning.Domain.ViewModels
{
public class StepEditorVM
{
public CourseStep CurrentStep { get; set; }
public List<CourseStep> Steps { get; set; }
}
}
По сравнению со всеми остальными, это ничто.
Так почему бы не сделать это?
Другие биты:
Общий репозиторий:
namespace ES.eLearning.Domain
{
public class SqlRepository<T> : IRepository<T> where T : class
{
DataContext db;
public SqlRepository(DataContext db)
{
this.db = db;
}
#region IRepository<T> Members
public IQueryable<T> Query
{
get { return db.GetTable<T>(); }
}
public List<T> FetchAll()
{
return Query.ToList();
}
public void Add(T entity)
{
db.GetTable<T>().InsertOnSubmit(entity);
}
public void Delete(T entity)
{
db.GetTable<T>().DeleteOnSubmit(entity);
}
public void Save()
{
db.SubmitChanges();
}
#endregion
}
}
IRepository:
namespace Wingspan.Web.Mvc
{
public interface IRepository<TEntity> where TEntity : class
{
List<TEntity> FetchAll();
IQueryable<TEntity> Query {get;}
void Add(TEntity entity);
void Delete(TEntity entity);
void Save();
}
}
ПРИМЕЧАНИЕ. Это то, над чем я сейчас работаю, так что это незавершенная работа, которая намного проще, чем будет заключительная вещь, но это, безусловно, первая и вторая итерация, и она дает представлениенасколько структурирована ваша работа.
Сложность возрастет, когда клиенту понадобятся новые функции в представлениях и т. д. Но даже в этом случае это среда, на которой вы можете очень легко построить и протестировать изменения.
Причина, по которой я так поступаю, в основном заключается в том, чтобы обеспечить структурированный способ написания вашего кода.Вы можете записать все это за утро, прежде чем вы даже создадите соответствующие виды.
Т.е. все происходит очень быстро, и вы точно знаете, что пытаетесь сделать.
Как только вы это сделаете, вы создадите свои Представления и увидите, что произойдет ...
Шутка аппарт, красота в том, что к тому времени, когда вы добираетесь до представлений, вы знаете, что делаете, вы знаете своиданные, его форма и дизайн представления просто текут.Затем вы добавляете дополнения, которые требуются в Views, и, конечно, задание выполнено.
Конечно, другая причина - тестирование.Но даже здесь вы получаете выгоду от высоко структурированного подхода: ваши тесты также будут следовать очень четкой схеме.Так просто написать.
Весь смысл:
Весь смысл вышеизложенного состоит в том, чтобы подчеркнуть, насколько мало усилий уходит на написание ViewModel, по сравнению с общими усилиями.