了解如何在 .NET Core 和 C# 中使用 GraphQL

2025-05-24

了解如何在 .NET Core 和 C# 中使用 GraphQL

GraphQL 是 Facebook 开发的一项技术,它使前端能够与后端协商所需的数据。如果您愿意,它还允许 API 构建者将来自不同 API 的数据拼接在一起。这是一项非常酷的技术,它不仅适用于 JavaScript,您绝对可以在下一个 .Net 项目中使用它。

在本文中,我们将介绍:

  • 为什么,为什么我们要用这项技术来构建 API
  • 它由哪些部分组成
  • 演示,让我们构建一个 API 并了解如何让它与我们的数据源协同工作

资源

 为什么?我们为什么需要它?REST API 有什么问题?

GraphQL 允许内容协商,这意味着你只需要一个端点。它还允许你精确查询所需的字段。在后端,你可以从不同的数据源获取数据,因此对于前端开发人员和后端开发人员来说,这绝对是一个值得兴奋的理由。

 GraphQL 由哪些部分组成

GraphQL 由一个 schema 定义组成。您可以使用 GQL(GraphQL 查询语言)来定义该 schema,也可以通过修饰类来响应某些资源请求(更多内容请参见后续文章)。

除了架构之外,还有一个核心概念叫做解析器。解析器只是一个知道如何处理传入查询的函数。解析器会映射到特定的资源。

然后,您将拥有一个名为 GraphiQL 的可视化环境,可用于运行查询。大多数 GraphQL 实现都附带某种形式的可视化环境。

如何查询

GraphQL 查询起来有点特殊,但其实很简单。要查询资源,你可以这样输入:

{ 
  resource
}
Enter fullscreen mode Exit fullscreen mode

但这还不够。您还需要指定所需的列,如下所示:

{
  resource {
    column,
    column2
  }
}
Enter fullscreen mode Exit fullscreen mode

要使用参数进行查询,您可以像这样输入:

{
  users(id:1) {
    name,
    created
  }
}
Enter fullscreen mode Exit fullscreen mode

最终结果始终是与查询匹配的 JSON 响应。因此,如果我们执行上述查询,我​​们将得到如下所示的返回结果:

{
  "data": {
    "users": [{
      "name" : "chris",
      "created": "2018-01-01"  
    }]
  }
}
Enter fullscreen mode Exit fullscreen mode

 演示 - 让我们构建一个 API。

我们需要将一些 GraphQL 理论与代码结合起来。因此,我们将介绍一个概念,然后展示相应的代码。

设置

我们需要做以下事情

  1. 创建解决方案
  2. 创建控制台应用程序
  3. 安装GraphQL NuGet 包

创建解决方案

让我们首先创建一个解决方案目录,如下所示:

mkdir demo
cd demo

Enter fullscreen mode Exit fullscreen mode

接下来,让我们创建实际的解决方案文件:

dotnet new sln
Enter fullscreen mode Exit fullscreen mode

创建控制台应用

创建控制台项目非常简单,只需输入以下内容:

dotnet new console -o App
Enter fullscreen mode Exit fullscreen mode

然后导航到项目目录:

cd App
Enter fullscreen mode Exit fullscreen mode

添加我们的 GraphQL NuGet 库

接下来,让我们添加 GraphQL NuGet 包

dotnet add package GraphQL
Enter fullscreen mode Exit fullscreen mode

你好 GraphQL

现在我们准备添加代码

// Program.cs

using System;
using GraphQL;
using GraphQL.Types;

namespace App
{
  class Program
  {
    static void Main(string[] args)
    {
      Console.WriteLine("Hello World!");
      var schema = Schema.For(@"
          type Query {
              hello: String
          }
          ");

      var root = new { Hello = "Hello World!" };
      var json = schema.Execute(_ =>
      {
          _.Query = "{ hello }";
          _.Root = root;
      });

      Console.WriteLine(json);
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

上面的代码有三个有趣的部分:

  1. 声明我们的模式
  2. 定义我们的解析器
  3. 执行我们的查询API

声明我们的模式

我们输入的字符串Schema.For包含称为 GQL 或 GraphQL 查询语言的内容。它通常定义三件事:

  1. 查询,这就是我们可以查询的
  2. 类型,我们目前还没有任何类型,但我们稍后会在文章中介绍。
  3. 变异,这就是我们所说的语义上的改变

让我们特别关注设置模式的部分:

var schema = Schema.For(@"
  type Query {
      hello: String
  }
");
Enter fullscreen mode Exit fullscreen mode

目前,我们只有,type Query并且它说我们可以查询,hello并且响应是字符串类型hello: string

解决我们的疑问

Schema 只是整个难题的一部分。另一部分是解析器代码。这部分代码实际上负责处理传入的请求。在我们的例子中,解析器代码如下所示:

var root = new { Hello = "Hello World!" };
Enter fullscreen mode Exit fullscreen mode

正如我们上面看到的,它映射了查询内部的一些内容hello,并表示 - 如果用户要求hello,那么我们就会回答Hello World

执行查询

在下面的代码中,我们通过将查询分配给我们提供的 lambda 表达式中的{ hello }属性来执行查询_.Queryschema.Execute()

var json = schema.Execute(_ =>
{
    _.Query = "{ hello }";
    _.Root = root;
});
Enter fullscreen mode Exit fullscreen mode

然后将查询的结果分配给我们的变量json,我们可以轻松地将其打印到终端:

Console.WriteLine(json); 
Enter fullscreen mode Exit fullscreen mode

架构优先

这是一种不同的方法,我们将使用类并装饰它们,其想法是,类将包含在我们进行查询时充当解析器的方法。

为了做到这一点,我们需要执行以下操作:

  1. 更新我们的模式,我们需要一个新的自定义类型,我们需要在Query

  2. 创建一些我们需要的类来支持我们的类型、查询以及内存数据库

架构更新

到目前为止,我们的 schema 还没有自定义类型。让我们来改变这种情况,添加自定义类型Jedi,并将其暴露为可查询的内容,如下所示:


Schema.For(@"
  type Jedi {
      name: String,
      side: String
  }

  type Query {
      hello: String,
      jedis: [Jedi]
  }
  ", _ =>
{
_.Types.Include<Query>();
});
Enter fullscreen mode Exit fullscreen mode

上面我们通过编写 来添加Jedi类型type Jedi,并在 中定义其属性{}。然后我们将jedis其添加到Query并声明其为 类型[Jedi],这意味着它是一个 数组Jedi。最后,我们给出 的Schema.For()第二个参数:

_.Types.Include<Query>();
Enter fullscreen mode Exit fullscreen mode

这意味着我们指定了一个Query处理所有传入请求的类。我们还没有这个类,所以让我们创建它。

创建支持类

首先,我们需要一个类Query。它现在负责处理Query我们模式中 内部的所有内容,这意味着它需要处理hellojedis。让我们看一下它Query是什么样子的:

public class Query 
{
    [GraphQLMetadata("jedis")]
    public IEnumerable<Jedi> GetJedis() 
    {
        return StarWarsDB.GetJedis();
    }

    [GraphQLMetadata("hello")]
    public string GetHello() 
    {
        return "Hello Query class";
    }
}
Enter fullscreen mode Exit fullscreen mode

这里我们定义了两个方法GetJedis()和。注意我们如何在每个方法上GetHello()使用装饰器来映射它们将处理的 中的哪个属性。我们还看到我们调用了一个类,因此接下来我们需要创建它:GraphQLMetadataQueryStarWarsDB

public static IEnumerable<Jedi> GetJedis() 
{
    return new List<Jedi>() {
        new Jedi(){ Name ="Luke", Side="Light"},
        new Jedi(){ Name ="Yoda", Side="Light"},
        new Jedi(){ Name ="Darth Vader", Side="Dark"}
    };
}
Enter fullscreen mode Exit fullscreen mode

定义查询的内容

让我们定义用于查询 GraphQL API 的查询:

{ jedis { name, side } }
Enter fullscreen mode Exit fullscreen mode

上面我们说的是,我们想要查询jedis,并且我们想要列nameside。将其与 SQL 表达式进行比较,在 SQL 表达式中,我们可以输入:

SELECT name, side
FROM jedis;
Enter fullscreen mode Exit fullscreen mode

让我们用查询来更新代码,如下所示:

var json = schema.Execute(_ =>
{
    _.Query = "{ jedis { name, side } }";
});

Console.WriteLine(json);
Enter fullscreen mode Exit fullscreen mode

结果是:

看起来效果不错,好吧 :)

使用参数

现在我们已经完成了许多工作,但我们需要能够处理参数。有时我们只需要返回一条记录,因此需要根据键过滤更大的集合。为此,我们需要:

  1. 更新我们的架构以支持带参数的查询

  2. 在我们的查询类中创建一个能够解析参数的方法

  3. 验证一切正常

更新我们的架构

首先,我们需要更新我们的模式,以便我们支持带参数的查询,如下所示:


Schema.For(@"
  type Jedi {
      name: String,
      side: String,
      id: ID
  }

  type Query {
      hello: String,
      jedis: [Jedi],
      jedi(id: ID): Jedi
  }
  ", _ =>
{
_.Types.Include<Query>();
});
Enter fullscreen mode Exit fullscreen mode

我们实际上在上面做了两件事。我们将字段添加idJedi类型中。我们还将此行添加到Query

jedi(id: ID): Jedi
Enter fullscreen mode Exit fullscreen mode

更新我们的代码
我们的 Jedi 类没有字段,Id所以我们需要添加它,如下所示:

public class Jedi 
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Side { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

接下来,我们需要向查询类添加一个方法,如下所示:

[GraphQLMetadata("jedi")]
public Jedi GetJedi(int id)
{
    return StarWarsDB.GetJedis().SingleOrDefault(j => j.Id == id);
}
Enter fullscreen mode Exit fullscreen mode

请注意,上面我们只需要将 matchid作为输入参数即可。代码本身只是一个SingleOrDefaultLINQ 查询,返回一个条目。

更新查询

让我们尝试像这样查询这个新资源:

{ jedi(id: 1) { name } }
Enter fullscreen mode Exit fullscreen mode

结果如下:

有效!!!:)

概括

我们已经讲解了很多内容。我们介绍了 GQL,即 GraphQL 查询语言。此外,我们还学习了如何在 schema 中定义资源、自定义类型以及如何解析这些资源。关于 GraphQL,还有很多内容需要学习,但本文已经够长了。希望这篇文章能让您初次体验 GraphQL,并乐在其中。在下一篇中,我们将介绍如何构建无服务器 API,并利用 GraphQL 将其部署到云端。

文章来源:https://dev.to/dotnet/learn-how-you-can-use-graphql-in-net-core-and-c-4h96
PREV
调试的秘密艺术训练你的眼睛👀认真地:训练你的眼睛👁👁但是怎么做呢?¯\(ツ)/¯回归基础🔎不要相信文档🔐熟能生巧🏌️‍♂️🏌️‍♀️最好的调试工具是你的头脑🧠这是一门你可以学习的艺术
NEXT
如何使用 .NET Core、C# 和 VS Code 中的 async/await 提高 .NET 程序的响应速度