ASP.NET Core中使用GraphQL


本篇中我将演示如何配置持久化仓储,这里原文中是使用的Postgres, 这里我改用了EF Core For SqlServer。本文的例子需要在上一篇的代码基础上修改。没有代码的同学,可以去https://github.com/lamondlu/GraphQL_Blogs/tree/master/Part%20V下载。

之前我们编写了一个DataStore类,里面硬编码了一个数据集合,这里我们希望改用依赖注入的方式进行解耦,所以首先我们需要创建一个抽象接口IDataStore

public interface IDataStore
{
IEnumerable<Item> GetItems();
Item GetItemByBarcode(string barcode);
}

由于接下来我们需要使用EF Core, 所以这里我们需要添加一个EF Core的上下文类ApplicationDbContext

public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
{ } public DbSet<Item> Items { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Item>().ToTable("Items");
modelBuilder.Entity<Item>().HasKey(p => p.Barcode); modelBuilder.Entity<Item>().HasData(new Item {
Barcode = "123",
Title = "Headphone",
SellingPrice = 50 }); modelBuilder.Entity<Item>().HasData(new Item {
Barcode = "456",
Title = "Keyboard",
SellingPrice = 40 });
modelBuilder.Entity<Item>().HasData(new Item {
Barcode = "789",
Title = "Monitor",
SellingPrice = 100 }); base.OnModelCreating(modelBuilder);
}
}

这里为了导入一些初始数据,我们在OnModelCreating方法中使用HasData方法添加了3个初始数据。

下面我们修改DataStore类, DataStore应该实现IDataStore接口, 其中的GetItemByBarcodeGetItems方法需要改为从数据库中读取。

public class DataStore : IDataStore
{
private ApplicationDbContext _applicationDbContext; public DataStore(ApplicationDbContext applicationDbContext)
{
_applicationDbContext = applicationDbContext;
} public Item GetItemByBarcode(string barcode)
{
return _applicationDbContext.Items.First(i => i.Barcode.Equals(barcode));
} public IEnumerable<Item> GetItems()
{
return _applicationDbContext.Items;
}
}

接下来,我们要在Startup.cs类中的ConfigureServices添加Entity Framework配置

services.AddDbContext<ApplicationDbContext>(option =>
{
option.UseSqlServer(Configuration.GetConnectionString("SampleDB"));
});

TIPS: 这里注意不要忘记创建一个appsettings.json, 在其中添加数据库连接字符串

配置完成之后,我们需要使用以下命令添加Migration,并更新数据库

dotnet ef migrations add Initial
dotnet ef database update

现在针对数据库的修改都已经完成了。

另外我们还需要修改服务注册代码,将注册服务的生命周期从单例(Singleton)改为作用域(Scoped), 因为当注入服务的生命周期为单例时,需要处理多线程问题和潜在的内存泄漏问题。

services.AddScoped<IDataStore, DataStore>();
services.AddScoped<HelloWorldQuery>();
services.AddScoped<ISchema, HelloWorldSchema>();

修改完成后,Startup.cs最终代码如下:

public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
} public IConfiguration Configuration { get; } public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(option =>
{
option.UseSqlServer(Configuration.GetConnectionString("SampleDB"));
}); services.AddSingleton<IDocumentExecuter, DocumentExecuter>();
services.AddSingleton<IDocumentWriter, DocumentWriter>(); services.AddScoped<IDataStore, DataStore>();
services.AddScoped<HelloWorldQuery>();
services.AddScoped<ISchema, HelloWorldSchema>();
} public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
} app.UseDefaultFiles();
app.UseStaticFiles(); app.UseMiddleware<GraphQLMiddleware>();
}
}

现在我们启动项目, 程序会抛出一个错误

System.InvalidOperationException: Cannot resolve scoped service 'GraphQL.Types.ISchema' from root provider

这个问题的原因是,中间件是单例的,如果在中间件的构造函数中使用作用域(Scoped)的依赖注入, 会导致这个问题(具体请参见https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-2.1)。这里ISchema的生命周期是作用域,并且在GraphQLMiddleware类中是从构造函数注入的,所以这里我们需要修改GraphQLMiddleware类,ISchema需要改从Invoke方法注入。

中间件最终代码如下:

public class GraphQLMiddleware
{
private readonly RequestDelegate _next;
private readonly IDocumentWriter _writer;
private readonly IDocumentExecuter _executor;
public GraphQLMiddleware(RequestDelegate next, IDocumentWriter writer, IDocumentExecuter executor)
{
_next = next;
_writer = writer;
_executor = executor;
} public async Task InvokeAsync(HttpContext httpContext, ISchema schema)
{
if (httpContext.Request.Path.StartsWithSegments("/api/graphql")
&& string.Equals(httpContext.Request.Method,
"POST",
StringComparison.OrdinalIgnoreCase))
{
string body;
using (var streamReader = new StreamReader(httpContext.Request.Body))
{
body = await streamReader.ReadToEndAsync(); var request = JsonConvert.DeserializeObject<GraphQLRequest>(body); var result = await _executor.ExecuteAsync(doc =>
{
doc.Schema = schema;
doc.Query = request.Query;
doc.Inputs = request.Variables.ToInputs();
}).ConfigureAwait(false); var json = await _writer.WriteToStringAsync(result);
await httpContext.Response.WriteAsync(json);
}
}
else
{
await _next(httpContext);
}
}
}

修改完成之后,我们重新启动项目,项目正常启动成功, GraphiQL界面出现。

现在我们还是使用上一章的查询代码,查询二维码是123的货物数据。

