【问题标题】:ASP.NET MVC - Service Layer <-> ControllersASP.NET MVC - 服务层 <-> 控制器
【发布时间】:2012-01-10 01:42:40
【问题描述】:

假设您正在实现自己的 stackoverflow 版本(再次,是的)

您的服务提供了所有必需的功能,如下所示:

class Question { ... } // EF entity
class Answer { ... } // EF entity

interface IStackoverflowService
{
    void PostQuestion(Question question);
    void PostAnswer(Answer answer);
    void UpdateQuestion(Question question);
    ...
}

这似乎很简单,总的来说我认为这是个好主意。我在这里唯一不喜欢的是客户端代码(ASP.NET MVC 控制器)可以直接访问Questions 和Answers。假装我们有一些与发布问题和答案有关的强硬 BL。将这个逻辑集中在一个“单一的地方”——在服务层上是个好主意。如果您的客户端代码可以访问Questions,那么有一天有人可能会决定向您的一个控制器添加“一点点逻辑”,这基本上是个坏主意。

我正在考虑定义一些 DTO,它们将成为服务接口的一部分,因此客户端代码将只能使用这些包含“恰到好处的详细信息”的 DTO。

假设您的问题实体是这样定义的:

interface Question
{
    int Id { get; set; }
    User Poster { get; set; }
    DateTime Posted { get; set; }
    DateTime? Edited { get; set; }
    string Title { get; set; }
    string Text { get; set; }
    IQueryable<Answer> Answers { get; set; }
    ...
}

发布问题时,请求应仅包含TitleTextPoster。所以,我会定义一个PostQuestionDTO

class PostQuestionDTO
{
    User Poster { get; set; }
    string Title { get; set; }
    string Text { get; set; }
}

当有人打开页面查看问题时,会有更多详细信息,例如 PostedEdited

class QuestionDetailsDTO
{
    User Poster { get; set; }
    string Title { get; set; }
    string Text { get; set; }
    DateTime Posted { get; set; }
    DateTime? Edited { get; set; }
}

等等。这是一个好的做法还是你认为它过度设计?这里有哪些常用的方法?

【问题讨论】:

  • 实施 DTO 并不能阻止人们向控制器“添加一点逻辑”。 MVC 是它自己的范例,我希望人们能够意识到这一点并停止尝试添加 n 层概念。
  • 问题不在于MVC,而在于“MVC + BL”中的“+”符号
  • 控制器应该包含关于作为控制器一部分的动作的业务逻辑,模型应该封装其他业务逻辑。除非您需要连接到 WCF 或其他服务来访问您的数据,在这种情况下,您可以将其封装在 EF 中。不需要在单独的程序集中使用 PL/BL/DL 的 n 层 BL 抽象。 MVC 模式非常清楚什么去哪里。

标签: asp.net-mvc controller dto service-layer


【解决方案1】:

我最近使用了大量的 Ninject 和 AutoMapper 几乎完全实现了您所说的内容。我的逻辑结构是这样的:

    MyCompany.Data // Data layer namespace containing EF EDMX file / Codefirst / ADO.Net, whatever you want.
    class User { } // EF Entity

MyCompany.Business // Business layer namespace containing business level factory interfaces and classes that expose their own business objects (some are directly mapped to the DB, most are not). All members expose POCO objects

class NewUser { } // POCO class RegisteredUser { } // POCO interface IAccountFactory {
    void AddUser(NewUser user);
    RegisteredUser GetUser(int id); } // factory interface class AccountFactory : IAccountFactory // Service provider

MyCompany.MVC // Presentation layer containing controllers and views. Controllers expose POCO objects from the business layer to the Views.

我一点也不认为它是矫枉过正的——是的,它需要更长的时间来编写,但 AutoMapper 基本上为你删除了大部分的工作。

我的一个同事非常热衷于控制反转,这显然解决了这个问题......虽然我还没有完全接受它:)

【讨论】:

    猜你喜欢
    • 2012-03-09
    • 1970-01-01
    • 2012-11-08
    • 1970-01-01
    • 1970-01-01
    • 2021-03-19
    • 2014-02-19
    • 1970-01-01
    • 2012-06-01
    相关资源
    最近更新 更多