简体   繁体   English

需要有关ASP.NET MVC 3体系结构的一些指南

[英]Some guidance on ASP.NET MVC 3 architecture required

I am an experienced .NET developer who has primarily been working with webforms. 我是一位经验丰富的.NET开发人员,主要从事Web表单的开发。 I am familiar with MVC but have not used it commercially yet. 我熟悉MVC,但尚未在商业上使用过。 I am currently conducting some self-education in this area and am somewhat confused by the differences in opinion on the subject of architecture, let me prefix this question with the understanding that there is not a right or wrong answer but I am simply seeking what is an elegant solution. 我目前正在这方面进行一些自我教育,但对建筑学的观点分歧感到有些困惑,让我以没有正确或错误答案为前提的这个问题作为前缀,而我只是在寻求什么。一个优雅的解决方案。

I will start out by saying that I am not using the entity framework or any sort of ORM – I would like to directly implement my own business objects and data access code (using ADO, SPROCS etc) to ensure they are optimal, this is a personal preference. 首先,我不会使用实体框架或任何类型的ORM,我想直接实现自己的业务对象和数据访问代码(使用ADO,SPROCS等)以确保它们是最佳的,这是个人喜好。 This is where I am struggling to find consistent information as it appears most information relates to the use of LINQ to SQL or the Entity Framework. 这是我在努力寻找一致信息的地方,因为看起来大多数信息与LINQ to SQL或实体框架的使用有关。

MY application has been structured with the following projects: 我的应用程序由以下项目构成:

  • Web (MVC 3 Web application) Web(MVC 3 Web应用程序)
  • Models (class library) 模型(类库)

There are only two projects because I am having issues decoupling things; 只有两个项目,因为我在解决问题上存在问题。 this is the root of my question. 这是我问题的根源。 My model class library contains… 我的模型类库包含…

  • classic business objects with fields and properties 具有字段和属性的经典业务对象
  • A repository class for each business object which contains data access code (ADO.NET straight forward SqlDataReaders etc) 每个业务对象的存储库类,其中包含数据访问代码(ADO.NET直接SqlDataReaders等)
  • An interface for each repository class 每个存储库类的接口

The issue I have is the dependency between all these layers. 我遇到的问题是所有这些层之间的依赖关系。 It does not feel right at all! 感觉根本不对!

1.The business objects should contain methods that implement the business logic, so aside from the fields and properties there are methods to implement any required logic? 1.业务对象应包含实现业务逻辑的方法,因此,除了字段和属性外,还有实现所需逻辑的方法吗?

2.The repository classes execute data access code but know about the business objects, this again does not feel right, the data access code should sit in its own class library and know nothing about the objects? 2.存储库类执行数据访问代码,但知道业务对象,这又感觉不对,数据访问代码应位于其自己的类库中,而对对象一无所知?

3.The controllers (in the web layer) leverage the repository interfaces but why? 3.控制器(在Web层中)利用存储库接口,但是为什么呢? They should not contain business logic, the 'model' or business object should? 它们不应该包含业务逻辑,“模型”或业务对象应该吗? The controllers should certainly not contain business logic so again this is not right. 控制器当然不应该包含业务逻辑,所以这又是不对的。 I don't want business logic in repositories as they are hitting the database. 我不希望存储库中的业务逻辑进入数据库。

I am struggling to find an elegant architecture for the application, just a basic outline of how to implement my own objects, my own data access code and ensure the application is loosely coupled. 我正在努力为应用程序找到一个优雅的体系结构,只是如何实现自己的对象,我自己的数据访问代码以及确保应用程序松散耦合的基本概述。 Can anyone offer me any guidance please? 有人可以给我任何指导吗?

I would suggest a few changes to your solution structure. 我建议对您的解决方案结构进行一些更改。

For example, the projects could be structured as follows:- 例如,项目的结构可以如下:

Core Library 核心图书馆

This would be simple POCO's that represent your domain data and interfaces to any services. 这将是简单的POCO,代表您的域数据和任何服务的接口。 There is no business logic here. 这里没有业务逻辑。 Just simple properties. 只是简单的属性。

eg. 例如。

public class User { public int UserId { get; 公共类User {public int UserId {get; set; 组; } public string Name { get; } public string Name {get; set; 组; } } }}

- Core
      \Entities <-- Poco's
      \Services <-- Interfaces for services

Services 服务

This would be where you contain your business logic. 这就是您包含业务逻辑的地方。 How does a user validate? 用户如何验证? How do we calculate when a Order should be auto-archived or whatever? 我们如何计算何时应该自动归档订单? Generally, I don't do any database stuff in here. 通常,我在这里不做任何数据库工作。

Repository 资料库

This is where you do your basic database stuff. 这是您执行基本数据库工作的地方。 You said you're not using L2S or EF, etc. No probs. 您说您没有使用L2S或EF等。没有问题。 I would seriously seriously look at using a Micro-ORM instead, like Dapper or Massive . 我会认真考虑使用Micro-ORM,例如DapperMassive

