假设我想发出一个更新房屋状态的发布请求,理想情况下,这些数据应该在某种服务层中,通常这涉及
- 验证用户 - 他们仍然活跃还是被管理员踢出?
- 检查 houseid - houseid/记录是否有效?
- 用户可以看到房子的详细信息吗?
- 将状态更新为“打开”或“关闭”
在现实世界/复杂领域中 - 大多数视图都非常复杂,我们必须抛出该区域的房屋数量,房屋评论数量,房屋详细信息等,也许房屋未完成任务的数量...
简而言之-上述所有代码都可能在服务层内,但是可以说抛出异常,用户无法更新房屋的状态-现在要填充视图,您必须首先(再次)获取房屋详细信息,加载将您刚刚在服务层中加载的所有其他内容所有这些都放在控制器中,或者对加载此数据的服务层进行其他创新...
如何通过运行验证和各种方式来确保我的域模型受到保护,而无需多次重写相同的代码......
此代码在操作方法内,它很容易在服务层内......
//注意:_repo 是对 linq to sql 的简单抽象...
[HttpGet]
public ActionResult TaskDetail(int houseid, int taskid)
{
var loggedonuser = _repo.GetCurrentUser();
var _house = _repo.Single<House>(x => x.HouseID == houseid && x.Handler == loggedonuser.CompanyID);
if (_house == null)
throw new NoAccessException();
var summary = _house.ToSummaryDTO();
var companies = _repo.All<Company>();
var users = _repo.All<User>();
var task = _repo.Single<HouseTask>
(x => x.HouseID == _house.HouseID && x.TaskID == taskid && (x.CompanyID == loggedonuser.CompanyID));
var dto = new TaskDTO
{
TaskID = task.TaskID,
Title = task.Title,
Description = task.Description,
DateCreated = task.DateCreated,
IsClosed = task.IsClosed,
CompanyID = companies.Where(y => task.CompanyID == y.CompanyID).SingleOrDefault().Identifier,
};
if (task.DueDate.HasValue)
dto.DueDate = task.DueDate.Value;
var comments = _repo.All<HouseTaskComment>()
.Where(x => x.TaskID == task.TaskID)
.OrderByDescending(x => x.Timestamp)
.Select(x => new TaskCommentDTO
{
Comment = x.Comment,
Timestamp = x.Timestamp,
CompanyID = companies.Where(y => x.CompanyID == y.CompanyID).SingleOrDefault().Identifier,
UserID = users.Where(y => x.UserID == y.UserID).SingleOrDefault().Login,
Type = EnumHelper.Convert<TaskCommentType>(x.Type)
});
dto.AllComments = comments;
return View(new TaskViewModel
{
Summary = summary,
TaskDetail = dto,
NewComment = new TaskCommentDTO()
});
}
简而言之-获取摘要的房屋详细信息,获取任务详细信息(从多个可用任务中)并获取任务评论。恕我直言,这是一个简单的观点,没什么太复杂的。
此时用户可以: 添加评论、关闭/打开任务 - 如果他们有权这样做(为简单起见省略了代码)、设置任务截止日期,甚至清除任务的截止日期。
现在UpdateTaskStatus - 如果不能更新状态必须返回上面的视图,类似于评论,如果你不能评论请返回详细视图——评论可能被关闭。
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult TaskDueDate(int houseid, int taskid)
{
var duedate = Request.Form["duedate"];
var duetime = Request.Form["duetime"];
try
{
if (ModelState.IsValid)
{
var newduedate = DateHelper.GoodDate(duedate, duetime);
_service.SetTaskDueDate(houseid, taskid, newduedate);
return RedirectToAction("TaskDetail");
}
}
catch (RulesException ex)
{
ex.CopyTo(ModelState);
}
var loggedonuser = _repo.GetCurrentUser();
var _house = _repo.Single<House>(x => x.InstructionID == houseid && x.HandlerID == loggedonuser.CompanyID);
if (_house == null)
throw new NoAccessException();
var summary = _house.ToSummaryDTO();
var companies = _repo.All<Company>();
var users = _repo.All<User>();
var task = _repo.Single<HouseTask>
(x => x.InstructionID == _house.HouseID && x.CompanyID == loggedonuser.CompanyID && x.TaskID == taskid);
var dto = new TaskDTO
{
TaskID = task.TaskID,
Title = task.Title,
Description = task.Description,
DateCreated = task.DateCreated,
IsClosed = task.IsClosed,
CompanyID = companies.Where(y => task.CompanyID == y.CompanyID).SingleOrDefault().Identifier
};
if (task.DueDate.HasValue)
dto.DueDate = task.DueDate.Value;
var comments = _repo.All<HouseTaskComment>()
.Where(x => x.TaskID == task.TaskID)
.OrderByDescending(x => x.Timestamp)
.Select(x => new TaskCommentDTO
{
Comment = x.Comment,
Timestamp = x.Timestamp,
CompanyID = companies.Where(y => x.CompanyID == y.CompanyID).SingleOrDefault().Identifier,
UserID = users.Where(y => x.UserID == y.UserID).SingleOrDefault().Login
});
dto.AllComments = comments;
return View("TaskDetail", new TaskViewModel
{
Summary = summary,
TaskDetail = dto,
NewComment = new TaskCommentDTO()
});
}
我知道上面的代码结构很糟糕,但是对于如何纠正它的一些建议将不胜感激。
- 我将所有只读代码留在操作中,因为每个视图可能不同,我不希望服务层干扰这里
- 我想“保护”我的更新/编辑并将其保存在我的服务层或核心项目(单独的 c# 类库)甚至域层中,我将如何编写代码处理验证,(这是我在服务中所做的调用),执行实际保存?
我听说过 CommandHandler 方法,这是一个好方法吗?理想情况下,我想在我的域中使用一种简单的方法而不是控制器操作来保持我的验证+持久性....