zoukankan      html  css  js  c++  java
  • ASP.NET Core中使用GraphQL

    出处:https://www.cnblogs.com/lwqlun/p/9937468.html 

    ASP.NET Core中使用GraphQL


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

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

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

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

    Copy
    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方法需要改为从数据库中读取。

    Copy
    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配置

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

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

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

    Copy
    dotnet ef migrations add Initial
    dotnet ef database update

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

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

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

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

    Copy
    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方法注入。

    中间件最终代码如下:

    Copy
    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

     
  • 相关阅读:
    Power BI 根据用户权限动态生成导航跳转目标
    Power BI Tooltips 增强功能
    Power BI refresh error “could not load file or assembly…provided impersonation level is invalid”
    SQL 错误代码 18456
    如何使用SQL Server Integration Services从多个Excel文件读取数据
    通过表格编辑器将现有表引入Power BI数据流
    Power BI 中动态增长的柱状图
    ambari2.7.3离线安装hdp3.1.0时,ambari-hdp-1.repo中baseurl无值
    ambari 安装 cannot download file mysql-connector-java from http://8080/resource/mysql-connector-java.jar
    洛谷P4180 [BJWC2010]严格次小生成树
  • 原文地址:https://www.cnblogs.com/lhxsoft/p/11903556.html
Copyright © 2011-2022 走看看