数据正常从数据库中读取成功。下一章我们将讲解在ASP.NET Core中如何使用GraphQL添加修改数据。

本文源代码: https://github.com/lamondlu/GraphQL_Blogs/tree/master/Part%20VI

ASP.NET Core中使用GraphQL - 第六章 使用EF Core作为持久化仓储的更多相关文章

  1. ASP.NET Core中使用GraphQL - 第七章 Mutation

    ASP.NET Core中使用GraphQL - 目录 ASP.NET Core中使用GraphQL - 第一章 Hello World ASP.NET Core中使用GraphQL - 第二章 中间 ...

  2. ASP.NET Core中使用GraphQL - 第四章 GraphiQL

    ASP.NET Core中使用GraphQL ASP.NET Core中使用GraphQL - 第一章 Hello World ASP.NET Core中使用GraphQL - 第二章 中间件 ASP ...

  3. ASP.NET Core中使用GraphQL - 第五章 字段, 参数, 变量

    ASP.NET Core中使用GraphQL ASP.NET Core中使用GraphQL - 第一章 Hello World ASP.NET Core中使用GraphQL - 第二章 中间件 ASP ...

  4. ASP.NET Core中使用GraphQL - 第三章 依赖注入

    ASP.NET Core中使用GraphQL ASP.NET Core中使用GraphQL - 第一章 Hello World ASP.NET Core中使用GraphQL - 第二章 中间件 SOL ...

  5. ASP.NET Core中使用GraphQL - 最终章 Data Loader

    ASP.NET Core中使用GraphQL - 目录 ASP.NET Core中使用GraphQL - 第一章 Hello World ASP.NET Core中使用GraphQL - 第二章 中间 ...

  6. ASP.NET Core中使用GraphQL - 第八章 在GraphQL中处理一对多关系

    ASP.NET Core中使用GraphQL - 目录 ASP.NET Core中使用GraphQL - 第一章 Hello World ASP.NET Core中使用GraphQL - 第二章 中间 ...

  7. ASP.NET Core中使用GraphQL - 第九章 在GraphQL中处理多对多关系

    ASP.NET Core中使用GraphQL ASP.NET Core中使用GraphQL - 第一章 Hello World ASP.NET Core中使用GraphQL - 第二章 中间件 ASP ...

  8. ASP.NET Core中使用GraphQL - 第一章 Hello World

    前言 你是否已经厌倦了REST风格的API? 让我们来聊一下GraphQL. GraphQL提供了一种声明式的方式从服务器拉取数据.你可以从GraphQL官网中了解到GraphQL的所有优点.在这一系 ...

  9. ASP.NET Core中使用GraphQL - 第二章 中间件

    前文:ASP.NET Core中使用GraphQL - 第一章 Hello World 中间件 如果你熟悉ASP.NET Core的中间件,你可能会注意到之前的博客中我们已经使用了一个中间件, app ...

随机推荐

  1. java没有firendly访问类型

    java中只有public.private.protected.default这几种修饰符,没有friendly修饰符,没加修饰符就是friendly.friendly只是一种说法,把它认为是defa ...

  2. js生成带logo的二维码

    作为一名java程序员,一直以来都是使用服务端生成二维码,最近接触前端的设计,感觉二维码这块如果放到前端去生成,一方面可以减轻服务端的压力,访问带宽,另一方面,前端页面控制比较顺畅 闲话少叙,说下我的 ...

  3. BZOJ_3196_Tyvj 1730 二逼平衡树_树状数组套主席树

    BZOJ_3196_Tyvj 1730 二逼平衡树_树状数组套主席树 Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排 ...

  4. STM32标准库GPIO操作

    STM32标准库GPIO操作 STM32任何外围设备的使用都分为两部分:初始化和使用.体现在代码上就是:(1)有一个初始化函数(2)main函数中的使用 1.初始化GPIO 初始化GPIO函数代码: ...

  5. window 7 安装Jmeter并配置https录制脚本

    安装与环境配置: http://blog.csdn.net/hhuangdanfeng/article/details/51564765 http://blog.csdn.net/u010573212 ...

  6. sudo apt-get update: 0% [正在等待报头]

    问题描述:使用apt-get下载一个文件,由于下载的太慢,使用Ctrl+C强制结束.然后输入sudo apt-get update,想继续下载其他文件.结果出现如标题所示的错误,截图如下:按照网上说的 ...

  7. 七牛云免费对象存储,并绑定到cloudreve中

    之前开通了腾讯云的对象存储COS并使用中,不过之前主要将它当作云盘使用,这两天再做博客系统时发现也可以将它作为网站的图库,这样对网站的访问效率也会提高. 今天了解到七牛云有免费的对象存储可以使用,于是 ...

  8. SpringBoot框架与MyBatis集成,连接Mysql数据库

    SpringBoot是一种用来简化新Spring应用初始搭建及开发过程的框架,它使用特定方式来进行配置,使得开发人员不再需要定义样板化的配置.MyBatis是一个支持普通SQL查询.存储和高级映射的持 ...

  9. TensorFlow从1到2(二)续讲从锅炉工到AI专家

    图片样本可视化 原文第四篇中,我们介绍了官方的入门案例MNIST,功能是识别手写的数字0-9.这是一个非常基础的TensorFlow应用,地位相当于通常语言学习的"Hello World!& ...

  10. 创建一个 Spring Boot 项目,你会几种方法?

    我最早是 2016 年底开始写 Spring Boot 相关的博客,当时使用的版本还是 1.4.x ,文章发表在 CSDN 上,阅读量最大的一篇有 42W+,如下图: 2017 年由于种种原因,就没有 ...