asp.net mvc post request + service layer-最好的方法

时间:2011-08-04 13:27:43

标签: c# linq-to-sql asp.net-mvc-2 design-patterns domain-model

让我们说我想发布一个帖子请求来更新房子的状态,理想情况下这些数据应该在某种服务层,通常这涉及到

  1. 验证用户 - 他们是否仍处于活动状态或被管理员踢出?
  2. 检查houseid - houseid /记录有效吗?
  3. 用户可以查看房屋详细信息吗?
  4. 将状态更新为“打开”或“关闭”
  5. 在现实世界/复杂领域 - 大多数观点都非常复杂,我们不得不抛弃该地区的房屋数量,房屋的评论数量,房屋的详细信息等,也许是未完成任务的数量在房子里......

    简而言之 - 以上所有代码都可能位于服务层内,但是假设引发异常,用户无法更新房屋状态 - 现在要填充视图,首先要获取房屋详细信息(再次),加载你刚刚加载到服务层内的所有其他东西控制器内的所有内容或另一个装修到加载这些数据的服务层......

    如何通过运行验证和所有排序来确保我的域模型受到保护,而无需多次重写相同的代码......

    此代码位于action方法内部,可以很容易地位于服务层内......

    //注意:_repo是一个简单的抽象,超过linq到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()
        });
    }
    

    我知道上面的代码结构很糟糕,但是对于如何纠正它的一些建议将不胜感激。

    1. 我在动作中留下所有只读代码,因为每个视图可能不同,我不希望服务层干扰这里
    2. 我想“保护”我的更新/编辑并将其保存在我的服务层或核心项目(单独的c#class lib)或甚至是Domain层中,我将如何编写代码句柄验证,(这就是我所做的)在服务电话里面),执行实际保存?
    3. 我听说过CommandHandler方法,这是一个好方法吗?理想情况下,我希望在我的域内使用一种简单的方法而不是控制器操作来保持我的验证+持久性......

2 个答案:

答案 0 :(得分:7)

答案 1 :(得分:0)

您是否可以从标准FaultException继承并向HouseDTO类型添加HouseDetails属性?