65.9K
CodeProject 正在变化。 阅读更多。
Home

SPA^2 使用 ASP.Net Core 1.1 + Angular 2.4 - 第 6 部分

starIconstarIconstarIconstarIconstarIcon

5.00/5 (9投票s)

2017年3月21日

CPOL

13分钟阅读

viewsIcon

21380

downloadIcon

274

如何使用 NSwag 为 Angular 2 创建 Typescript 数据模型和数据服务,并生成 Swagger Web API 文档。

或从 Github Part6 分支下载
注意:源代码不包括机器生成的以下代码。

引言

到目前为止,本系列文章一直介绍一种将 ASP.Net Core 与 Angular 2 集成的方法。

第 1 部分 - 如何集成 ASP.Net Core 和 Angular 2
第 2 部分 - 如何使用标签助手显示数据
第 3 部分 - 如何将标签助手用于数据输入,添加使用 EF Core 的 SQL 后端。
第 4 部分 - 使用 OpenIdDict 添加 JWT 令牌身份验证。 
第 5 部分 - 添加异步服务、服务器端验证、一个简单的 Angular 2 数据网格和更多标签助手。

这是第 6 部分 - 我们将使用 NSwag 为我们的 Web API 方法添加 Swagger 文档,然后使用(免费的)NSwag Studio 工具自动为 Angular 2 创建 Typescript 数据模型和数据服务。

注意:IIS 部署的主题将推迟到第 7 部分,因为本文档篇幅已稍长。

添加 NSwag - Dot Net 的 Swagger 库

首先,我们将添加 NSwag,然后用它创建一个在线自文档化的测试页面。

我们可以使用 Postman 测试 Web API 方法,我个人认为这对于测试和调试非常有用,但是它并不总是对半技术性的最终用户有用,或者用于文档,而且使用 Postman 仍然相当手动,也就是说,每次更改 Web API 数据服务时,您都需要维护另一个东西。这些文章的重点之一是展示另一种使用 ASP.Net Core 和 Angular 2(或任何客户端框架)的方法,同时也展示如何减少复制代码/手动修改的工作量。

所以,首先是 NSwag 的 Swagger 文档。

右键单击 A2SPA 项目,然后单击“管理 NuGet 程序包”。

单击“浏览”,然后在搜索框中输入 nswag,
然后在几秒钟后,单击 NSwag.AspNetCore

单击“安装”按钮,几秒钟后,您会看到一个“审阅更改”对话框

单击“确定”

单击“我接受”

使用 NuGet 添加 Nswag.Annotations

接下来,我们需要更新 Startup.cs 文件以注册 NSwag,为我们提供 Swagger 文档。

就在这一行之上

app.UseMvc(routes =>
{

Add

app.UseSwaggerUi(typeof(Startup).GetTypeInfo().Assembly, new SwaggerUiOwinSettings()
{
    DefaultPropertyNameHandling = PropertyNameHandling.CamelCase
});


为了解决依赖关系,请将以下内容添加到 Startup.cs 类顶部的“usings”中。

using NJsonSchema;
using NSwag.AspNetCore;
using System.Reflection;

让我们尝试构建它,然后按 Ctrl-F5... 它不会成功,但让我们看看会出什么问题。

我们的主页仍然在那里,手动将 URL 从 .../home 更改为 .../swagger

此消息告诉我们 NSwag 认为我们存在 CORS 或跨域请求设置问题。

由于我们没有 CORS 策略(到目前为止也不需要),这完全有可能。

但是,在我们修复一个不一定存在的问题之前,让我们先使用网络选项卡看一下 F12 调试。

按 F12,单击网络选项卡,清除缓存,然后按刷新,滚动浏览各种请求直到找到 swagger.json 文件,然后查看响应本身。

我们收到错误

System.InvalidOperationException: 方法 'Post' 在路径 '/api/Home' 上被多次注册。

由于我们不打算提供 Home 控制器的详细信息,因为它不用于 Web API 数据服务,我们可以告诉 Swagger 忽略它。

更新 HomeController.cs 文件以添加

using NSwag.Annotations;


然后用 [SwaggerIgnore] 属性装饰该类,以便最终的 HomeController.cs 如下所示。

using Microsoft.AspNetCore.Mvc;
using NSwag.Annotations;
 
namespace A2SPA.Controllers
{
    [SwaggerIgnore]
    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            ViewData["Title"] = "Home";
            return View();
        }
 
        public IActionResult Error()
        {
            return View();
        }
    }
}

