ASP。NET MVC -服务层控制器

时间:2020-12-13 16:34:32

Let's say you're implementing your own version of * (once again, yes)

假设您正在实现自己的*版本(再说一遍,yes)

You have a service that provides all the required functionality like this:

您的服务提供了所有必要的功能,如:

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

interface I*Service
{
    void PostQuestion(Question question);
    void PostAnswer(Answer answer);
    void UpdateQuestion(Question question);
    ...
}

That seems to be pretty simple and generally I believe it's a good idea. The only thing that I don't like here is that client code (ASP.NET MVC controllers) has direct access to Questions and Answers. Pretend we have some tough BL related with posting questions and answers. It's good idea to have this logic concentrated in a "single place" - on a service layer. In case your client code has access to Questions, it's possible that someday somebody will decide to add "just a little bit of logic" to one of your controllers which is basically bad idea.

这看起来很简单,一般来说我认为这是个好主意。我唯一不喜欢的是客户端代码(ASP)。NET MVC控制器)可以直接访问问题和答案。假设我们有一些关于张贴问题和答案的强硬的BL。最好将这种逻辑集中在“单个位置”——服务层上。如果你的客户端代码有访问问题的权限,有可能某天有人会决定给你的一个控制器添加“一点点逻辑”,这基本上是一个坏主意。

I'm thinking about defining a number of DTOs which will be the part of service interface, so the client code will only be able to work with these DTOs that contain "just the right amount of details".

我正在考虑定义一些dto,这些dto将是服务接口的一部分,因此客户端代码将只能使用这些dto,这些dto包含“适当的细节”。

Let's say your question entity is defined like this:

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

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; }
    ...
}

When posting the question, the request should only contain Title, Text and Poster. So, I'll define a PostQuestionDTO:

在发布问题时,请求应该只包含标题、文本和海报。我定义一个PostQuestionDTO:

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

When somebody opens the page to check the question, there's a little bit more details like Posted and Edited:

当有人打开页面查看问题时,会有更多的细节,如发布和编辑:

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

And so on. Is it a good practice or do you think it's overengineering? What are the common approaches here?

等等。这是一个好习惯还是你认为这是过度设计?这里常见的方法是什么?

1 个解决方案

#1


1  

I've recently implemented pretty much exactly what you're talking about, using a lot of Ninject and AutoMapper. My logical structure is like this:

我最近使用了大量的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.

I don't think it's overkill at all - yes, it takes a little longer to write, but AutoMapper basically removes most of the donkey work for you.

我认为这一点都不过分——是的,写起来要花一些时间,但是AutoMapper基本上会删除你的大部分工作。

A colleague of mine is very keen on Inversion of Control, which apparently solves this problem... though I'm not completely sold on it yet :)

我的一个同事非常热衷于控制倒置,这显然解决了这个问题……虽然我还没有完全相信它:)

#1


1  

I've recently implemented pretty much exactly what you're talking about, using a lot of Ninject and AutoMapper. My logical structure is like this:

我最近使用了大量的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.

I don't think it's overkill at all - yes, it takes a little longer to write, but AutoMapper basically removes most of the donkey work for you.

我认为这一点都不过分——是的,写起来要花一些时间,但是AutoMapper基本上会删除你的大部分工作。

A colleague of mine is very keen on Inversion of Control, which apparently solves this problem... though I'm not completely sold on it yet :)

我的一个同事非常热衷于控制倒置,这显然解决了这个问题……虽然我还没有完全相信它:)