我使用了ASP.NET MVC几年,构建复杂的视图模型总是很困难的。
目前,我有一个视图,它显示了一个会议列表,我有以下问题:
我一直试图遵循脂肪模型和精益控制器的想法。
因此,我有以下带有索引操作(HttpGet和HttpPost)的控制器:
(注意: Dispatcher用于发送和接收包含DTO的消息)
public partial class MeetingController : BaseController {
public MeetingController(IDispatcher dispatcher) : base(dispatcher) {}
[HttpGet]
public virtual ActionResult Index(Int32 pageNumber = 1) {
MeetingIndexModel model = new MeetingIndexModelHandler(_dispatcher).Create();
return View(model);
} // Index
[HttpPost]
public virtual ActionResult Index(MeetingIndexModel.Filter filter, Int32 p = 1) {
if (ModelState.IsValid) {
MeetingIndexModel model = new MeetingIndexModelHandler(_dispatcher).Update();
return View(Views.Index, model);
} else {
MeetingIndexModel model = new MeetingIndexModelHandler(_dispatcher).Create();
return View(Views.Index, model);
}
} // Index所以这个模型有点复杂,因为所有的需要,所以我想:
public class MeetingIndexModel {
public IPagedList<ViewEntity> Entities { get; set; }
public ViewFilter Filter { get; set; }
public ViewHelper Helper { get; set; }
public class ViewEntity {
public Int32 Id { get; set; }
public String EmployeeId { get; set; }
public String EmployeeName { get; set; }
public String LocationName { get; set; }
public DateTime Date { get; set; }
}
public class ViewFilter {
public String Location { get; set; }
public String Stamp { get; set; }
}
public class ViewHelper {
public Page Page { get; set; }
public SelectList Locations { get; set; }
}
}实体是使用AutoMapper从DTO中扁平的会议;
Filter是用于过滤会议并在dispatcher中传递的参数。
助手包含SelectLists和其他参数..。
然后我有一个MeetingIndexHandler,它创建、更新甚至提交视图模型。例如,在创建或更新会议时,就会发生提交。
public interface IViewModelHandler<T> {
T Create();
T Update(T model);
void Submit(T model);
}当然,对于MeetingIndexModel,有一个提交方法是没有意义的。
因此,首先,在这种情况下,提交方法是没有意义的。
最后,我有了
public class MeetingIndexModelHandler : IViewModelHandler<MeetingIndexModel> {
private IDispatcher _dispatcher;
public ScheduleIndexModelHandler(IDispatcher dispatcher) {
_dispatcher = dispatcher;
}
public ScheduleIndexModel Create() {
IList<MeetingDTO> meetings = _dispatcher.GetMeetings(DateTime.UtcNow, pageSize, pageNumber);
// Map MeetingDTO to MeetingIndexModel.ViewEntity
// Call GetLocations to get locations from database into Helper.Locations
} // Create
private SelectList GetLocations(String currentLocation) {
}}
我发现这种方法从控制器中删除了很多代码.
但有几个问题我正在寻求帮助:
这种方法是否有超越工程的资格?你认为如何?
如果是,您还使用了哪些其他方法来解决这个问题?
更新1-我已经在使用服务层: dispacther
请注意,我已经有一个服务层(IDispatcher),用于从数据库获取数据,等等.例如,我像这样使用它:
FindMeetingsByDataQuery query = new FindMeetingsByDataQuery(DateTime.UtcNow);
FindMeetingsByDataReply reply = _dispacther.Send<FindMeetingsByDataReply>(query);
// Map reply.Models to my View Models现在清楚了吗?
因此,我需要一种方法来移动这个逻辑(与服务层的通信),以构建远离控制器的视图模型。
更新2-仅使用ViewModel而不使用ViewModelHandler
另一种方法是在ViewModel中填充ViewModel而不是使用ViewModel处理程序的所有逻辑。所以在主计长里我有:
public virtual ActionResult Index(Int32 pageNumber = 1) {
MeetingIndexViewModel model = new MeetingIndexViewModel(_dispatcher);
model.Create(pageNumber, 20, DateTime.UtcNow);
return View(model);
} // IndexMeetingIndexViewModel是:
public class MeetingIndexViewModel : ViewModel {
private IDispatcher _dispatcher;
public IPageList<EntityModel> Entities { get; set; }
public FilterModel Filter { get; set; }
public HelperModel Helper { get; set; }
public MeetingIndexViewModel(IDispatcher dispatcher) {
_dispatcher = dispatcher;
}
public void Create(Int32 pageNumber, Int32 pageSize, DateTime date) {
FindMeetingsByDateQuery query = new FindMeetingsByDateQuery(date, pageNumber, pageSize);
FindMeetingByDateReply reply = _dispatcher.Send<FindMeetingByDateReply>(query);
IEnumerable<MeetingIndexViewModel.EntityModel> entities = Mapper.Map<IEnumerable<FindMeetingByDateReply.MeetingModel>, IEnumerable<MeetingIndexViewModel.EntityModel>>(reply.Meetings);
Entities = new PagedList(entities);
Filter = new FilterModel { Date = date.ToString() };
Helper = new HelperModel {
PageSize = pageSize,
PageNumber = pageNumber,
Locations = _GetLocations(x.Filter.Location)
};
} // Create
public void Submit() {
// In cases where a ViewModel must be sent to the business layer for saving than it is done here. Otherwise this method is removed.
}
private SelectList _GetLocations(Int32? selected) {
GetLocationsQuery query = new GetLocationsQuery();
GetLocationsReply reply = _dispatcher.Send<GetLocationsReply>(query);
return new SelectList(reply.Locations.Select(x => new { Id = x.Id, Name = x.Name }).ToList(), "Id", "Name", selected);
} // _GetLocations
public class EntityModel {
public Int32 Id { get; set; }
public String EmployeeId { get; set; }
public String EmployeeName { get; set; }
public String LocationName { get; set; }
public DateTime Date { get; set; }
} // EntityModel
public class FilterModel {
public Int32? Location { get; set; }
public String Date { get; set; }
} // FilterModel
public class HelperModel {
public Int32 PageSize { get; set; }
public Int32 PageSize { get; set; }
public SelectList Locations { get; set; }
} // HelperModel}
因此,通过这种方式,我删除了从控制器构建视图模型的所有逻辑,并将其传递给视图模型本身。这可以接受吗?现在它不仅仅是一台POCO。
更新3-使用ViewModel和自定义ViewModelHandler的方法
public class MeetingIndexViewModelHandler {
public MeetingIndexViewModel Create(Int32 pageNumber, Int32 pageSize, DateTime date) {
// Code to create the ViewModel
}
// Code to update the ViewModel
// Code to submit the ViewModel
}我认为,拥有来自接口的ViewModelHandler会使一切变得困难,因为每个视图模型都是视图模型。
更新4-将代码留在控制器中
另一种方法是,如3中所示,使ViewModel只是一个POCO,而不是让Handler只将代码留在Controller中。一般来说,代码并不多,但有时可能是.
注:,根据您的经验和我发布的信息,您认为一个好的方法是什么?
发布于 2014-07-29 11:18:12
为此,我建议使用MVVM ()设计模式。MVVM在Model之上添加了新的包装器VM,它允许您保持模型(DTO)的干净,但是您可以添加额外的属性,如标题、描述、.这将允许您保持模型的清洁,并且它们可以在多个VM之间共享。
我会将所有操作保存在VM中,并将模型作为DTO。大多数情况下,每个动作都有自己的VM,但大多数情况下,相同控制器的每个VM都共享相同的模型。
发布于 2014-07-29 11:49:37
只是一个建议,如果您保留相同的接口,但将一个参数添加到接受Create基类的ViewModelArgs方法中,怎么样:
public interface IViewModelHandler<T> {
T Create(ViewModelArgs args);
T Update(T model);
void Submit(T model);
}然后,您可以使args成为ViewModel中的嵌套类。
public class SomeViewModel
{
public class SomeViewModelArgs : ViewModelArgs
{
public SomeViewModelArgs(string value) { // blah }
}
}像这样打电话:
SomeViewModel model = new SomeViewModelHandler(_dispatcher).Create(new SomeViewModel.SomeViewModelArgs("someValue"));试着在这里考虑缺点,可能是在嘲笑/测试时的一些问题?值得一想,但这意味着你可以保留你的界面
编辑
但是,不确定这会给您带来什么,您不能仅仅在ViewModel上设置一个构造函数。VM不能决定从调度员那里得到什么吗?
它似乎是一个没有任何考虑它自己的图层
例如,它结束了什么:
[HttpGet]
public virtual ActionResult Index(Int32 pageNumber = 1)
{
MeetingIndexModel model = new MeetingIndexModel();
model.GetData();
return View(model);
}或者,如果注入了依赖项(如果您不想在构造函数中执行与数据相关的工作,那么可以让模型绑定器调用一个“后解析”方法-您也可以在其中更好地处理错误):
[HttpGet]
public virtual ActionResult Index(Int32 pageNumber = 1, MeetingIndexModel model)
{
return View(model);
}只是不知道这一层给了你什么。你能解释一下你觉得这对你有什么好处吗?也许我从你的意图中遗漏了什么
发布于 2014-07-29 12:48:19
更新
就我个人而言,我只会使用没有处理程序的服务层。如果您只为网站使用服务层,那么您可以直接从它返回视图模型。您的代码将更简单、更易读,而且如果需要的话,始终可以添加更多的层。这样,您就可以直接将db实体映射到视图模型。
https://stackoverflow.com/questions/25013831
复制相似问题