ASP。NET Core 2.1:集成VMD.RESTApiResponseWrapper。REST API应用程序的核心

介绍 几个月前,我写了一篇关于如何为ASP创建一致的对象响应包装器的文章。NET Core和Web API应用程序。我也做了两个版本的NuGet包包装,可以在下面找到: VMD.RESTApiResponseWrapper。core vmd.restapiresponsewrapper.net|0>>>> 令我惊讶的是,两个NuGet包现在都有数百个下载,我收到了一些来自开发人员的评论和电子邮件,询问如何在项目中实际使用它们。本文旨在回答我收到的那些常见的问题,所以现在就开始吧。 开始 在我们开始之前,我想感谢那些正在查看这个图书馆并且可能已经尝试过的人们。我真的很感谢你们对这个图书馆的反馈,我希望这对你们的项目有所帮助。 闲话少说,让我们看看如何在应用程序中使用它。让我们继续,启动Visual Studio 2017。通过浏览File >创建一个新项目新项目。在新建项目对话框的左窗格中,选择Installed >Visual c#祝辞网络比;net核心比;ASP。NET Core Web应用程序。给项目起个随便的名字在这个demo中,我们叫它MyWebApp。”,如下图所示: 图1:New Project对话框 单击OK,它将带您进入下一个屏幕,如下图所示: 图2:ASP。NET Core模板对话框 选择Empty,然后单击OK,让Visual Studio为您生成默认的项目文件和依赖项。以下是默认生成的文件: 图3:默认生成的文件 让我们快速概览一下生成的每个文件。 如果你已经知道了ASP的核心重大变化。NET Core,那么你可以跳过这部分,但如果你是新的ASP。NET Core,然后我想强调其中的一些变化。如果您使用过以前版本的ASP。NET之前,那么你会注意到新的项目结构是完全不同的。该项目现在包括这些文件: 依赖项:包含应用程序属性所需的分析程序、NuGet和SDK依赖项:包含launchSettings。管理与每个调试配置文件(如IIS、IIS Express和应用程序本身)相关联的应用程序配置设置的json文件。在这里,您可以为应用程序中使用的框架定义特定于概要文件的配置(编译和调试概要文件)。wwwroot:存放所有静态文件的文件夹。这些是web应用程序将直接服务于客户端的资产,包括HTML、CSS、图像和JavaScript文件。启动。cs:这是你放置启动和配置代码的地方。程序。cs:这是初始化应用程序所需的所有服务的地方。 该模型 让我们创建几个简单的模型,我们将使用在这个演示下面的属性: 隐藏,复制Code

namespace MyWebApp.API.Model
{
    public class Band
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Genre { get; set; }
    }

    public class CreateBandDTO
    {
        public string Name { get; set; }
        public string Genre { get; set; }
    }

    public class UpdateBandDTO
    {
        public string Name { get; set; }
        public string Genre { get; set; }
    }
}

模型只不过是包含一些用于保存信息的属性的普通类。 模拟数据 我将尽量使这个演示尽可能简单,因此我在这里不会使用任何数据库,因为这不是本文的真正目的。如果你想学习如何工作与真实的数据从数据库,然后检查我的其他文章: 从实体框架核心开始:构建一个ASP。NET Core应用程序与Web API和代码优先开发 现在,我们继续工作吧。假设我们有以下定义模拟数据的类: 隐藏,复制Code

public class SampleData
{
        public static List<Band> GetBands()
        {
            return new List<Band>()
            {
                new Band { Id = 1, Name="Alice in Chains", Genre= "Heavy Metal"},
                new Band { Id = 2, Name="Soundgarden", Genre= "Grunge"},
                new Band { Id = 3, Name="Pearl Jam", Genre= "Grunge"},
                new Band { Id = 4, Name="Audioslave", Genre= "Alternative Metal"},
                new Band { Id = 5, Name="Stone Temple Pilots", Genre= "Hard Rock"},
                new Band { Id = 6, Name="Nirvana", Genre= "Grunge"},
                new Band { Id = 7, Name="Third Eye Blind", Genre= "Alternative Rock"},
                new Band { Id = 8, Name="Led Zeppelin", Genre= "Blues Rock"},
                new Band { Id = 9, Name="The Beatles", Genre= "Rock and Roll"},
                new Band { Id = 10, Name="The Rolling Stones", Genre= "Blues Rock"}
            };
        }
}