Tests 测验

You're doing unit and integration tests, right? 您正在进行单元和集成测试,对吗? i recommend xUnit or nUnit for the testing framework. 我建议将xUnit或nUnit用于测试框架。

Web Application Web应用程序

This is the MVC3 application. 这是MVC3应用程序。 I would recommend using StructureMap for your Dependency Injection. 我建议对您的依赖注入使用StructureMap (You are using an IoC/DI, right?) (您正在使用IoC / DI,对吗?)

You might think at first -> that's SOOO many projects, right? 您可能首先想到->这么多项目,对吗? well, it's easy to split this into TWO projects only. 好吧,很容易将其分为两个项目。

  1. Web Application Web应用程序
  2. Test project 测试项目

and the Core Library, Services, Repository all exist in the Web Application project as folders. Web应用程序项目中的核心库,服务,存储库都作为文件夹存在。

Try and not over-engineer the Visual Studio solution. 尝试不要过度设计Visual Studio解决方案。 Most people think they need lots of projects and crap loads of abstraction .. because that's what they think everyone else is doing and it's the right thing. 大多数人认为他们需要大量的项目和大量的抽象工作,..因为那是他们认为其他人都在做的事,这是正确的。 Well, that train of thought is very very early 2000's .. and in 2012 - lots of shiz has changed since then. 好吧,这个思路是在2000年代初期。2012年-自那时以来,许多神志发生了变化。

Try using DI/IoJ, NuGet for downloading these libraries into your solution, Micro-OR/M's for data access and a Testing project. 尝试使用DI / IoJ,使用NuGet将这些库下载到您的解决方案中,使用Micro-OR / M进行数据访问和测试项目。

A few projects to check out, re: how things are layed out : 一些项目要签出,关于:如何布置:

  1. JabbR.net JabbR.net
  2. RavenOverflow RavenOverflow
  1. maybe, if the model requires it. 也许,如果模型需要的话。 most models are simple dtos with public properties. 大多数模型是具有公共属性的简单dto。 but you could just as easily encapsulate some of this. 但是您可以轻松地封装其中的一些内容。

  2. not exactly. 不完全是。 a repository is a collection of business objects. 存储库是业务对象的集合。 it may create instances of these objects from a database. 它可以从数据库创建这些对象的实例。

  3. controllers are the entry point for controlling what happens on the server. 控制器是控制服务器上发生的事情的入口点。 reads would load data from the repositories into view models and push the view models into the view. 读取将把存储库中的数据加载到视图模型中,并将视图模型推入视图中。 writes would load data from repositories, update the domain and save the changes. 写入将从存储库加载数据,更新域并保存更改。 then redirect to a read controller action. 然后重定向到读取控制器操作。

most importantly. 最重要的是。 don't over think the architecture. 不要过度考虑架构。 this happens too much. 这种事情发生得太多了。 devs want clean code and actually make it more complicated to maintain, rather than simpler. 开发人员想要干净的代码,实际上会使维护起来更复杂,而不是更简单。

whether or not you use a database or ORM is irrelevant, you have the same functionality in your repositories. 无论您使用的是数据库还是ORM都无关紧要,存储库中的功能相同。

I think starting small is good and then as the need arises you start widening your view and start separating out layers as you need them. 我认为从小做起是好的,然后随着需求的增长,您开始扩大视野并根据需要将各层分开。 Why separate your work into 20ish projects if you got 2 models, 1 view and a single table to query and update in a database. 如果您有2个模型,1个视图和一个表在数据库中进行查询和更新,为什么要将您的工作分为20个项目。

Start small and let the "need" drive the design. 从小处着手,让“需求”驱动设计。 If you need to read/write lots of tables in a database it might be time now to start using the repository pattern. 如果您需要读取/写入数据库中的许多表,现在可能是时候开始使用存储库模式了。 You find you are now in need of at least 10 or more different models it might be now time to implement a library to contain DTOs/models and take them out of the web application. 您发现您现在至少需要10个或更多个不同的模型,现在可能是时候实现一个包含DTO /模型的库并将其从Web应用程序中删除的时候了。

If you for example require to write unit tests or do TDD you find that being able to mock the repository, business and service layer straight away come in handy. 例如,如果您需要编写单元测试或执行TDD,那么您会发现能够立即模拟存储库,业务和服务层会派上用场。

For the sake of argument though, I have seen projects which had similar to the below (but most will not need that level of separation): 为了便于讨论,我看到了与以下项目相似的项目(但大多数项目不需要这种分离程度):

  • The web project; 网络项目; consuming a service library and dto library 使用服务库和DTO库
  • A service library; 服务库; consuming a business layer library and dto library 消耗业务层库和dto库
  • A business layer library; 业务层库; consuming a repository library, entity library and dto library 消耗存储库库,实体库和dto库
  • A repository library; 存储库; consuming the entity library 消费实体库
  • A entity library 实体库
  • A dto library dto库

