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