再次构建并按 Ctrl-F5,我们将看到一种趋势,现在 PartialController 需要进行相同的 SwaggerIgnore 处理。

添加相同的 using 语句和 Swagger Ignore 属性,再次构建并按 Ctrl-F5。

并且,一如既往,我们在 Nswag 中遇到了另一个错误,这次与 OpenIdDict 的数据服务有关。

System.InvalidOperationException: JSON 属性 'item' 在类型 'AspNet.Security.OpenIdConnect.Primitives.OpenIdConnectParameter' 上被多次定义。

由于我们已经有了这些服务,所以我们也将忽略它,为每个文件(AccountController.cs、AuthorizationController.cs 和 ResourceController.cs)重复相同的过程,然后再次构建并按 Ctrl-F5(或者如果浏览器仍然打开,则刷新)。

最终,我们应该会看到我们的 Swagger 页面,swagger.json 不再生成异常,而是一个功能齐全的 JSON 文档。

关闭调试窗口。

单击 Swagger 文档页面上的链接,其中以灰色文本显示“SampleData”,它将展开显示该特定 Web API 类下的所有可用服务。

这些条目中的每一个都对应于一个不同的 Web API 方法,它们代表了我们在上一篇文章(第 5 部分)中添加的所有新的 CRUD 操作。

单击(例如)Get 方法中的每个方法,它们将打开一个测试页面,如下所示。

像“get by id”这样需要 Id 的方法将具有输入文本框,用于提供查询(如果需要)。在 ID 框中输入例如 1,然后单击“Try it out!”按钮,我们将看到我们的安全措施生效,因为我们收到了 401 错误。