上面的类只是一个普通类,它具有一个名为GetBands()的公共静态方法。该方法定义了一个类型带列表,并向集合中添加了一些默认记录。 创建一个API控制器 让我们创建一个新的ASP。NET Core API控制器,并定义一些可以用于测试的端点。下面是我的控制器类的样子: 隐藏,收缩,复制Code

using Microsoft.AspNetCore.Mvc;
using MyWebApp.API.Model;
using System.Collections.Generic;
using System.Linq;

namespace MyWebApp.API.v1
{
    [Route("api/v1/[controller]")]
    [ApiController]
    public class BandsController : ControllerBase
    {
        // GET: api/v1/bands
        [HttpGet]
        public IEnumerable<Band> Get()
        {
            return SampleData.GetBands();
        }

        // GET api/v1/bands/7
        [HttpGet("{id}")]
        public Band Get(int id)
        {
            var data = SampleData.GetBands().Where(o => o.Id.Equals(id));
            if (data.Any())
                return data.First();

            return null;
        }

        // POST api/v1/bands
        [HttpPost]
        public IActionResult Post([FromBody]CreateBandDTO band)
        {
             //Call a method to add a new record to the entity
            return Ok();
        }

        // PUT api/v1/bands/7
        [HttpPut("{id}")]
        public IActionResult Put(int id, [FromBody]UpdateBandDTO band)
        {
            //Call a method to update the entity
            return Ok();
        }

        // DELETE api/bands/7
        [HttpDelete("{id}")]
        public IActionResult Delete(int id)
        {
            //Call a method to delete an entity
            return Ok();
        }
    }
}

上面的控制器类包含四个基本的HTTP方法,如GET、POST、PUT和DELETE。这就是典型的RESTful API的样子。注意,您无法找到POST、PUT和DELETE的任何代码实现。这是因为我们这里没有处理数据库或内存中的数据存储。我只是把它们包括在这里,所以你可以想象端点是什么样的。 测试输出 让我们构建并运行应用程序。下面是我在《邮差》中做的几个测试的截图示例: 得到:/ api / v1 /乐队 图4:HTTP Get请求 得到:api / v1 /带/ {id} 图5:HTTP Get请求 在这一点上,API可以工作,但问题是它不能给开发人员一个有意义的响应。我们知道,数据是响应的一个非常重要的部分。然而,仅仅将数据作为JSON响应输出并没有真正的帮助,特别是当在每个请求之间发生意外行为时。 作为一个快速回顾,如果你要然后,您将使用HTTP动词,如GET、POST、PUT和DELETE。这些操作中的每一个都可能返回不同的类型,这取决于方法/操作的设计方式。您的POST、PUT和DELETE端点可能返回数据,也可能根本不返回数据。你的GET端点可以返回一个字符串、一个列表、一个可枚举的、一个自定义类或一个对象。另一方面,如果您的API抛出一个错误,它将返回一个对象,或者最坏的情况是返回一个HTML字符串,说明错误的原因。所有这些响应之间的差异使得使用API变得困难,因为使用者需要知道在每种情况下返回的数据的类型和结构。客户端代码和服务代码都变得难以管理。 这就是为什么我提出了一个库,它为成功和错误结果提供了一致的响应格式。 整合VMD.RESTApiResponseWrapper。核心库在3个简单的步骤! 只需几个步骤,您就可以让您的API控制器返回一些有意义的响应,而无需您自己做太多的开发工作。你所要做的就是: 步骤1 从NuGet下载并安装该库。 图6:NuGet包管理器 您可以通过NPM安装包,如上图所示,或使用以下命令在NPM控制台: 隐藏,复制Code

PM> Install-Package VMD.RESTApiResponseWrapper.Core -Version 1.0.4

引用: 注意:截至撰写本文时的最新版本是v1.0.4,它的目标是ASP。NET Core 2.1版本。 步骤2 在Startup.cs中声明下面的命名空间: 隐藏,复制Code

using VMD.RESTApiResponseWrapper.Core.Extensions;

步骤3 在Startup.cs的Configure()方法中注册UseAPIResponseWrapperMiddleware,如下所示: 隐藏,复制Code

public void Configure(IApplicationBuilder app, IHostingEnvironment env) {
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseAPIResponseWrapperMiddleware();
    app.UseMvc();
}

