在ASP.NET Core中使用Apworks开发数据服务:对HAL的支持
HAL,全称为Hypertext Application Language,它是一种简单的数据格式,它能以一种简单、统一的形式,在API中引入超链接特性,使得API的可发现性(discoverable)更强,并具有自描述的特点。使用了HAL的API会更容易地被第三方开源库所调用,并且使用起来也很方便,开发者可以像处理普通JSON数据那样去处理API数据。有关HAL的更多信息,可以参考官方网站:http://stateless.co/hal_specification.html。目前,很多RESTful服务开发框架都支持HAL的Response格式(Content-Type为application/hal+json),比如大名鼎鼎的Spring Data,默认就支持HAL。现在,使用全新的Apworks Core(今后简称Apworks)开发数据服务时,默认也提供对HAL的支持。
HAL的启用和禁用
在上一篇快速开发文章中,演练部分通过修改Startup.cs文件中的ConfigureServices方法以在ASP.NET Core Web API中启用Apworks以及Data Service的开发支持。首先我们回顾一下这段代码:
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc(); services.AddApworks()
.WithDataServiceSupport(new DataServiceConfigurationOptions
(new MongoRepositoryContext
(new MongoRepositorySettings("localhost", "customer-service"))))
.Configure();
}
默认情况下,HAL的支持是启用的。也就是说,当你运行Data Service时,直接发起HTTP GET请求,返回的Response已经是application/hal+json格式的了:

注意:由于返回的数据量并没有超出一页的分页尺寸,所以在_links下仅显示了一个self的链接。如果存在多个分页,那么_links部分也会出现prev、next、first、last等链接。
如果希望禁用HAL的功能,其实非常简单,在上面的代码中,在构造DataServiceConfigurationOptions时直接指定useHalSupport参数为false即可:
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc(); services.AddApworks()
.WithDataServiceSupport(new DataServiceConfigurationOptions
(new MongoRepositoryContext
(new MongoRepositorySettings("localhost", "customer-service")), useHalSupport: false))
.Configure();
}
于是,得到的返回内容就不再是application/hal+json,而是application/json了:

开发人员在开发Data Service的时候,可以根据自己的需求启用或者禁用HAL的支持。
自定义HAL的返回内容
在ASP.NET Core Web API中使用Apworks开发数据服务时,对于HAL的返回内容是可以自定义的。当然,这并不会改变HTTP Response的Content-Type,而是针对Response Body,其Json内容是可以被自定义的。例如,在上面的例子中,HTTP GET的Response Body中不仅包含所请求的数据对象数组(customers),而且还包含分页信息,以及一个含有分页链接的_links的对象。在实现Data Service的时候,如果这些返回内容不能满足需求,开发人员完全可以自定义。
举个例子,假设我们希望在返回内容中包含当前的服务器时间,其开发过程如下。
首先,新建一个继承于Apworks.Integration.AspNetCore.DataServices.DataServiceHalBuildConfiguration的类型,取名为ServerTimeHalBuildConfiguration:
using Apworks.Integration.AspNetCore.DataServices;
using Hal.Builders;
using Microsoft.AspNetCore.Http.Extensions;
using System; namespace CustomerService
{
public class ServerTimeHalBuildConfiguration : DataServiceHalBuildConfiguration
{
protected override void RegisterHalBuilderFactoryForGetAll()
{
this.RegisterHalBuilderFactory("*.Get(int, int)", context =>
new ResourceBuilder()
.WithState(new { ServerTime = DateTime.UtcNow })
.AddSelfLink().WithLinkItem(context.HttpContext.Request.GetEncodedUrl())
.AddEmbedded(context.ControllerAction.ControllerName.ToLower())
.Resource(new ResourceBuilder().WithState(context.State))
);
}
}
}
然后,回到Startup.cs文件中的ConfigureServices方法,在DataServiceConfigurationOptions的构造函数参数中,指定halBuildConfigurationFactory参数,代码如下:
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc(); services.AddApworks()
.WithDataServiceSupport(new DataServiceConfigurationOptions
(new MongoRepositoryContext
(new MongoRepositorySettings("localhost", "customer-service")),
halBuildConfigurationFactory: _ => new ServerTimeHalBuildConfiguration()))
.Configure();
}
OK,任务完成,测试一下。打开MINGW,执行curl http://localhost:2238/api/customers -i命令,看看结果如何:

可以看到,我们已经在返回的HAL结果中加入了服务器的UTC时间,同时,还是保留了_self的链接。不过,分页的链接没有包含在内,这是因为我们通过override重写了RegisterHalBuilderFactoryForGetAll方法。你可以参考Apworks框架源代码中的Apworks.Integration.AspNetCore.DataServices.DataServiceHalBuildConfiguration类来了解如何将分页的链接加入到HAL的返回结果中。
大致对上面的代码做一些介绍:
- DataServiceHalBuildConfiguration及其子类主要负责对HAL Resource Builder(Builder模式,[GoF95])的定义和注册,它能将某一个HAL的资源构造器(Resource Builder)关联到某一个ASP.NET Core Web API的控制器上
- RegisterHalBuilderFactory方法会根据其第一个参数(ControllerActionSignature)确定一个ASP.NET Core Web API的Controller Action方法,并将第二个参数所指定的HAL Resource Builder工厂方法委托(Delegate)注册到由ControllerActionSignature指定的Controller Action方法上
- 在HalResultFilterAttribute类中,当Controller Action执行完成时,会根据所注册的Hal Resource Builder Factory来获取最终的HAL内容(通过调用ResourceBuilder的Build方法),然后将产生的HAL以application/hal+json格式返回
- 在SupportsHalAttribute类中会根据是否存在一个IHalBuildConfiguration的Service注册,来确定是否使用HAL的返回内容
- DataServiceController类已经使用了SupportsHalAttribute,因此,它具有使用HAL功能的能力,那么继承于它的控制器都会被应用SupportsHalAttribute特性,因此,你开发的数据服务控制器(Data Service Controller)无需关注HAL的功能
- 最后,在DataServiceConfigurationOptions类的构造函数中,通过指定useHalSupport以及halBuildConfigurationFactory两个参数,来决定是否需要HAL的支持,以及如何产生HAL的结果
事实上,如果你不打算使用DataServiceController来快速开发数据服务,而是希望使用传统的方式自己开发自己的RESTful服务,你完全可以使用Apworks.Integration.AspNetCore.Hal命名空间下的类型来使得你的RESTful服务也支持流行的HAL,而且开发过程非常方便。由此可见,Apworks.Integration.AspNetCore中对HAL的支持并不是专为框架本身的数据服务开发而设计的,它能够应用于普通的RESTful服务的开发,数据服务只不过是HAL的一个客户而已。
总结
本文介绍了Apworks数据服务开发中对HAL的支持,可以看到,Apworks框架的设计是:
- 灵活的:通过不同的配置信息来干预数据服务的执行过程,同时还支持自定义扩展来定制自己的数据服务
- 通用的:组件的设计尽可能达到通用性,比如HAL的机制,它不仅仅是Apworks数据服务的“特供”,它可以被应用在任何由ASP.NET Core Web API所开发的RESTful服务上
- 开发体验友好的:简单的API定义使得应用程序快速开发成为可能,Fluent Interface API(流畅接口)的设计,使得开发者能够用更为自然的语言来完成所需要的功能操作,大大提升开发生产率。在Apworks的整个框架中,会更多地引入流畅接口以便保持较好的开发者体验
就HAL这部分来说,它利用了ASP.NET Core中的ResultFilter以及Filter Factory,建议大家可以了解一下HAL以及Data Service的相关代码,来熟悉ASP.NET Core中Filter的相关内容。
值得一提的是,Apworks中对HAL的支持使用的正是我自己开发的HAL库,这套库也是开源的,开源地址是:https://github.com/daxnet/hal,它是为数较少的完整实现HAL规范,并支持.NET Core的HAL开发库,同样,它支持流畅接口。
下一讲打算介绍一下如何在Apworks数据服务中使用Entity Framework Core。敬请期待。
在ASP.NET Core中使用Apworks开发数据服务:对HAL的支持的更多相关文章
- 在 asp.net core 中使用类似 Application 的服务
在 asp.net core 中使用类似 Application 的服务 Intro 在 asp.net 中,我们可以借助 Application 来保存一些服务器端全局变量,比如说服务器端同时在线的 ...
- [.NET Core]ASP.NET Core中如何解决接收表单时的不支持的媒体类型(HTTP 415 Unsupported Media Type)错误呢?
[.NET Core]ASP.NET Core中如何解决接收表单时的不支持的媒体类型(HTTP 415 Unsupported Media Type)错误呢? 在ASP.NET Core应用程序中,接 ...
- 在ASP.NET Core中使用Apworks快速开发数据服务
不少关注我博客的朋友都知道我在2009年左右开发过一个名为Apworks的企业级应用程序开发框架,旨在为分布式企业系统软件开发提供面向领域驱动(DDD)的框架级别的解决方案,并对多种系统架构风格提供支 ...
- 【半译】在ASP.NET Core中创建内部使用作用域服务的Quartz.NET宿主服务
在我的上一篇文章中,我展示了如何使用ASP.NET Core创建Quartz.NET托管服务并使用它来按计划运行后台任务.不幸的是,由于Quartz.NET API的工作方式,在Quartz作业中使用 ...
- asp.net core中遇到需要自定义数据包解密方法的时候
最近将公司的项目用.netcore重写, 服务的http外部接口部分收发消息是DES加解密的, 那么在asp.net core mvc的action处理之前需要加入解密这个步骤. 我第一想到的是用fi ...
- NET Core中使用Apworks
NET Core中使用Apworks HAL,全称为Hypertext Application Language,它是一种简单的数据格式,它能以一种简单.统一的形式,在API中引入超链接特性,使得AP ...
- 在Asp.Net Core中使用中间件保护非公开文件
在企业开发中,我们经常会遇到由用户上传文件的场景,比如某OA系统中,由用户填写某表单并上传身份证,由身份管理员审查,超级管理员可以查看. 就这样一个场景,用户上传的文件只能有三种人看得见(能够访问) ...
- 如何在 ASP.NET Core 中构建轻量级服务
在 ASP.NET Core 中处理 Web 应用程序时,我们可能经常希望构建轻量级服务,也就是没有模板或控制器类的服务. 轻量级服务可以降低资源消耗,而且能够提高性能.我们可以在 Startup 或 ...
- 项目开发中的一些注意事项以及技巧总结 基于Repository模式设计项目架构—你可以参考的项目架构设计 Asp.Net Core中使用RSA加密 EF Core中的多对多映射如何实现? asp.net core下的如何给网站做安全设置 获取服务端https证书 Js异常捕获
项目开发中的一些注意事项以及技巧总结 1.jquery采用ajax向后端请求时,MVC框架并不能返回View的数据,也就是一般我们使用View().PartialView()等,只能返回json以 ...
随机推荐
- [TPYBoard-Micropython之会python就能做硬件 7] 学习使用蓝牙模块及舵机
转载请注明:@小五义 http://www.cnblogs.com/xiaowuyi 欢迎加入讨论群 64770604 一.实验器材 1.TPYboard V102板 一块 2 ...
- 计算机存储负数以及int转byte时-128的出现
我们看下面这段代码 输出的结果的是128,这个没什么疑问 但是当我们不改变数值仅仅加了一个强制转换后 这时我们会发现结果会变成负的128.这时候我们就要怀疑了,为什么会出现这样的结果呢? 对于这个问题 ...
- 一道面试题引发的对javascript类型转换的思考
最近群里有人发了下面这题:实现一个函数,运算结果可以满足如下预期结果: add(1)(2) // 3 add(1, 2, 3)(10) // 16 add(1)(2)(3)(4)(5) // 15 对 ...
- 妙用 `package.json` 快速 `import` 文件(夹)
前言 import router from './router'; import router from '../../router'; import router from './../../../ ...
- C++ protected访问权限思考
看了云风关于protected的思考,自己也总结了下. C++的访问权限有三个 private.protected.public. 如果不包括继承的话,比较好理解,可以分为类外和类内两部分.类外不能访 ...
- node插件http-proxy实现反向代理
最近自己动手做了一个微信小程序,是直接买的腾讯云的小程序解决方案,怎么说那,用起来还是会遇到不少问题的,不过在交流群里还是会有很多人帮助你的. 闲话少说,因为要再做一个别的服务,就想直接用这台小程序的 ...
- virtualBox,webstorm,开虚拟机传代码
一起git一个新技能 利用virtualBOX在本地开一个虚拟机,然后设置webstorm连接到虚拟机,将代码传到虚拟机里. 以下详细讲解: 第一步: 第二步:管理虚拟机的设置(我是用的是Xshell ...
- mysql命令[转]
来自:http://www.cnblogs.com/zhangzhu/archive/2013/07/04/3172486.html 1.连接到本机上的MYSQL.首先打开DOS窗口,然后进入目录my ...
- Python中参数是传值,还是传引用?
在 C/C++ 中,传值和传引用是函数参数传递的两种方式,在Python中参数是如何传递的?回答这个问题前,不如先来看两段代码. 代码段1: def foo(arg): arg = 2 print(a ...
- java-信息安全(四)-数据签名、数字证书
概述 信息安全基本概念: 数字签名 数字证书 数字签名 数字签名(又称公钥数字签名.电子签章)是一种类似写在纸上的普通的物理签名,但是使用了公钥加密领域的技术实现,用于鉴别数字信息的方法.一套数字签名 ...