这里有新鲜出炉的精品教程, 程序狗速度看过来!
ASP.NET
ASP.NET 是. NET FrameWork 的一部分, 是一项微软公司的技术, 是一种使嵌入网页中的脚本可由因特网服务器执行的服务器端脚本技术, 它可以在通过 HTTP 请求文档时再在 web 服务器上动态创建它们 指 Active Server Pages(动态服务器页面) , 运行于 IIS(Internet Information Server 服务, 是 Windows 开发的 Web 服务器)之中的程序
ABP 是为新的现代 Web 应用程序使用最佳实践和使用最流行工具的一个起点可作为一般用途的应用程序的基础框架或项目模板接下来通过本文给大家详细介绍 ABP 入门教程, 感兴趣的朋友一起看看吧
ABP 是 ASP.NET Boilerplate Project (ASP.NET 样板项目)的简称
ASP.NET Boilerplate 是一个用最佳实践和流行技术开发现代 WEB 应用程序的新起点, 它旨在成为一个通用的 WEB 应用程序框架和项目模板
ABP 的官方网站: http://www.aspnetboilerplate.com
ABP 在 Github 上的开源项目: https://github.com/aspnetboilerplate
ABP 的由来
DRY 避免重复代码是一个优秀的开发者在开发软件时所具备的最重要的思想之一我们在开发企业 WEB 应用程序时都有一些类似的需求, 例如: 都需要登录页面用户 / 角色管理权限验证数据有效性验证多语言 / 本地化等等一个高品质的大型软件都会运用一些最佳实践, 例如分层体系结构领域驱动设计依赖注入等我们也可能会采用 ORM 数据库迁移 (Database Migrations) 日志记录 (Logging) 等工具
从零开始创建一个企业应用程序是一件繁琐的事, 因为需要重复做很多常见的基础工作许多公司都在开发自己的应用程序框架来重用于不同的项目, 然后在框架的基础上开发一些新的功能但并不是每个公司都有这样的实力假如我们可以分享的更多, 也许可以避免每个公司或每个项目的重复编写类似的代码作者之所以把项目命名为 ASP.NET Boilerplate, 就是希望它能成为开发一般企业 WEB 应用的新起点, 直接把 ABP 作为项目模板
ABP 是什么?
ABP 是为新的现代 Web 应用程序使用最佳实践和使用最流行工具的一个起点可作为一般用途的应用程序的基础框架或项目模板它的功能包括:
服务器端:
基于最新的. NET 技术 (目前是 ASP.NET MVC 5Web API 2C# 5.0, 在 ASP.NET 5 正式发布后会升级)
实现领域驱动设计(实体仓储领域服务领域事件应用服务数据传输对象, 工作单元等等)
实现分层体系结构 (领域层, 应用层, 展现层和基础设施层) 提供了一个基础架构来开发可重用可配置的模块集成一些最流行的开源框架 / 库, 也许有些是你正在使用的
提供了一个基础架构让我们很方便地使用依赖注入(使用 Castle Windsor 作为依赖注入的容器)
提供 Repository 仓储模式支持不同的 ORM(已实现 Entity Framework NHibernateMangoDb 和内存数据库)
支持并实现数据库迁移 (EF 的 Code first) 模块化开发(每个模块有独立的 EF DbContext, 可单独指定数据库)
包括一个简单的和灵活的多语言 / 本地化系统
包括一个 EventBus 来实现服务器端全局的领域事件统一的异常处理(应用层几乎不需要处理自己写异常处理代码)
数据有效性验证(Asp.NET MVC 只能做到 Action 方法的参数验证, ABP 实现了 Application 层方法的参数有效性验证)
通过 Application Services 自动创建 Web Api 层(不需要写 ApiController 层了)
提供基类和帮助类让我们方便地实现一些常见的任务
使用约定优于配置原则
客户端:
BootstrapLessAngularJsjQueryModernizr 和其他 JS 库: jQuery.validatejQuery.formjQuery.blockUIjson2 等
为单页面应用程序 (AngularJsDurandaljs) 和多页面应用程序 (Bootstrap+Jquery) 提供了项目模板
自动创建 Javascript 的代理层来更方便使用 Web Api 封装一些 Javascript 函数, 更方便地使用 ajax 消息框通知组件忙状态的遮罩层等等
除 ABP 框架项目以外, 还开发了名叫 Zero 的模块, 实现了以下功能:
身份验证与授权管理(通过 ASP.NET Identity 实现的)
用户 & 角色管理系统设置存取管理(系统级租户级用户级, 作用范围自动管理)
审计日志(自动记录每一次接口的调用者和参数)
ABP 不是什么?
ABP 提供了一个应用程序开发模型用于最佳实践它拥有基础类接口和工具使我们容易建立起可维护的大规模的应用程序
然而:
它不是 RAD 工具之一, RAD 工具的目的是无需编码创建应用程序相反, ABP 提供了一种编码的最佳实践
它不是一个代码生成工具在运行时虽然它有一些特性构建动态代码, 但它不能生成代码
它不是一个一体化的框架相反, 它使用流行的工具 / 库来完成特定的任务(例如用 EF 做 ORM, 用 Log4Net 做日志记录, 使得 Castle Windsor 作为赖注入容器, AngularJs 用于 SPA 框架)
就我使用了 ABP 几个月的经验来看, 虽然 ABP 不是 RAD, 但是用它开发项目绝对比传统三层架构要快很多
虽然 ABP 不是代码生成工具, 但因为有了它, 使我们项目的代码更简洁规范, 这有利于使用代码生成工具
我自己使用 VS2013 的 Scaffolder+T4 开发的代码生成器, 可根据领域对象的 UML 类图自动生成全部前后端代码和数据库, 简单的 CURD 模块几乎不需要编写代码, 有复杂业务逻辑的模块主要补充领域层代码即可这样就能把时间多花在领域模型的设计上, 减少写代码的时间
下面通过原作者的简单任务系统例子, 演示如何运用 ABP 开发项目
从模板创建空的 web 应用程序
ABP 提供了一个启动模板用于新建的项目(尽管你能手动地创建项目并且从 nuget 获得 ABP 包, 模板的方式更容易)
转到 www.aspnetboilerplate.com/Templates 从模板创建你的应用程序
你可以选择 SPA(AngularJs 或 DurandalJs)或者选择 MPA(经典的多页面应用程序)项目可以选择 Entity Framework 或 NHibernate 作为 ORM 框架
这里我们选择 AngularJs 和 Entity Framework, 填入项目名称 SimpleTaskSystem, 点击 CREATE MY PROJECT 按钮可以下载一个 zip 压缩包, 解压后得到 VS2013 的解决方案, 使用的. NET 版本是 4.5.1
每个项目里引用了 Abp 组件和其他第三方组件, 需要从 Nuget 下载
黄色感叹号图标, 表示这个组件在本地文件夹中不存在, 需要从 Nuget 上还原操作如下:
要让项目运行起来, 还得创建一个数据库这个模板假设你正在使用 SQL2008 或者更新的版本当然也可以很方便地换成其他的关系型数据库
打开 Web.Config 文件可以查看和配置链接字符串:
- <add name="Default" connectionString="Server=localhost; Database=SimpleTaskSystemDb; Trusted_Connection=True;" />
- (在后面用到 EF 的 Code first 数据迁移时, 会自动在 SQL Server 数据库中创建一个名为 SimpleTaskSystemDb 的数据库)
就这样, 项目已经准备好运行了! 打开 VS2013 并且按 F5:
下面将逐步实现这个简单的任务系统程序
创建实体
把实体类写在 Core 项目中, 因为实体是领域层的一部分
一个简单的应用场景: 创建一些任务 (tasks) 并分配给人 我们需要 Task 和 Person 这两个实体
Task 实体有几个属性: 描述 (Description) 创建时间 (CreationTime) 任务状态 (State), 还有可选的导航属性(AssignedPerson) 来引用 Person
- public class Task : Entity<long>
- {
- [ForeignKey("AssignedPersonId")]
- public virtual Person AssignedPerson { get; set; }
- public virtual int? AssignedPersonId { get; set; }
- public virtual string Description { get; set; }
- public virtual DateTime CreationTime { get; set; }
- public virtual TaskState State { get; set; }
- public Task()
- {
- CreationTime = DateTime.Now;
- State = TaskState.Active;
- }
- }
Person 实体更简单, 只定义了一个 Name 属性:
- public class Person : Entity
- {
- public virtual string Name { get; set; }
- }
在 ABP 框架中, 有一个 Entity 基类, 它有一个 Id 属性因为 Task 类继承自 Entity<long>, 所以它有一个 long 类型的 IdPerson 类有一个 int 类型的 Id, 因为 int 类型是 Entity 基类 Id 的默认类型, 没有特别指定类型时, 实体的 Id 就是 int 类型
创建 DbContext
使用 EntityFramework 需要先定义 DbContext 类, ABP 的模板已经创建了 DbContext 文件, 我们只需要把 Task 和 Person 类添加到 IDbSet, 请看代码:
- public class SimpleTaskSystemDbContext : AbpDbContext
- {
- public virtual IDbSet<Task> Tasks { get; set; }
- public virtual IDbSet<Person> People { get; set; }
- public SimpleTaskSystemDbContext()
- : base("Default")
- {
- }
- public SimpleTaskSystemDbContext(string nameOrConnectionString)
- : base(nameOrConnectionString)
- {
- }
- }
通过 Database Migrations 创建数据库表
我们使用 EntityFramework 的 Code First 模式创建数据库架构 ABP 模板生成的项目已经默认开启了数据迁移功能, 我们修改 SimpleTaskSystem.EntityFramework 项目下 Migrations 文件夹下的 Configuration.cs 文件:
- internal sealed class Configuration : DbMigrationsConfiguration<SimpleTaskSystem.EntityFramework.SimpleTaskSystemDbContext>
- {
- public Configuration()
- {
- AutomaticMigrationsEnabled = false;
- }
- protected override void Seed(SimpleTaskSystem.EntityFramework.SimpleTaskSystemDbContext context)
- {
- context.People.AddOrUpdate(
- p => p.Name,
- new Person {Name = "Isaac Asimov"},
- new Person {Name = "Thomas More"},
- new Person {Name = "George Orwell"},
- new Person {Name = "Douglas Adams"}
- );
- }
- }
在 VS2013 底部的程序包管理器控制台窗口中, 选择默认项目并执行命令 Add-Migration InitialCreate
会在 Migrations 文件夹下生成一个 xxxx-InitialCreate.cs 文件, 内容如下:
- public partial class InitialCreate : DbMigration
- {
- public override void Up()
- {
- CreateTable(
- "dbo.StsPeople",
- c => new
- {
- Id = c.Int(nullable: false, identity: true),
- Name = c.String(),
- })
- .PrimaryKey(t => t.Id);
- CreateTable(
- "dbo.StsTasks",
- c => new
- {
- Id = c.Long(nullable: false, identity: true),
- AssignedPersonId = c.Int(),
- Description = c.String(),
- CreationTime = c.DateTime(nullable: false),
- State = c.Byte(nullable: false),
- })
- .PrimaryKey(t => t.Id)
- .ForeignKey("dbo.StsPeople", t => t.AssignedPersonId)
- .Index(t => t.AssignedPersonId);
- }
- public override void Down()
- {
- DropForeignKey("dbo.StsTasks", "AssignedPersonId", "dbo.StsPeople");
- DropIndex("dbo.StsTasks", new[] { "AssignedPersonId" });
- DropTable("dbo.StsTasks");
- DropTable("dbo.StsPeople");
- }
- }
然后继续在程序包管理器控制台执行 Update-Database, 会自动在数据库创建相应的数据表:
PM> Update-Database
数据库显示如下:
(以后修改了实体, 可以再次执行 Add-Migration 和 Update-Database, 就能很轻松的让数据库结构与实体类的同步)
定义仓储接口
通过仓储模式, 可以更好把业务代码与数据库操作代码更好的分离, 可以针对不同的数据库有不同的实现类, 而业务代码不需要修改
定义仓储接口的代码写到 Core 项目中, 因为仓储接口是领域层的一部分
我们先定义 Task 的仓储接口:
- public interface ITaskRepository : IRepository<Task, long>
- {
它继承自 ABP 框架中的 IRepository 泛型接口
在 IRepository 中已经定义了常用的增删改查方法:
所以 ITaskRepository 默认就有了上面那些方法可以再加上它独有的方法 GetAllWithPeople(...)
不需要为 Person 类创建一个仓储类, 因为默认的方法已经够用了 ABP 提供了一种注入通用仓储的方式, 将在后面创建应用服务一节的 TaskAppService 类中看到
实现仓储类
我们将在 EntityFramework 项目中实现上面定义的 ITaskRepository 仓储接口
通过模板建立的项目已经定义了一个仓储基类: SimpleTaskSystemRepositoryBase(这是一种比较好的实践, 因为以后可以在这个基类中添加通用的方法)
- public class TaskRepository : SimpleTaskSystemRepositoryBase<Task, long>, ITaskRepository
- {
- public List<Task> GetAllWithPeople(int? assignedPersonId, TaskState? state)
- {
- // 在仓储方法中, 不用处理数据库连接 DbContext 和数据事务, ABP 框架会自动处理
- var query = GetAll(); //GetAll() 返回一个 IQueryable<T > 接口类型
- // 添加一些 Where 条件
- if (assignedPersonId.HasValue)
- {
- query = query.Where(task => task.AssignedPerson.Id == assignedPersonId.Value);
- }
- if (state.HasValue)
- {
- query = query.Where(task => task.State == state);
- }
- return query
- .OrderByDescending(task => task.CreationTime)
- .Include(task => task.AssignedPerson)
- .ToList();
- }
- }
TaskRepository 继承自 SimpleTaskSystemRepositoryBase 并且实现了上面定义的 ITaskRepository 接口
创建应用服务(Application Services)
在 Application 项目中定义应用服务首先定义 Task 的应用服务层的接口:
- public interface ITaskAppService : IApplicationService
- {
- GetTasksOutput GetTasks(GetTasksInput input);
- void UpdateTask(UpdateTaskInput input);
- void CreateTask(CreateTaskInput input);
- }
ITaskAppService 继承自 IApplicationService,ABP 自动为这个类提供一些功能特性(比如依赖注入和参数有效性验证)
然后, 我们写 TaskAppService 类来实现 ITaskAppService 接口:
- public class TaskAppService : ApplicationService, ITaskAppService
- {
- private readonly ITaskRepository _taskRepository;
- private readonly IRepository<Person> _personRepository;
- /// <summary>
- /// 构造函数自动注入我们所需要的类或接口
- /// </summary>
- public TaskAppService(ITaskRepository taskRepository, IRepository<Person> personRepository)
- {
- _taskRepository = taskRepository;
- _personRepository = personRepository;
- }
- public GetTasksOutput GetTasks(GetTasksInput input)
- {
- // 调用 Task 仓储的特定方法 GetAllWithPeople
- var tasks = _taskRepository.GetAllWithPeople(input.AssignedPersonId, input.State);
- // 用 AutoMapper 自动将 List<Task > 转换成 List<TaskDto>
- return new GetTasksOutput
- {
- Tasks = Mapper.Map<List<TaskDto>>(tasks)
- };
- }
- public void UpdateTask(UpdateTaskInput input)
- {
- // 可以直接 Logger, 它在 ApplicationService 基类中定义的
- Logger.Info("Updating a task for input:" + input);
- // 通过仓储基类的通用方法 Get, 获取指定 Id 的 Task 实体对象
- var task = _taskRepository.Get(input.TaskId);
- // 修改 task 实体的属性值
- if (input.State.HasValue)
- {
- task.State = input.State.Value;
- }
- if (input.AssignedPersonId.HasValue)
- {
- task.AssignedPerson = _personRepository.Load(input.AssignedPersonId.Value);
- }
- // 我们都不需要调用 Update 方法
- // 因为应用服务层的方法默认开启了工作单元模式(Unit of Work)
- //ABP 框架会工作单元完成时自动保存对实体的所有更改, 除非有异常抛出有异常时会自动回滚, 因为工作单元默认开启数据库事务
- }
- public void CreateTask(CreateTaskInput input)
- {
- Logger.Info("Creating a task for input:" + input);
- // 通过输入参数, 创建一个新的 Task 实体
- var task = new Task { Description = input.Description };
- if (input.AssignedPersonId.HasValue)
- {
- task.AssignedPersonId = input.AssignedPersonId.Value;
- }
- // 调用仓储基类的 Insert 方法把实体保存到数据库中
- _taskRepository.Insert(task);
- }
- }
TaskAppService 使用仓储进行数据库操作, 它通往构造函数注入仓储对象的引用
数据验证
如果应用服务 (Application Service) 方法的参数对象实现了 IInputDto 或 IValidate 接口, ABP 会自动进行参数有效性验证
CreateTask 方法有一个 CreateTaskInput 参数, 定义如下:
- public class CreateTaskInput : IInputDto
- {
- public int? AssignedPersonId { get; set; }
- [Required]
- public string Description { get; set; }
- }
Description 属性通过注解指定它是必填项也可以使用其他 Data Annotation 特性
如果你想使用自定义验证, 你可以实现 ICustomValidate 接口:
- public class UpdateTaskInput : IInputDto, ICustomValidate
- {
- [Range(1, long.MaxValue)]
- public long TaskId { get; set; }
- public int? AssignedPersonId { get; set; }
- public TaskState? State { get; set; }
- public void AddValidationErrors(List<ValidationResult> results)
- {
- if (AssignedPersonId == null && State == null)
- {
- results.Add(new ValidationResult("AssignedPersonId 和 State 不能同时为空!", new[] { "AssignedPersonId", "State" }));
- }
- }
- }
你可以在 AddValidationErrors 方法中写自定义验证的代码
创建 Web Api 服务
ABP 可以非常轻松地把 Application Service 的 public 方法发布成 Web Api 接口, 可以供客户端通过 ajax 调用
- DynamicApiControllerBuilder
- .ForAll<IApplicationService>(Assembly.GetAssembly(typeof (SimpleTaskSystemApplicationModule)), "tasksystem")
- .Build();
SimpleTaskSystemApplicationModule 这个程序集中所有继承了 IApplicationService 接口的类, 都会自动创建相应的 ApiController, 其中的公开方法, 就会转换成 WebApi 接口方法
可以通过 http://xxx/api/services/tasksystem/Task/GetTasks 这样的路由地址进行调用
通过上面的案例, 大致介绍了领域层基础设施层应用服务层的用法
现在, 可以在 ASP.NET MVC 的 Controller 的 Action 方法中直接调用 Application Service 的方法了
如果用 SPA 单页编程, 可以直接在客户端通过 ajax 调用相应的 Application Service 的方法了(通过创建了动态 Web Api)
总结
以上所述是小编给大家介绍的 ABP(现代 ASP.NET 样板开发框架)系列之二 ABP 入门教程详解, 希望对大家有所帮助, 如果大家有任何疑问请给我留言, 小编会及时回复大家的在此也非常感谢大家对 PHPERZ 网站的支持!
来源: http://www.phperz.com/article/18/0312/352290.html