引用: 注意:确保在MVC中间件之前注册它。 这是简单的!现在尝试再次构建并运行应用程序。根据我们的示例,下面是响应的样子: 图7:HTTP Get请求 您注意到,response对象现在包含一些属性,如版本、状态代码、消息,并且实际数据存储在Result属性中。 当我们试图指向一个不存在的URL时,这是另一个输出示例: 图8:HTTP Get请求 任何可能发生的意外错误都将自动处理,而不需要您做任何事情。您注意到响应输出是动态的。通过动态,我的意思是,我们没有包含结果属性,而是使用ResponseException属性来处理错误和异常信息。 启用自定义响应 让我们继续,修改现有的API端点以返回其他HTTP谓词的消息。 得到 隐藏,复制Code

// GET api/bands/7
[HttpGet("{id}")]
public APIResponse Get(int id) {
    var data = SampleData.GetBands().Where(o => o.Id.Equals(id));
    if (data.Any())
        return new APIResponse(200, "Data found", data.First());

    return null;
}

结果 图9:HTTP Get请求 帖子 隐藏,复制Code

// POST api/bands
[HttpPost]
public APIResponse Post([FromBody]CreateBandDTO band) {
    long bandID = 10; //10 is just an example here

    //Call a method to add a new record to the entity
    //bandID = YourRepo.Add(band);

    return new APIResponse(201, $"New record with ID {bandID} successfully added.");
}

结果 图10:HTTP Post请求 把 隐藏,复制Code

// PUT api/bands/6
[HttpPut("{id}")]
public APIResponse Put(long id, [FromBody]UpdateBandDTO band) {
    //Call a method to update the entity
    //YourRepo.Update(band);

    return new APIResponse(200, $"The record with ID {id} has been successfully updated.", id);
}

结果 图11:HTTP Put请求 删除 隐藏,复制Code

// DELETE api/bands/7
[HttpDelete("{id}")]
public APIResponse Delete(int id) {
    //Call a method to delete an entity
    //YourRepo.Delete(id);

    return new APIResponse(200, $"The record with ID {id} has been successfully deleted.", id);
}

结果 图12:HTTP Delete请求 注意,响应对象对于每个HTTP操作请求都是一致的。这无疑为您的API使用者提供了更好且有意义的信息。 实现模型验证 模型验证允许您在类/属性级别强制执行预定义的验证规则。您通常会使用这种验证技术来保持关注点的清晰分离,从而使您的验证代码的编写、维护和测试变得更加简单。 正如您已经知道的,ASP。NET Core 2.1引入了APIController属性,它对400个错误请求执行自动模型状态验证。当控制器被APIController属性修饰时,框架将自动注册一个ModelStateInvalidFilter,它运行在onactionexecute事件上。这将检查模型状态的有效性,并相应地返回响应。这是一个很好的特性,但是由于我们希望返回一个自定义响应对象而不是400坏请求错误,所以我们将在本例中禁用该特性。 要禁用自动模型状态验证,只需在Startup.cs文件的ConfigureServices()方法中添加以下代码: 隐藏,复制Code

public void ConfigureServices(IServiceCollection services) {
    services.Configure<ApiBehaviorOptions>(options =>
    {
        options.SuppressModelStateInvalidFilter = true;
    });

    services.AddMvc();
}

使用数据注释验证 数据注释是存在于System.ComponentModel下的属性类。可用于修饰类或属性以实施预定义验证规则的DataAnnotations名称空间。要启用数据注释模型验证,我们需要注册下面的命名空间: 隐藏,复制Code

using System.ComponentModel.DataAnnotations;

让我们修改CreateBandDTO类,以使用数据注释实现基本的模型验证。以下是修改后的代码: 隐藏,复制Code

public class CreateBandDTO
{
    [Required]
    [MaxLength(20)]
    public string Name { get; set; }
    [Required]
    public string Genre { get; set; }
}

现在,当我们再次运行应用程序并发出POST请求时,当Name属性为空时,应该会出现如下图所示的结果: 图13:HTTP Post请求 请注意,包装器捕获验证错误并将其放入ValidationErrors属性中,以便于跟踪。更多的正关于模型验证的信息,请参阅ASP中的模型验证。网络核心MVC。 使用流利的验证 如果由于某种原因,您不想使用System.ComponentModel。如果您想使用FluentValidation,您也可以这样做。让我们看一个快速示例,看看如何集成FluentValidation。 首先下载并安装NuGet包,如下图所示: 图14:NuGet包管理器 您也可以使用NPM控制台通过运行以下命令来安装它: 隐藏,复制Code

Install-Package FluentValidation.AspNetCore

