zoukankan      html  css  js  c++  java
  • 在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格式的了:

    image

    注意:由于返回的数据量并没有超出一页的分页尺寸,所以在_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了:

    image

    开发人员在开发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命令,看看结果如何:

    image

    可以看到,我们已经在返回的HAL结果中加入了服务器的UTC时间,同时,还是保留了_self的链接。不过,分页的链接没有包含在内,这是因为我们通过override重写了RegisterHalBuilderFactoryForGetAll方法。你可以参考Apworks框架源代码中的Apworks.Integration.AspNetCore.DataServices.DataServiceHalBuildConfiguration类来了解如何将分页的链接加入到HAL的返回结果中。

    大致对上面的代码做一些介绍:

    1. DataServiceHalBuildConfiguration及其子类主要负责对HAL Resource BuilderBuilder模式,[GoF95])的定义和注册,它能将某一个HAL的资源构造器(Resource Builder)关联到某一个ASP.NET Core Web API的控制器上
    2. RegisterHalBuilderFactory方法会根据其第一个参数(ControllerActionSignature)确定一个ASP.NET Core Web API的Controller Action方法,并将第二个参数所指定的HAL Resource Builder工厂方法委托(Delegate)注册到由ControllerActionSignature指定的Controller Action方法上
    3. HalResultFilterAttribute类中,当Controller Action执行完成时,会根据所注册的Hal Resource Builder Factory来获取最终的HAL内容(通过调用ResourceBuilder的Build方法),然后将产生的HAL以application/hal+json格式返回
    4. SupportsHalAttribute类中会根据是否存在一个IHalBuildConfiguration的Service注册,来确定是否使用HAL的返回内容
    5. DataServiceController类已经使用了SupportsHalAttribute,因此,它具有使用HAL功能的能力,那么继承于它的控制器都会被应用SupportsHalAttribute特性,因此,你开发的数据服务控制器(Data Service Controller)无需关注HAL的功能
    6. 最后,在DataServiceConfigurationOptions类的构造函数中,通过指定useHalSupport以及halBuildConfigurationFactory两个参数,来决定是否需要HAL的支持,以及如何产生HAL的结果

    事实上,如果你不打算使用DataServiceController来快速开发数据服务,而是希望使用传统的方式自己开发自己的RESTful服务,你完全可以使用Apworks.Integration.AspNetCore.Hal命名空间下的类型来使得你的RESTful服务也支持流行的HAL,而且开发过程非常方便。由此可见,Apworks.Integration.AspNetCore中对HAL的支持并不是专为框架本身的数据服务开发而设计的,它能够应用于普通的RESTful服务的开发,数据服务只不过是HAL的一个客户而已。

    总结

    本文介绍了Apworks数据服务开发中对HAL的支持,可以看到,Apworks框架的设计是:

    1. 灵活的:通过不同的配置信息来干预数据服务的执行过程,同时还支持自定义扩展来定制自己的数据服务
    2. 通用的:组件的设计尽可能达到通用性,比如HAL的机制,它不仅仅是Apworks数据服务的“特供”,它可以被应用在任何由ASP.NET Core Web API所开发的RESTful服务上
    3. 开发体验友好的:简单的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。敬请期待。

  • 相关阅读:
    e621. Activating a Keystroke When Any Child Component Has Focus
    e587. Filling Basic Shapes
    e591. Drawing Simple Text
    e595. Drawing an Image
    e586. Drawing Simple Shapes
    e636. Listening to All Key Events Before Delivery to Focused Component
    在 PL/SQL 块的哪部分可以对初始变量赋予新值? (选择1项)
    Oracle数据库中,在SQL语句中连接字符串的方法是哪个?(选择1项)
    你判断下面语句,有什么作用?(单选)
    Oracle数据库表空间与数据文件的关系描述正确的是( )
  • 原文地址:https://www.cnblogs.com/daxnet/p/6701119.html
Copyright © 2011-2022 走看看