Most of those were even further broken down into separate libraries, containing interfaces in one and implementations in another and so on. 其中大多数甚至进一步分解为单独的库,其中一个包含接口,另一个包含实现,依此类推。 Some projects I have worked on had over 50 libraries to separate most if not everything but it was always based on a requirement or need. 我从事过的一些项目有50多个库,即使不是全部,也可以将大多数库分开,但这总是基于需求。

The idea of the above example is to have the web application merely deal with passing DTOs to a service call and receiving DTOs back form a service call. 上面示例的思想是使Web应用程序仅处理将DTO传递到服务调用并从服务调用接收DTO的情况。

You can use the DTOs most of the time as Models but sometimes if you need a flat model based on several DTOs you can create your own view-model as a wrapper to flatten out the multiple DTOs. 您通常可以将DTO用作模型,但是有时如果您需要基于多个DTO的平面模型,则可以创建自己的视图模型作为包装器以平整多个DTO。

The service goes of and call a method in a manager, passing a DTO, which resides in the Business layer library. 该服务将通过驻留在业务层库中的DTO并在管理器中调用方法。 That manager will use the DTO and map it to one or more entities and calls methods on the repository passing those entities. 该经理将使用DTO并将其映射到一个或多个实体,并调用传递这些实体的存储库中的方法。 The repository returns entities which the manager uses to construct the DTO to send back. 存储库返回实体,管理者使用这些实体构造DTO以发回。

There is many ways of doing this and I'm sure not a single one is the only right way. 有很多方法可以做到这一点,我敢肯定,唯一的方法就是唯一的方法。

You can achieve further separation and independence using a dependency injection framework like Ninject for example. 您可以使用诸如Ninject之类的依赖项注入框架来实现进一步的分离和独立性。

The above is merely a single example. 以上仅仅是一个例子。 It might work great for one group of people while another find it unacceptable. 它可能对一组人有用,而另一组人则认为这是不可接受的。 It depends on many factors, the size of the project being one of the main ones. 它取决于许多因素,项目的规模是主要因素之一。

Aside all that though, always start with a manageable sized architecture you will keep re-factoring over and over as the need arises for change, be it to cater for mocking in unit tests, the number of models has become unmanageable within the web application or now a separate team has to write the service layer and you don't want that to interfere with your development, the service layer might now have to be consumed by a different UI layer and not just your web front-end, etc... 除了所有这些之外,总是从可管理的大小的体系结构开始,随着变更的需要,您将不断地进行重构,以适应单元测试中的模拟,Web应用程序中模型的数量变得难以管理或现在需要一个单独的团队来编写服务层,并且您不希望这样做干扰您的开发,现在服务层可能必须由其他UI层使用,而不仅仅是您的Web前端,等等。

A few points: 几点:

  • There is no problem with having 'business logic' in your repositories. 存储库中具有“业务逻辑”没有问题。 In fact most of your 'business logic' is going to be there. 实际上,您的大多数“业务逻辑”都将存在。 Your repositories contain queries, and if those queries are at all interesting then those queries are going to be intimately related to your 'business logic'. 您的存储库中包含查询,如果这些查询非常有趣,那么这些查询将与您的“业务逻辑”紧密相关。

  • There is no problem with having 'business logic' in your controllers. 控制器中具有“业务逻辑”没有问题。 Your controllers are controlling your UI and how your UI works is 'business logic'. 您的控制器正在控制您的UI,并且UI的工作方式是“业务逻辑”。

  • By definition, in a layered architecture each layer is aware of the public interface of the layer above it. 根据定义,在分层体系结构中,每个层都知道其上一层的公共接口。 Your data access can see the public interface of your domain layer. 您的数据访问可以看到您域层的公共接口。 Your UI layer can see the public interface of your service layer. 您的UI层可以看到服务层的公共界面。

  • If your project is so small that you can afford to handcode your own data access layer, rather than use an ORM or similar, then having a fully decoupled Starship Enterprise architecture is probably only going to make your life most difficult. 如果您的项目如此之小,以至于您有能力手动编码自己的数据访问层,而不是使用ORM或类似的代码,那么拥有完全脱钩的Starship Enterprise架构可能只会使您的生活最困难。 (And by this I'm implying that I think you're crazy writing your own data access layer - at least try a light-weight framework like Dapper). (因此,这意味着我认为您疯狂地编写了自己的数据访问层-至少尝试了像Dapper这样的轻量级框架)。

  • Base your choices on your needs. 根据您的需求进行选择。 Ask yourself "Why does X need to be decoupled from Y". 问问自己“为什么X需要与Y解耦”。 The answer may be "So I can mock X out when I'm unit testing Y". 答案可能是“所以我可以在对Y进行单元测试时模拟X”。 The answer may be "So I can use X in my other project that doesn't need to know about Y". 答案可能是“所以我可以在不需要知道Y的其他项目中使用X”。 If you can't find an answer, then YAGNI. 如果找不到答案,请选择YAGNI。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM