【asp.net core 系列】6 实战之 一个项目的完整结构
0. 前言
在《asp.net core 系列》之前的几篇文章中,我们简单了解了路由、控制器以及视图的关系以及静态资源的引入,让我们对于asp.net core mvc项目有了基本的认识。不过,这些并不是 asp.net core mvc项目的全部内容,剩下的内容我将结合实战项目为大家讲解其中的知识。现在,就让我们开始吧。
1. 项目构建
抛开之前的项目,现在跟着我重新创建一个项目,第一步依旧是先创建一个解决方案:
dotnet new sln --name Template
我先介绍一下这个项目(指整个项目,不是单独的asp.net core 应用),这是一个后台管理的模板应用,提供了常见后台系统(管理员端)的功能,包括员工管理、部门管理、角色管理等功能。
现在回到项目中,通常一个项目需要一个模型层,一个数据提供层以及web展示层。然后,我们依次创建 Data、Domain、Web 三个项目,其中Data和Domain 是 classlib,Web是mvc项目。
# 确保当前目录与 Template.sln 处于相同的目录
dotnet new classlib --name Data
dotnet new classlib --name Domain
dotnet new mvc --name Web
添加三个项目到解决方案中:
dotnet sln add Data
dotnet sln add Domain
dotnet sln add Web
因为Data 中存放着模型层,所以需要其他项目对它有一个引用:
cd Domain
dotnet add reference ../Data
cd ../Web
dotnet add reference ../Data
当然,实际开发中我们应当还有一个Service层,这一层用来存放业务代码,减少控制器里不必要的业务代码。那么继续:
# 回到项目的根目录
cd ..
dotnet new classlib --name Service
dotnet sln add Service
然后添加Service的引用:
cd Service
dotnet add reference ../Data
将 Service的引用添加到Web里:
cd ../Web
dotnet add reference ../Service
现在一个大型工程基本都是面向接口编程,几个关键层应当都是接口层,我们实际上还缺少Domain的实现层和Service的实现层。
cd ..
dotnet new classlib --name Domain.Implements
dotnet new classlib --name Service.Implements
在对应的实现层中,引入它们实现的接口层,并引入Data:
cd Domain.Implements
dotnet add reference ../Data
dotnet add reference ../Domain
cd ../Service.Implements
dotnet add reference ../Data
dotnet add reference ../Domain
dotnet add reference ../Service
这里在Service的实现层添加Domain接口层的引用,而不是实现层的引用。这是因为面向接口编程,我们需要对Service实现层隐藏Domain的实现,所以对于Service的实现层来说,不需要关心Domain层的实现逻辑。
在Web中添加新建的两个实现层的引用:
cd ../Web
dotnet add reference ../Domain.Implements
dotnet add reference ../Service.Implements
添加这两个实现层到解决方案中:
cd ..
dotnet sln add Domain.Implements
dotnet sln add Service.Implements
下图是到目前为止的项目结构图:

整体而言,Data是各个层之间的数据流通依据,所以各个项目都依赖于此项目,各个接口层的实现层都只对Web可见,其他各层实际上并不清楚具体实现。
隐藏实现层有什么好处呢?
- 调用方不知道实现方的逻辑,避免调用方对特定实现的依赖
- 有利于团队协作,有的团队是针对模块划分,有的是针对分层划分,无论哪种,使用接口都是一个好的选择
- 有利于后期优化,可以很方便的切换实现层,而不用重新编译过多的代码
当然,并不只有这些好处,不过这样有一个坏处,在web层调用service层时会更繁琐,不过这也不是不可解决的,后续的内容中会为大家介绍如何解决这个烦恼。
2. 项目补充
通常情况下,一个完整的项目还会有一个工具类项目和一个测试项目。所以,继续添加以下项目:
dotnet new classlib --name Utils
Utils 表示工具类,通常一个项目中工具类会比较多,所以就抽成了一个项目,单独列出来。
添加测试项目:
dotnet new nunit --name Test
这里使用的是nunit 3测试框架,当然还有另一个是xunit测试框架。
添加两个项目到解决方案里:
dotnet sln add Utils
dotnet sln add Test
3. 总结
本章内容旨在通过创建项目,让大家了解实际开发中项目的层级规划思想,这并不代表我的就是最优的,只是这是我总结出来相对方便的层级关系。这里并没有讲解如何通过Visual Studio或者Rider创建这样的一个项目,我希望大伙能够自己试试。
好了,希望大家能创建好项目,当然了后期我会给大家提供这个项目的源码的,地址暂时保密哦。
更多内容烦请关注我的博客《高先生小屋》

【asp.net core 系列】6 实战之 一个项目的完整结构的更多相关文章
- ASP.NET Core 系列视频完结,新项目实战课程发布。
今天把MVC的章节完成了,给大家从头到尾做了一个登录注册的示例,带前后端Model验证,算是完整的示例.同时借助于eShopOnContainers的示例也做了一个DBContextSeed的包装器来 ...
- asp.net core系列 59 Ocelot 构建基础项目示例
一.入门概述 从这篇开始探讨Ocelot,Ocelot是一个.NET API网关,仅适用于.NET Core,用于.NET面向微服务/服务的架构中.当客户端(web站点.ios. app 等)访问we ...
- 【目录】asp.net core系列篇
随笔分类 - asp.net core系列篇 asp.net core系列 68 Filter管道过滤器 摘要: 一.概述 本篇详细了解一下asp.net core filters,filter叫&q ...
- 【asp.net core 系列】8 实战之 利用 EF Core 完成数据操作层的实现
0. 前言 通过前两篇,我们创建了一个项目,并规定了一个基本的数据层访问接口.这一篇,我们将以EF Core为例演示一下数据层访问接口如何实现,以及实现中需要注意的地方. 1. 添加EF Core 先 ...
- 【asp.net core 系列】10 实战之ActionFilter
0.前言 在上一篇中,我们提到了如何创建一个UnitOfWork并通过ActionFilter设置启用.这一篇我们将简单介绍一下ActionFilter以及如何利用ActionFilter,顺便补齐一 ...
- WPF中的常用布局 栈的实现 一个关于素数的神奇性质 C# defualt关键字默认值用法 接口通俗理解 C# Json序列化和反序列化 ASP.NET CORE系列【五】webapi整理以及RESTful风格化
WPF中的常用布局 一 写在开头1.1 写在开头微软是一家伟大的公司.评价一门技术的好坏得看具体的需求,没有哪门技术是面面俱到地好,应该抛弃对微软和微软的技术的偏见. 1.2 本文内容本文主要内容 ...
- ASP.NET Core系列(二):创建第一个.Net Core 项目
前面讲过 .NET Core简介及开发环境安装,本章会讲一讲ASP.NET Core 2.0的项目结构,查看完整的ASP.NET Core系列文章:https://www.cnblogs.com/zh ...
- Asp.Net Core 中IdentityServer4 实战之角色授权详解
一.前言 前几篇文章分享了IdentityServer4密码模式的基本授权及自定义授权等方式,最近由于改造一个网关服务,用到了IdentityServer4的授权,改造过程中发现比较适合基于Role角 ...
- 【asp.net core 系列】 1 带你了解一下asp.net core
0. 前言 这是一个新的系列,名字是<ASP.NET Core 入门到实战>.这个系列主讲ASP.NET Core MVC,辅助一些前端的基础知识(能用来实现我们需要的即可,并非主讲).同 ...
随机推荐
- HttpServletRequest 和 HttpServletResponse详解
用HttpServletRequest,现在整理如下,以便以后查阅 请求与响应相关的类和接口非常多,下表是主要的与请求和接口相关的类以及接口. 主要的与请求和接口相关的类及接口 方 法 说 ...
- Appium自动化(10) - appium高级元素定位方式之 UI Automator API 的详解
如果你还想从头学起Appium,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1693896.html 前言 前面介绍过根据id,clas ...
- python之Python内置函数一览表
Python 解释器自带的函数叫做内置函数,这些函数可以直接使用,不需要导入某个模块. 如果你熟悉 Shell 编程,了解什么是 Shell 内置命令,那么你也很容易理解什么是 Python 内置函数 ...
- node的http模块
node中的几个常用核心模块的api返回的都是eventEmitter的实例,也就是说都继承了on和emit方法,用以监听事件并触发回调来处理事件. http模块处理网络请求通常是创建一个server ...
- ESlint中console.log报错问题
ESlint中console.log报错问题 由于ESlint规范化,导致console.log的使用也会报错,下面是设置允许console.log控制台输出 描述:打开 package.json 文 ...
- mysql基本操作汇总
1.数据库操作 (1)创建数据库 CREATE DATABASE <数据库名>; 例子: CREATE DATABASE IF NOT EXISTS RUNOOB DEFAULT CHAR ...
- MySQL(4)— 数据查询
四.数据查询(DQL) 4-1.查询指定字段 select 完整 语法: select [distinct] 字段名1 [as] [别名],字段名2 [as] [别名] from 表1 [ left ...
- Poj2109 (1) k^n = p.
看到1<=p<10101 ,就去想大数操作了,后来看了discuss原来double完全可以放. 类型 长度 (bit) 有效数字 ...
- spring的动态代理实现
Host.java package cn.zys.dynamiproxy; public class Host implements Rent{ public void rent(){ System. ...
- Redis学习笔记(3)
一.Redis的事务(transaction) 1. 事务概念 本质:本质是一组命令的集合,所有的命令按照顺序一次性.串行化地执行,不允许其他命令的加入.Redis通过MULTI.EXEC.WATCH ...