博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
GraphQL ---02 GraphQL和C#结合的实战项目
阅读量:6809 次
发布时间:2019-06-26

本文共 7711 字,大约阅读时间需要 25 分钟。

本文章是介绍和记录如何创建GraphQL项目,以及如何使用GraphQL进行数据的相关操作。项目参照进行实践

一、项目结构:

  为了更好的和原有的项目结合在一起,尽可能减少对原项目的修改。我对项目结构做了如下分层。

二、项目结构分层说明

  Contracts层: 项目的接口层,重点存放项目的一些接口。和原项目的分层结构的Contracts一致

  Entities层: 实体模型层,存放实体模型。与原有项目的分层结构Entites层一致

  GraphQLDemo: 是使用Console控制台应用程序对GraphQL的调用实例

  GraphQLs: 使用GraphQL 的模型定义和查询、变更等操作的定义

  Services: 提供服务的具体实现层,和原有项目分层中的Services 层一致

  Tests: 使用Unit Test 测试调用GraphQL

在这里重点关注 标红的部分的介绍

三、GraphQLs项目介绍:

  GraphQLs重点是存储项目的GraphQL操作相关的内容

  1.在项目解决方案中,新建程序集,命名为GraphQLs

  2. 安装Graphql

NuGet 搜索 GraphQL

  3.创建GraphQL 的相关概念

  GraphQL有两种方式创建Schema,

    • 一种是使用Schema First,也就是使用创建Schema. 可以对比EntityFramework的DB First
    • 一种是使用Graph Type定义Schema,可以对比EntityFramework 的Code First

  在这里适用Code First定义数据模型,可以与原有的数据服务应用一起使用。可分为以下步骤:

  1)定义数据模型:

  假设原有的数据模型Book的结构是这样的:

public class User    {        public int Id { get; set; }        public string Name { get; set; }        public int Age { get; set; }        public string Gender { get; set; }    }

  那么定义对应的GraphQL的数据模型可以是这样的:

public class UserType:ObjectGraphType
// 继承自ObjectGraphType,并传递范型User { public UserType()// 在构造函数中,对属性作影射 { Name = "User"; Field(x => x.Id); Field(x => x.Name); Field(x => x.Age); Field(x => x.Gender); } }

  2)定义操作模型: 

  GraphQL的操作分为: Query(Select), Mutation(Create,Update,Delete),Subscription(订阅)

  • 定义Query操作
public class Query : ObjectGraphType// 定义Query    {        private IWrapper wrapper = new Wrapper();        IEnumerable
users = null; public Query() { Field
>(//在构造函数中定义查询操作 name: "users", //注意这个名字,后边查询的时候需要对应 arguments: new QueryArguments //定义查询参数 { new QueryArgument
{ Name = "name", Description = "The name for the user" }, new QueryArgument
{ Name = "age", Description = "The age for the user" }, new QueryArgument
{ Name = "gender", Description = "The gender for user" } }, resolve: context =>// 定义查询操作的执行 { var usercontext = context.UserContext;// 获取上下文,可在此作用户验证操作 users = wrapper.User.Find(u => true); var name = context.GetArgument
("name"); users = users.Where(u => name == null || u.Name == name); var age = context.GetArgument
("age"); users = users.Where(u => age == null || u.Age == age); var gender = context.GetArgument
("gender"); users = users.Where(u => gender == null || u.Gender == gender); return users; });     } }
  • 定义Mutation操作
public class Mutation:ObjectGraphType    {        private IWrapper wrapper = new Wrapper();        IEnumerable
users = null; public Mutation() { Field
( name: "createUser", arguments: new QueryArguments( new QueryArgument
> { Name = "user" } ), resolve: context => { var user = context.GetArgument
("user"); return wrapper.User.Add(user); } ); } }

  3. 定义GraphSchema

  定义GraphSchema就是定义Schema的Query、Mutation、Subscription操作

public class GraphSchema:Schema    {        public GraphSchema()        {            Query = new Query();            Mutation = new Mutation();        }    }

  4. 附.

  为了检验查询、修改操作,这里定义一个GraphQLQuery来定义操作,并定义一个查询操作类

