GraphQL 既是一种用于 API 的查询语言也是一个满足你数据查询的运行时。GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得它需要的数据,而且没有任何冗余,也让 API 更容易地随着时间推移而演进,还能用于构建强大的开发者工具。
——出自 https://graphql.cn
HotChocolate可以通过自定义Directive来对字段的值进行转换和处理,下在的例子就是给字符串给字符串类型的值转大写和替换。
using HotChocolate;
using HotChocolate.Data;
using HotChocolate.Execution;
using HotChocolate.Types;
using System;
using System.Collections.Generic;
using System.Reflection;namespace GraphQLBase003
{class Program{static void Main(string[] args)
{DirectiveDemo.Run();}}public class DirectiveDemo{public static void Run()
{var schema = SchemaBuilder.New().AddProjections().AddQueryType<Query>().AddDirectiveType<UpperDirectiveType>().AddDirectiveType<ReplaceDirectiveType>().Create();var executor = schema.MakeExecutable();Console.WriteLine("原name=abcde ");Console.WriteLine("--------------转大写-------------------");Console.WriteLine(executor.Execute("{ student{id name @upper(name:\"this is test\") age} }").ToJson());Console.WriteLine("--------------a替换成1 -------------------");Console.WriteLine(executor.Execute("{ student{id name @replace(old:\"a\",new:\"1\") age} }").ToJson());Console.WriteLine("--------------然后全部转大写-.a替换成1 -------------------");Console.WriteLine(executor.Execute("{ student{id name @upper(name:\"this is test\") @replace(old:\"a\",new:\"1\") age} }").ToJson());Console.WriteLine("--------------a替换成1.然后全部转大写-------------------");Console.WriteLine(executor.Execute("{ student{id name @replace(old:\"a\",new:\"1\") @upper(name:\"this is test\") age} }").ToJson());}public class Query{[UseProjection]public Student GetStudent()
{return new Student{Id = 1,Name = "abcde",Age = 234};}[UseProjection]public List<Student> GetStudents(){return new List<Student>{new Student{Id = 100,Name = "aBcD",Age=10},new Student{Id = 101,Name = "EFGH",Age=20}};}}public class Student{public int Id { get; set; }public string Name { get; set; }public int Age { get; set; }}public class UpperDirectiveType : DirectiveType<UpperDirective>{protected override void Configure(IDirectiveTypeDescriptor<UpperDirective> descriptor)
{descriptor.Name("upper");descriptor.Location(DirectiveLocation.Field);descriptor.Use(next => context =>{foreach (var directive in context.FieldSelection.Directives){if (directive.Name.Value == "upper"){if (context.Field.Member.MemberType == System.Reflection.MemberTypes.Property){var pro = context.Field.Member as PropertyInfo;var obj = context.GetType().GetMethod("Parent").MakeGenericMethod(context.ObjectType.RuntimeType).Invoke(context, new object[0]);var value = pro.GetValue(obj);pro.SetValue(obj, value.ToString().ToUpper()); }}}return next.Invoke(context);});}}public class UpperDirective{public string Name{get;set;}}public class ReplaceDirectiveType : DirectiveType<ReplaceDirective>{protected override void Configure(IDirectiveTypeDescriptor<ReplaceDirective> descriptor)
{descriptor.Name("replace");descriptor.Location(DirectiveLocation.Field);descriptor.Use(next => context =>{foreach (var directive in context.FieldSelection.Directives){if (directive.Name.Value == "replace"){var dir = new Dictionary<string, object>();foreach (var item in directive.Arguments){dir.Add(item.Name.Value?.ToLower(), item.Value.Value);}if (context.Field.Member.MemberType == System.Reflection.MemberTypes.Property){ var s = context.Parent<Student>();var pro = context.Field.Member as PropertyInfo;var obj = context.GetType().GetMethod("Parent").MakeGenericMethod(context.ObjectType.RuntimeType).Invoke(context, new object[0]);var value = pro.GetValue(obj);pro.SetValue(obj, value.ToString().Replace(dir["old"].ToString(), dir["new"].ToString())); }}}return next.Invoke(context);});}}public class ReplaceDirective{public string Old{get;set;}public string New{get;set;}}}
}
upper和replace两个Directive处理的还比较粗糙,这里主要说明Directive的定义方式;在调用这些Directive时,按照前后顺序调用,多个Directive可以同时生效,和asp.net core的中间件原理相近,上例的后两个调用 name @upper @replace和name @replace @upper返回的结果是不一样的。