ASP.NET Core中使用GraphQLhtml
本篇中我将演示如何配置持久化仓储,这里原文中是使用的Postgres
, 这里我改用了EF Core For SqlServer
。本文的例子须要在上一篇的代码基础上修改。没有代码的同窗,能够去https://github.com/lamondlu/GraphQL_Blogs/tree/master/Part%20V下载。git
以前咱们编写了一个DataStore
类,里面硬编码了一个数据集合,这里咱们但愿改用依赖注入的方式进行解耦,因此首先咱们须要建立一个抽象接口IDataStore
。github
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个初始数据。json
下面咱们修改DataStore
类, DataStore
应该实现IDataStore
接口, 其中的GetItemByBarcode
和GetItems
方法须要改成从数据库中读取。c#
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配置api
services.AddDbContext<ApplicationDbContext>(option => { option.UseSqlServer(Configuration.GetConnectionString("SampleDB")); });
TIPS: 这里注意不要忘记建立一个
appsettings.json
, 在其中添加数据库链接字符串多线程
配置完成以后,咱们须要使用如下命令添加Migration,并更新数据库app
dotnet ef migrations add Initial dotnet ef database update
如今针对数据库的修改都已经完成了。async
另外咱们还须要修改服务注册代码,将注册服务的生命周期从单例(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