为了验证这确实是问题所在,转到 SampleDataController.cs 类,并在 GetById 方法的正上方添加 [AllowAnonymous] 属性。

        [AllowAnonymous]
        [HttpGet("{id}")]

        public async Task<IActionResult> GetById(int id)
        {

由于我们在类级别具有 [Authorize] 属性,因此此更改将只允许一个方法 GetById 可访问,以检查这是否确实是问题所在。重建,如果您碰巧仍然打开了浏览器,甚至可以单击刚才失败的同一个“Try it out”按钮(如果 Web 服务器仍然在运行,则按 Ctrl-F5 启动 Web 服务器+浏览器),单击按钮后会开始出现一个点状的旋转器。

一切正常,您应该会看到结果 - 当然,前提是您选择了一个有效的 Id。

由于我们确实不想让此方法不受保护,因此请从 SampleDataController 类中的 GetById 方法中删除 [AllowAnonymous] 属性。

在开发过程中,您可能会放心地添加 [AllowAnonymous],但始终存在将其保留在代码中而未能保护您的 Web API 数据服务的风险。理想情况下,NSwag 可以为我们添加一个 bearer token,以便我们可以使用 OpenIdDict JWT 安全性来保护我们的数据服务。

要解决此问题,接下来编辑 Startup.cs 的 configure 方法,我们在其中添加了 Nswag 的早期配置,请进行此更改。

app.UseSwaggerUi(typeof(Startup).GetTypeInfo().Assembly, new SwaggerUiOwinSettings()
{
    DefaultPropertyNameHandling = PropertyNameHandling.CamelCase
});


变为这样:

app.UseSwaggerUi(typeof(Startup).GetTypeInfo().Assembly, new SwaggerUiOwinSettings()
{
    OperationProcessors =
    {
        new OperationSecurityScopeProcessor("apikey")
    },
    DocumentProcessors =
    {
        new SecurityDefinitionAppender("apikey", new SwaggerSecurityScheme
        {
            Type = SwaggerSecuritySchemeType.ApiKey,
            Name = "Authorization",
            In = SwaggerSecurityApiKeyLocation.Header
        })
    },
    DefaultPropertyNameHandling = PropertyNameHandling.CamelCase
});

重建并按 Ctrl-F5 启动浏览器,然后登录,按 F12 打开浏览器调试窗口。

在 Chrome 中,您需要选择 Application 选项卡。

 

在 Firefox 中,这称为 Storage 选项卡。

 

在 Edge 和 IE 中,位置有点晦涩,按 F12 进入调试,然后需要转到 Console(Ctrl 2 是快捷键)。

然后输入

sessionStorage

当您键入时,智能感知会生效,您会看到选项逐渐缩小。

一旦您获得一个选项,按两次 Enter,然后您将看到 session storage 的值。(注意:如果使用 local storage 而不是 session storage,请在此处键入 local storage)。

展开节点。

再次选择所有 token,这可能有点痛苦,Ctrl-A 无效,双击只会选择到最近的符号,例如 -,因此尝试单击第一个双引号的内部,然后向下拖动(这样更短),但请记住,如果您这样做,您将拾取后面的双引号。

到目前为止,我们不得不手动输入 URL,才能访问 NSwag 的 Swagger 文档页面。虽然您可以使用复制选项卡(查看您的浏览器是否支持此功能,右键单击浏览器选项卡),但我们将为我们的视图创建菜单链接。

由于 NSwag Swagger 文档将受到保护,因此我们将隐藏未登录 Web 应用程序的用户。

转到 Views 文件夹,然后到 AppComponent.cshtml 页面进行编辑,并在此代码下方添加。

<li [hidden]="!isLoggedIn()">
    <a class="nav-link" (click)="setTitle('About - A2SPA')" routerLink="/about">About</a>
</li>

以下内容。

<li [hidden]="!isLoggedIn()">
    <a class="nav-link" (click)="setTitle('About - A2SPA')" routerLink="/about">About</a>
</li>
<li [hidden]="!isLoggedIn()">
    <a class="nav-link" href="/swagger">NSwag</a>
</li>

请注意,我们使用了标准的超链接而不是 Angular 2 的 routerLink,因为我们要导航离开我们的 SPA。

再次构建并刷新您的浏览器(如果已打开),或按 Ctrl-F5(如果尚未打开),您应该会看到新的菜单项。

右键单击新的 NSwag 菜单项并在新选项卡中打开它,同时保持已登录的“About”选项卡打开以供参考。在 About 选项卡中按 F12,找到 sessionStorage 并复制 bearer token,然后切换到查看 NSwag Swagger 文档的选项卡,单击顶部的 Authorise 按钮。

在“value”文本框中,输入“Bearer”一词,后跟一个空格,然后粘贴您刚刚复制的 bearer token。

单击 Authorize 按钮,似乎没有明显的变化,窗口关闭了,但您现在会发现请求已使用 bearer token 进行授权。

打开操作列表,单击 Get - 获取所有,就像我们之前尝试的那样。

然后再次单击 try it out。

最后,我们获得了授权和开发人员或最终用户的测试平台。

注意:如果您想将其限制为开发人员,一个快速的方法是将 Startup.cs 中的 configure 代码包装在。

if (env.IsDevelopment())
{
    // development only code can go here
}

您现在可以轻松地在开发过程中看到正在发生的事情(当然,您可以使用 Postman 或类似工具来完成),但这里的文档是围绕您的 API 自动生成的。

我们将添加的最后一项,同样是为了让代码为我们做更多的事情,是扩展我们的 Web API 方法的描述,以提供对新的 Swagger 文档的更多提示和指向。

使用 NSwag 精炼 Swagger 文档

最初,我们的文档可能看起来很棒,是自动创建的,几乎不需要任何工作,但是当您开始添加越来越多的服务、操作和数据类型时,您的用户可能会开始寻求更多信息。

考虑 GetById 方法。

将其与它正在记录的代码进行比较。

// GET: api/sampleData/{1}
[HttpGet("{id}")]
public async Task<IActionResult> GetById(int id)
{
    var testData = await _context.TestData
                           .DefaultIfEmpty(null as TestData)
                           .SingleOrDefaultAsync(a => a.Id == id);
 
    if (testData == null)
    {
        return Json(NoContent());
    }
 
    return Json(Ok(testData));
}

将光标放在 [HttpGet] 属性的左侧,按 Enter,然后按向上箭头,然后按三次正斜杠键,您将自动创建注释的框架。

// GET: api/sampleData/{1}
/// <summary>
/// 
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet("{id}")]
public async Task<IActionResult> GetById(int id)
{
    var testData = await _context.TestData
                           .DefaultIfEmpty(null as TestData)
                           .SingleOrDefaultAsync(a => a.Id == id);
 
    if (testData == null)
    {
        return Json(NoContent());
    }
     return Json(Ok(testData));
}

您可以删除之前的注释。

// GET: api/sampleData/{1}

然后用一些更有意义的内容填充详细信息,例如。

/// <summary>
/// Returns a single TestData record with matching Id
/// </summary>
/// <param name="id">the ID of the record to retrieve</param>
/// <returns>an IActionResult</returns>

标记的结束标签后按 Enter,您将创建一个空行,输入 <r,智能感知会给出 <remarks>,按 Enter,在这里您可以添加进一步的说明。

/// <remarks>This method will return an IActionResult containing the TestData record and StatusCode 200 if successful. 
/// If there is a an error, you will get a status message and StatusCode which will indicate what was the error.</remarks>

最后,我一直陷入的陷阱。您可能几乎认为它应该有效,凭借我们现在所拥有的一切。由于现在添加了这些注释,我们的方法在悬停或用于智能感知时会获得额外的帮助 - 所以至少我们可能会帮助其他开发人员。

NSwag 会自动使用 XML 文档,一旦有一个 XML 文件可供参考,但默认情况下它不会生成。这是通常一次完成然后忘记的设置之一,即实际上启用了 XML 文档。

在 VS2015 中,右键单击项目,然后单击属性,然后选择“生成”,然后在属性的底部,确保“XML 文档文件”复选框已勾选。

同样,如果您使用的是 VS2017,右键单击项目,然后单击属性,然后选择“生成”,与 VS2015 一样,在属性的底部,确保“XML 文档文件”复选框已勾选。

现在重建,按 Ctrl-F5 或刷新您的 swagger 文档页面,您应该会看到我们努力的成果。

关闭时,右侧会添加注释。

打开时,我们会获得更多信息。

还有更多功能,这里无法一一列出,否则本文档将变成关于 NSwag 的内容。

您可以展开其他方法,根据需要为其他方法添加文档,或参考最终源代码以获取更多想法。

自动为 Angular2 创建 Typescript 数据模型和服务

在我们转向部署之前,在仍在使用 NSwag 并秉持自动化思维时,最后一件要自动化的就是为我们的 Angular 2 客户端代码使用的 Typescript 数据模型和 Typescript 数据服务。

正如我们生成的 Swagger 文档,您将看到 Swagger 格式的 JSON 数据,例如。

https://:57149/swagger/v1/swagger.json

swagger.json 文件由 NSwag 生成,因为它会查看您的 Web API 类,然后被您之前导航到的 ../swagger 路径下的 swagger 客户端所使用。

这个相同的 swagger.json 文件也可以被 NSwag Studio 工具使用。NSwag Studio 也来自 NSwag 的创建者/维护者 Rico Sutter,可以从这里安装。

上面的链接来自 NSwag 在 GitHub 上的仓库:https://github.com/NSwag/NSwag

安装后,从您的 swagger 页面获取 swagger.json 文件的 URL。

然后在 NSwag Studio 中,选择左侧的 Documents 选项卡,然后选择“Swagger Specification”,粘贴您刚刚从 swagger 页面复制的 swagger.json URL。然后单击“Create Local Copy”按钮将 JSON 数据副本获取到 NSwag Studio 中。

现在在 NSwag Studio 的右侧,

勾选“TypeScript Client”复选框,然后您会看到一个新的选项卡出现。

选择 TypeScript Client 选项卡,将 Typescript 版本从 1.8 更改为 2.0。

接下来向下滚动,然后在“Template”下拉菜单中选择“Angular 2”。

暂时保留默认设置。

单击 Generate Outputs。

如果您想将代码复制回源文件,这很好,但更好的方法是设置 NSwag Studio,使其直接写回到您的 Visual Studio 项目中。

要直接生成 typescript 文件,在 typescript 设置页面的底部,单击“Output file path:”输入框右侧的“..”按钮。导航到您的项目文件空间内的 wwwroot\app 文件夹。然后添加一个名称(例如)nswag 以创建 nswag.ts。

单击 Save 按钮,然后单击 Generate Files。回到 Visual Studio,右键单击 app 文件夹,然后选择 Add,然后选择 Existing Item。

选择 wwwroot\app\nswag.ts 文件。

接下来使用我们生成的文件,替换现有文件。更新 /wwwroot/app/app.module.ts 文件并更改这些代码部分。

从现有

import { SampleDataService } from './services/sampleData.service';
import { TestData } from './models/testData';

到新的

import { SampleDataClient, TestData, SwaggerException } from './nswag';

    constructor(private sampleDataService: SampleDataService, private toastrService: ToastrService) { }

改为

constructor(private sampleDataService: SampleDataClient, private toastrService: ToastrService) { }

然后更改我们数据服务调用的名称(智能感知会在此提示),从这些

this.sampleDataService.addSampleData(this.testData)
 … 
this.sampleDataService.getSampleData()
 … 
this.sampleDataService.editSampleData(this.testData)
 … 
this.sampleDataService.deleteRecord(itemToDelete)


到这些

this.sampleDataService.post(this.testData)
…
this.sampleDataService.get()
…
this.sampleDataService.put(this.testData)
…
this.sampleDataService.delete(itemToDelete.id)

保存,清理并重建项目,然后按 Ctrl-F5,瞧,它应该和以前一样工作。

链接

有关 **NSwag** 的更多信息

**NSwag 源代码** 在 GitHub 上:https://github.com/NSwag/NSwag
**NSwag 示例源代码** 在 GitHub 上:https://github.com/NSwag/Samples
以及 NSwag 的作者和维护者 **Rico Suter**,他的 **博客** 在这里:http://blog.rsuter.com/

关注点

(问) 在编写代码时,您学到了什么有趣/好玩/令人讨厌的东西吗?
(答) 再次提醒我一些词语的令人讨厌的美国拼写。以及“Authorization”为何比“Authorisation”更有效 - 发送 token 时,有趣的是,它不会被 Authorised 或 Authorized。

(问) 您有没有做过什么特别聪明、疯狂或出格的事情?
(答) 喜欢 NSwag 和 NSwag Studio 的代码生成功能……为什么手工编写代码,当您可以自动生成或重新生成它,并且从一个地方获得它——您的数据模型。
 

历史

第 1 部分 - 如何集成 ASP.Net Core 和 Angular 2
第 2 部分 - 如何使用标签助手显示数据
第 3 部分 - 如何将标签助手用于数据输入,添加使用 EF Core 的 SQL 后端。
第 4 部分 - 使用 OpenIdDict 添加 JWT 令牌身份验证。 
第 5 部分 - 添加异步服务、服务器端验证、一个简单的 Angular 2 数据网格和更多标签助手。

这是第 6 部分 - 我们将使用 NSwag 为我们的 Web API 方法添加 Swagger 文档,然后使用(免费的)NSwag Studio 工具自动为 Angular 2 创建 Typescript 数据模型和数据服务。

第 7 部分将涵盖我们的 SPA / 单页应用程序部署到 IIS。

 

© . All rights reserved.