安装完成后,我们现在可以开始使用FluentValidation API了。你应该声明下面的命名空间到你声明你的模型: 隐藏,复制Code

using FluentValidation;

让我们将CreateBandDTO类恢复到其原始状态,并添加一个名为CreateBandValidator的新类。以下是修改后的代码: 隐藏,复制Code

public class CreateBandDTO
{
    public string Name { get; set; }
    public string Genre { get; set; }
}

public class CreateBandValidator : AbstractValidator<CreateBandDTO>
{
    public CreateBandValidator() {
        RuleFor(o => o.Name).NotEmpty().MaximumLength(20);
        RuleFor(o => o.Genre).NotEmpty();
    }
}

您注意到,我们不再使用Required和MaxLength属性来对模型强制执行预定义的验证规则。相反,我们让它们简单明了。我喜欢FluentValidation的一点是,我们可以通过为每个模型创建一个验证器类来分离验证的逻辑,我们希望为每个模型实现一些约束和其他验证规则。 完成这项工作的最后一部分是在Startup.cs文件中配置FluentValidation,如下面的代码所示: 隐藏,复制Code

public void ConfigureServices(IServiceCollection services) {
    services.Configure<ApiBehaviorOptions>(options =>
    {
        options.SuppressModelStateInvalidFilter = true;
    });

    services.AddMvc().AddFluentValidation();
    services.AddTransient<IValidator<CreateBandDTO>, CreateBandValidator>();
}

有关更多信息,请参见此链接。 下面是模型验证失败时的响应截图: 图15:HTTP Post请求 这样一个信息丰富、一致和有意义的响应可以帮助开发人员轻松地消耗您的API并解决故障。 处理自定义错误和异常 您可以使用ApiException对象来返回错误和异常消息。例如,下面的代码处理和模拟一个意外错误,可能发生在您的代码使用try-catch块: 隐藏,复制Code

[HttpGet]
public IEnumerable<Band> Get() {
    try
    {
        //This is just an example to trigger an error
        int number = Convert.ToInt32("100abc");
    }
    catch (NullReferenceException ex)
    {
        throw new ApiException(ex);
    }
    catch (FormatException ex)
    {
        throw new ApiException(ex);
    }
    catch (ArithmeticException ex)
    {
        throw new ApiException(ex);
    }
    catch (Exception ex)
    {
        throw new ApiException(ex);
    }

    return SampleData.GetBands();
}

上面的代码试图将一个包含非数字值的字符串转换为在运行时会导致错误的整数类型。响应输出是这样的: 图16:HTTP Get请求 当您的自定义代码验证失败时,您还可以使用ApiException抛出您自己的消息。例如,如果你的代码验证用户凭证,它失败了,你可以这样做: 隐藏,复制Code

throw new ApiException($"The userid {id} does not exist.", 400);

使大摇大摆 Swagger为您的API提供了一个高级文档,它允许开发人员引用API端点的详细信息,并在必要时对它们进行测试。这是非常有用的,特别是当你的API是公开的并且你希望有很多开发人员使用它的时候。 要在API应用程序中启用Swagger,请通过NPM下载并安装Swashbuckle包,如下图所示: 图17:NuGet包管理器 在Startup.cs文件的ConfigureServices()方法中添加以下代码: 隐藏,复制Code

// Register the Swagger generator, defining 1 or more Swagger documents
services.AddSwaggerGen(c =>
{
     c.SwaggerDoc("v1", new Info 
     { Title = "My REST API with VMD.RESTApiResponseWrapper.Core", Version = "v1" });
});

接下来,我们需要启用中间件来服务生成的JSON文档和Swagger UI。为此,在Startup.cs文件的Configure()方法中添加以下代码: 隐藏,复制Code

// Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger();

// Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.), 
// specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
     c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
});

现在运行你的应用程序,并添加" /swagger "到URL,它应该显示swagger UI如下图所示: 图18:Swagger UI 下面是一个来自Swagger UI的POST请求/响应示例: 图19:Swagger UI HTTP Post请求 甜蜜的! 有关更多信息,请参见此链接。 总结 在本文中,我们学习了如何合并VMD.RESTApiResponseWrapper。核心包库到你的ASP。NET Core 2.1应用程序。 你可以试一试。欢迎评论和建议,所以请随意留言,我很乐意回答任何疑问。 本文转载于:http://www.diyabc.com/frontweb/news17313.html

posted @ 2020-08-13 01:18  Dincat  阅读(167)  评论(0编辑  收藏  举报