public class GraphQLQuery    {        public string OperationName { get; set; }        public string NamedQuery { get; set; }        public string Query { get; set; }        public object UserContext { get; set; }        public JObject Variables { get; set; }    }
public class ActionExecute    {        private IDocumentExecuter executer;        private IDocumentWriter writer;        private ISchema schema;        public ActionExecute()        {            executer = new DocumentExecuter();            writer = new DocumentWriter();            schema = new GraphSchema();        }        public async Task
ExecuteAction(GraphQLQuery query) { var result = await executer.ExecuteAsync(_ => { _.Schema = schema; _.Query = query.Query; _.Inputs = query.Variables.ToInputs();// 查询变量的输入 _.OperationName = query.OperationName;// 操作名称 _.UserContext = query.UserContext;// 添加用户上下文对象 _.ValidationRules = DocumentValidator.CoreRules(); // 添加自定义查询验证 逻辑 _.ExposeExceptions = true;// 是否追踪错误 _.FieldMiddleware.Use
(); // 使用中间件 _.EnableMetrics = true;// 是否使用查询度量 _.ComplexityConfiguration = new ComplexityConfiguration // 防止恶意查询 { MaxComplexity = 12, MaxDepth = 15 // 允许查询总最大嵌套数 }; }); return result; } public async Task
Execute(GraphQLQuery query) { var result = await ExecuteAction(query).ConfigureAwait(false); var json = await writer.WriteToStringAsync(result); return json; } }

四、 测试和检验

  一切准备就绪,下边对创建的GraphQL进行测试

  1. 查询测试:
public class QueryTest    {        private ActionExecute execute = new ActionExecute();        [Fact]        public void TestMethod1()        {            Assert.True(1 == 1);        }        [Theory]        [InlineData(16, "Male")]        [InlineData(18, "FeMale")]        public async void QueryUsers(int age, string gender)        {            var queryStr = @"{users(age:" + age + ",gender:" + "\"" + gender + "\"" + "){id name gender age}}";            var result = await execute.ExecuteAction(new GraphQLQuery { Query = queryStr,UserContext= "Add Role" });            var data = result.Data;            Assert.Null(result.Errors?.Count);        }    }

  为了检验GraphQL的查询优越性,你可以修改一下queryStr=@"{users{id name gender age}}"; 或queryStr=@"{users{gender age}}";queryStr=@"{users{ name age}}";注意这里的@和{}只是C# 对字符串操作的一种方式。

  发现了什么?

  如果我们在前端(Web、微信小程序、手机APP),在web端,作为后台管理系统,我可能需要获取用户的所有信息,那么我可能需要使用queryStr=@"{users{id name gender age}}"。在微信小程序端,我只要根据用户的id查询用户名字就可以了,那么我只用变动查询语句:queryStr=@"{users(id){ name}}";

  意味着什么?

  意味着我们只需要提供一个API接口,该端口接受传递的查询字符串就可以了。所有的实体都可以只用这一个接口了。想查询什么,由前端决定了,再也不需要追着后端接口开发工程师要数据了。我想这样以来,前端和后端只需要一个接口沟通,会比REST API来的更方便了。

2.变更测试:

public class MutationTest    {        private ActionExecute execute = new ActionExecute();        [Theory]        [InlineData(16, "Test1")]        [InlineData(18, "Test2")]        public async void CreateUser(int age, string name)        {            var queryStr = @"{query: mutation ($user: UserInput!){createUser(user:$user){id name age}},variables:{user:{name: " + name + @",age:" + age + @"}}}";            var query = new GraphQLQuery            {                Query = "mutation ($user: UserInput!){createUser(user:$user){id name age}}",                Variables = JObject.Parse("{user:{\"name\": \"" + name + "\",\"age\":" + age + "}}")            };            var result = await execute.ExecuteAction(query);            Assert.Null(result.Errors.Count);        }    }

  发现了什么?

  同样的。我们只需要传递查询的参数,传递对应的参数Variables 就能完成修改动作。同时,该变更和查询的操作字符串语句很像,只是多了一个mutation。

五、后续

  这篇文章只是介绍了使用控制台和UnitTest测试使用了GraphQL,后续会更新在Asp.Net Core MVC 中使用GraphQL,也可以学习杨旭的文章。很好的博主

 

转载于:https://www.cnblogs.com/kingkangstudy/p/10471751.html

你可能感兴趣的文章
2017 ZSTU寒假排位赛 #5
查看>>
如何查看gpio 使用状态,以及被那些模块request
查看>>
MyBatis-SELECT基本查询
查看>>
通配符&&选择器
查看>>
2013与2014之流水
查看>>
call Kernelized Correlation Filters Tracker(Matab) in Qt(c++)
查看>>
CodeForces 292D Connected Components (并查集+YY)
查看>>
函数式编程
查看>>
为什么要有mmu
查看>>
1018. Binary Prefix Divisible By 5可被 5 整除的二进制前缀
查看>>
webform 组合查询
查看>>
java多态 -- 猫狗案列
查看>>
Oracle 相关知识点结构图
查看>>
一个简单的软件工程流程
查看>>
BZOJ2653middle——二分答案+可持久化线段树
查看>>
BZOJ4543[POI2014]Hotel加强版——长链剖分+树形DP
查看>>
x=n; y=1; while(x>=(y−1)∗(y−1)) y++; 以上程序的时间复杂度为 ?
查看>>
A joke about regular expression
查看>>
【UIKit】UITableView 5
查看>>
常用颜色代码
查看>>