Hot Chocolate 构建 GraphQL .Net Core 服务
Hot Chocolate 是 .NET 平台下的一个开源组件库, 您可以使用它创建 GraphQL 服务, 它消除了构建成熟的 GraphQL 服务的复杂性, Hot Chocolate 可以连接任何服务或数据源,并创建一个有凝聚力的服务,为您的消费者提供统一的 API。
我会在 .NET 应用中使用 Hot Chocolate 组件来构建 GraphQL 服务, 让我们开始吧!
创建服务
- 创建一个GraphQL服务
安装nuget包:
HotChocolate.AspNetCore // GraphQL - HotChocolate实现包
HotChocolate.Data.EntityFramework //HotChocolate-IQueryable 实现包
HotChocolate.Subscriptions.Redis //redis订阅
Microsoft.EntityFrameworkCore.SqlServer //orm ef sqlServer
Microsoft.EntityFrameworkCore.Tools //ef 工具
builder.Services.AddGraphQLServer()
使用Hot Chocolate
- 新增一个Query
builder.Services.AddQueryType<MyQuery>()//一个Query,所有Query写在一起
public class MyQuery{[UseOffsetPaging][UseProjection][UseFiltering][UseSorting]public IQueryable<Superhero> GetSuperheroes([Service] ApplicationDbContext context) =>context.Superheroes;[UseOffsetPaging][UseProjection][UseFiltering][UseSorting]public IQueryable<Movie> GetMovies([Service] ApplicationDbContext context) =>context.Movies;[UseOffsetPaging][UseProjection][UseFiltering][UseSorting]public IQueryable<Superpower> GetSuperpowers([Service] ApplicationDbContext context) =>context.Superpowers;}
- 使用特性 搜索、排序、投影
builder.Services.AddProjections()
.AddFiltering()
.AddSorting()
.SetPagingOptions(new PagingOptions
{
MaxPageSize = 10000,
DefaultPageSize = 10,
IncludeTotalCount = true
});
- 创建多个Query,通过ExtendObjectType("Query")关联
.AddQueryType(q => q.Name("Query")).AddTypeExtension<SuperheroQuery>().AddTypeExtension<MovieQuery>().AddTypeExtension<SuperpowerQuery>()[ExtendObjectType("Query")]public class SuperheroQuery{[UseOffsetPaging][UseProjection]//始终显示的数据字段,无论是否查询该字段[UseFiltering][UseSorting][GraphQLDescription("获取超级英雄集合")]public IQueryable<Superhero> GetSuperheroes([Service] ApplicationDbContext context) =>context.Superheroes;}
- 创建Mutation&自定义错误信息
.AddMutationType(m => m.Name("Mutation")).AddTypeExtension<SuperheroMutation>()[ExtendObjectType("Mutation")]public class SuperheroMutation{public async Task<Boolean> AddSuperheroAsync(SuperheroDto superhero, [Service] ISuperheroRepository _repository, [Service] ITopicEventSender sender){var (Success, KeyId) = await _repository.AddSuperheroAsync(superhero);await sender.SendAsync("SuperheroModified", superhero);return Success;}[Error(typeof(NameTakenException))]public async Task<Boolean> UpdateSuperheroAsync([ID] Guid Id, string name, [Service] ISuperheroRepository _repository, [Service] ITopicEventSender sender){var Success = await _repository.UpdateSuperheroAsync(Id, name);await sender.SendAsync("SuperheroModified", new SuperheroDto{Id = Id,Name = name,Description = "",Height = 0,Movies = null,Superpowers = null});return Success;}}public class NameTakenException : Exception{public NameTakenException(string username): base($"The name {username} is already taken."){}}
- 创建指令
.AddDirectiveType<ToUpperDirectiveType>().AddType<toLowerDirective>()/// <summary>/// 转大写指令/// </summary>public class ToUpperDirectiveType : DirectiveType{protected override void Configure(IDirectiveTypeDescriptor descriptor){descriptor.Name("toupper");//descriptor.Argument("name").Type<NonNullType<StringType>>();descriptor.Location(DirectiveLocation.Field);//https://chillicream.com/docs/hotchocolate/v13/execution-engine/field-middleware/#field-middleware-as-a-class//中间件 descriptor.Use((next, directive) =>{return async context =>{await next(context);if (context.Result is string str){context.Result = str.ToUpper();}else{context.ReportError("Bad Request.");context.OperationResult.SetResultState(WellKnownContextData.HttpStatusCode, 500);}};});}}/// <summary>/// 转小写指令/// 属性模式/// </summary>[DirectiveType(DirectiveLocation.Field)][toLowerDirectiveMiddleware]public class toLowerDirective{}/// <summary>/// 指令中间件/// </summary>public class toLowerDirectiveMiddlewareAttribute : DirectiveTypeDescriptorAttribute{protected override async void OnConfigure(IDescriptorContext context, IDirectiveTypeDescriptor descriptor, Type type){descriptor.Use((next, directive) =>{return async context =>{await next(context);if (context.Result is string str){context.Result = str.ToLower();}else{context.ReportError("Bad Request.");context.OperationResult.SetResultState(WellKnownContextData.HttpStatusCode, 500);}};});}}
- 创建订阅(通过webSocket方式)
.AddInMemorySubscriptions()//.AddRedisSubscriptions((sp) => ConnectionMultiplexer.Connect("127.0.0.1:6379,password=Michael,defaultDatabase=2")).AddSubscriptionType(q => q.Name("Subscription")).AddTypeExtension<SuperheroSubscribe>()//.AddSubscriptionType<SuperheroSubscribe>()//指定一个订阅类,所有订阅写在一起[ExtendObjectType("Subscription")]public class SuperheroSubscribe{[Subscribe][Topic("SuperheroUpdated")]public async Task<SuperheroDto> SuperheroUpdated([EventMessage] SuperheroDto superherodto, [Service] ISuperheroRepository _repository){var ret = await _repository.UpdateSuperheroAsync(superherodto.Id, $"{superherodto.Name}_{DateTime.Now.ToString("yyMMdd")}");superherodto.Description = "Subscribe-SuperheroModified";return superherodto;}#region 混合模式(订阅逻辑和解析器分离)/// <summary>/// 数据逻辑处理/// </summary>/// <param name="receiver"></param>/// <returns></returns>public async IAsyncEnumerable<SuperheroDto> SubscribeToSuperheroDto([Service] ITopicEventReceiver receiver, [Service] ISuperheroRepository _repository){yield return new SuperheroDto { Id = Guid.NewGuid(), Name = $"Name-{DateTime.Now.ToString("HHmmss")}" };//return ISourceStream<SuperheroDto>var source = await receiver.SubscribeAsync<SuperheroDto>("SuperheroModified");Task.Delay(3000);await foreach (SuperheroDto superherodto in source.ReadEventsAsync()){superherodto.Name = $"{superherodto.Name}_{DateTime.Now.ToString("HHmmss")}";var ret = await _repository.UpdateSuperheroAsync(superherodto.Id, superherodto.Name);yield return superherodto;}}/// <summary>/// 订阅/// 服务端必须开启websocket/// 订阅人监听websocket/// </summary>/// <param name="superherodto"></param>/// <param name="_repository"></param>/// <returns></returns>[Topic("SuperheroModified")][Subscribe(With = nameof(SubscribeToSuperheroDto))]public async Task<SuperheroDto> SuperheroModified([EventMessage] SuperheroDto superherodto){return superherodto;}#endregion}
必须先链接WebSocket,Mutation事件才会推送 ,GraphQL语法
subscription{superheroUpdated {idnamedescription}
}
Promgram 整体配置
var builder = WebApplication.CreateBuilder(args);Microsoft.Extensions.Configuration.ConfigurationManager configuration = builder.Configuration;// Add services to the container.builder.Services.AddControllers();// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbucklebuilder.Services.AddEndpointsApiExplorer();builder.Services.AddSwaggerGen();builder.Services.AddGraphQLServer().AddInMemorySubscriptions()//.AddRedisSubscriptions((sp) => ConnectionMultiplexer.Connect("127.0.0.1:6379,password=Michael,defaultDatabase=2")).AddSubscriptionType(q => q.Name("Subscription")).AddTypeExtension<SuperheroSubscribe>()//.AddSubscriptionType<SuperheroSubscribe>()//指定一个订阅类,所有订阅写在一起//.AddTypeExtensionsFromFile("./Stitching.graphql")//.ModifyOptions(options =>//{// /*// * code-first模式-Explicit:显示绑定(手动绑定字段,或者使用ObjectType<T>-override Configure手动设置)// * 显示绑定 必须所有数据都要声明包括 Tsortinput,Tinput,TOperationFilterInput等。。。// * Annotation-based模式-Implicit:隐式绑定(默认展示所有字段,或者使用ObjectType<T>-override Configure手动设置)// * GraphQLIgnoreAttribute 可过滤不需要的字段// */// options.DefaultBindingBehavior = BindingBehavior.Explicit;//}).AddType<SuperheroType>().AddType<MovieType>().AddType<SuperpowerType>()//.AddQueryType<MyQuery>()//一个Query,所有Query写在一起.AddQueryType(q => q.Name("Query")).AddTypeExtension<SuperheroQuery>().AddTypeExtension<MovieQuery>().AddTypeExtension<SuperpowerQuery>().AddMutationType(m => m.Name("Mutation")).AddTypeExtension<SuperheroMutation>().AddProjections().AddFiltering().AddSorting().SetPagingOptions(new PagingOptions{MaxPageSize = 10000,DefaultPageSize = 10,IncludeTotalCount = true}).AddDirectiveType<MyDirectiveType>().AddDirectiveType<ToUpperDirectiveType>().AddType<toLowerDirective>();string appRoot = builder.Environment.ContentRootPath;Environment.SetEnvironmentVariable("AppDataDirectory", System.IO.Path.Combine(appRoot, "App_Data"));var SqlServerConnStr = Environment.ExpandEnvironmentVariables(configuration.GetConnectionString("SqlServer"));// Add Application Db Context optionsbuilder.Services.AddDbContext<ApplicationDbContext>(options =>options.UseSqlServer(SqlServerConnStr));// Register custom services for the superheroesbuilder.Services.AddScoped<ISuperheroRepository, SuperheroRepository>();builder.Services.AddScoped<ISuperpowerRepository, SuperpowerRepository>();builder.Services.AddScoped<IMovieRepository, MovieRepository>();var app = builder.Build();// Configure the HTTP request pipeline.if (app.Environment.IsDevelopment()){app.UseSwagger();app.UseSwaggerUI();}app.UseHttpsRedirection();app.UseAuthorization();app.MapControllers();//使用GraphQL-Subscription 必须开启websocketapp.UseWebSockets();//https://blog.christian-schou.dk/how-to-implement-graphql-in-asp-net-core/app.MapGraphQL();app.Run();
- https://localhost:7199/graphql/
通过Strawberry Shake,自动链接GraphQL服务,创建客户端
Introduction - Strawberry Shake - ChilliCream GraphQL Platform
NSwagStudio,通过Swagger.json 文档创建 TypeScript Client、CSharp Client、CSharp Controller
NSwagStudio · RicoSuter/NSwag Wiki · GitHub
相关文章:
Hot Chocolate 构建 GraphQL .Net Core 服务
Hot Chocolate 是 .NET 平台下的一个开源组件库, 您可以使用它创建 GraphQL 服务, 它消除了构建成熟的 GraphQL 服务的复杂性, Hot Chocolate 可以连接任何服务或数据源,并创建一个有凝聚力的服务,为您的消费者提供统一的 API。 我会在 .NET 应用中使用…...
linux shell 入门学习笔记16 流程控制开发
shell的流程控制一般包括if、for、while、case/esac、until、break、continue语句构成。 if语句开发 单分支if //方式1 if <条件表达式> then 代码。。。 fi //方式2 if <条件表达式>;then 代码。。。 fi 双分支if if <条件表达式> then 代码1 if <条件表…...
机器学习:基于朴素贝叶斯对花瓣花萼的宽度和长度分类预测
机器学习:基于朴素贝叶斯对花瓣花萼的宽度和长度分类预测 作者:AOAIYI 作者简介:Python领域新星作者、多项比赛获奖者:AOAIYI首页 😊😊😊如果觉得文章不错或能帮助到你学习,可以点赞…...
给VivoBook扩容重装系统
现在笔记本重装系统都这么复杂吗?原谅我还是10年前的装机水平,折腾了一天终于把系统重新安装好了。 笔记本: ASUS VivoBook 安装系统: Win10 1、扩容 电脑配的512G硬盘满了要换个大的,后盖严丝合缝,不…...
vue 依赖注入使用教程
vue 中的依赖注入,官网文档已经非常详细,笔者在这里总结一份 目录 1、背景介绍 2、代码实现 2.1、依赖注入固定值 2.2、 依赖注入响应式数据 3、注入别名 4、注入默认值 5、应用层 Provide 6、使用 Symbol 作注入名 1、背景介绍 为什么会出现依…...
【再临数据结构】Day1. 稀疏数组
前言 这不单单是稀疏数组的开始,也是我重学数据结构的开始。因此,在开始说稀疏数组的具体内容之前,我想先说一下作为一个有着十余年“学龄”的学生,所一直沿用的一个学习方法:3W法。我认为,只有掌握了正确的…...
二十四、MongoDB 聚合运算( aggregate )
MongoDB 聚合( aggregate ) 用于处理数据,比如统计平均值,求和等。然后返回计算后的数据结果 MongoDB 聚合有点类似 SQL 语句中的 COUNT( * ) aggregate() 方法 MongoDB aggregate() 为 MongoDB 数据库提供了聚合运算 语法 aggregate() 方法的语法如下 > d…...
【C++】6.模板初阶
交换两个数 任何一个类型交换还要重新写一个函数 如何解决? 模板->写跟类型无关的函数 1.泛型编程 泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。 如何写一个函数适用所有类型的交换? #include &…...
Docker部署Airbyte
Linux环境部署前置要求机器配置2c4g(最低),4c8g(推荐)dockerdocker-compose (要求新版本的docker-compose)安装airbyte,打开终端,进入你想安装airbyte的目录。#Clone代码 git clone https://github.com/air…...
2023王道考研数据结构笔记第一章绪论
第一章 绪论 1.1 数据结构的基本概念 1.数据:数据是信息的载体,是描述客观事物属性的数、字符以及所有能输入到计算机中并被程序识别和处理的符号的集合。 2.数据元素:数据元素是数据的基本单位,通常作为一个整体进行考虑和处理…...
告别空指针让代码变优雅,Optional使用图文例子源码解读
一、前言 我们在开发中最常见的异常就是NullPointerException,防不胜防啊,相信大家肯定被坑过! 这种基本出现在获取数据库信息中、三方接口,获取的对象为空,再去get出现! 解决方案当然简单,只…...
【C++】哈希——unordered系列容器|哈希冲突|闭散列|开散列
文章目录一、unordered系列关联式容器二、哈希概念三、哈希冲突四、哈希函数五、解决哈希冲突1.闭散列——开放定址法2.代码实现3.开散列——开链法4.代码实现六、结语一、unordered系列关联式容器 在C98中,STL提供了底层为红黑树结构的一系列关联式容器,…...
mysql-面试
锁: mysql的锁分为全局锁、表锁、行锁、间隙锁 全局锁:Flush tables with read lock 可以全局设计库为只读 表锁:一种是表锁,一种是元数据锁(meta data lock,MDL) lock tables t1 read,t2 wi…...
【夏虫语冰】Win10局域网下两台电脑无法ping通: 无法访问目标主机
文章目录1、简介2、修改高级共享设置3、启用防火墙规则4、局域网内的其他主机访问NAT模式下的虚拟机4.1 虚拟机网络设置4.2 访问测试4.2.1 http测试4.2.2 curl测试4.2.3 telnet测试4.2.4 端口占用测试5、其他结语1、简介 ping 192.168.31.134ping主机ip时,访问无法…...
大数据框架之Hadoop:MapReduce(三)MapReduce框架原理——Join多种应用
3.7.1Reduce Join 1、工作原理 Map端的主要工作:为来自不同表或文件的key/value对,打标签以区别不同来源的记录。然后用连接字段作为key,其余部分和新加的标志作为value,最后进行输出。 Reduce端的主要工作:在Reduc…...
SSRF漏洞原理、危害以及防御与修复
一、SSRF漏洞原理漏洞概述SSRF(Server-side Request Forge,服务端请求伪造)是一种由攻击者构造形成由服务端发起请求的安全漏洞。一般情况下,SSRF攻击的目标是从外网无法访问的内部系统。正是因为它是由服务端发起的,所…...
CV学习笔记-ResNet
ResNet 文章目录ResNet1. ResNet概述1.1 常见卷积神经网络1.2 ResNet提出背景2. ResNet网络结构2.1 Residual net2.2 残差神经单元2.3 Shortcut2.4 ResNet50网络结构3. 代码实现3.1 Identity Block3.2 Conv Block3.3 ResNet网络定义3.4 整体代码测试1. ResNet概述 1.1 常见卷积…...
百亿数据,毫秒级返回查询优化
近年来公司业务迅猛发展,数据量爆炸式增长,随之而来的的是海量数据查询等带来的挑战,我们需要数据量在十亿,甚至百亿级别的规模时依然能以秒级甚至毫秒级的速度返回,这样的话显然离不开搜索引擎的帮助,在搜…...
cpp之STL
STL原理 STL ⼀共提供六⼤组件,包括容器,算法,迭代器,仿函数,适配器和空间配置器,彼此可以组合套⽤。容器通过配置器取得数据存储空间,算法通过迭代器存取容器内容,仿函数可以协助算…...
基于Spring Boot开发的资产管理系统
文章目录 项目介绍主要功能截图:登录首页信息软件管理服务器管理网络设备固定资产明细硬件管理部分代码展示设计总结项目获取方式🍅 作者主页:Java韩立 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项目…...
Markdown总结
文字的着重标记与段落的层次划分 Tab键可以缩进列表; shift Tab:取消缩进列表 加粗(****)、斜体(**)高亮:xxx$$:特殊标记删除:~~xxx~~多级标题:######无序列…...
字节跳动软件测试岗4轮面经(已拿34K+ offer)...
没有绝对的天才,只有持续不断的付出。对于我们每一个平凡人来说,改变命运只能依靠努力幸运,但如果你不够幸运,那就只能拉高努力的占比。 2021年10月,我有幸成为了字节跳动的一名测试工程师,从外包辞职了历…...
docker - 搭建redis集群和Etcd
概述 由于业务需要,需要把之前的分布式架构调整成微服务,把老项目迁移到k8s的服务中,再开始编码之前,需要再本地环境里做相应的准备工作,使用docker搭建redis集群,Etcd主要是注册本地的rpc服务。 Liunx O…...
Java程序开发中如何使用lntelliJ IDEA?
完成了IDEA的安装与启动,下面使用IDEA创建一个Java程序,实现在控制台上打印HelloWorld!的功能,具体步骤如下。 1.创建Java项目 进入New Project界面后,单击New Project选项按钮创建新项目,弹出New Project对话框&…...
【Linux】理解进程地址空间
🍎作者:阿润菜菜 📖专栏:Linux系统编程 我们在学习C语言的时候,都学过内存区域的划分如栈、堆、代码区、数据区这些。但我们其实并不真正理解内存 — 我们之前一直说的内存是物理上的内存吗? 前言 我们…...
Unity脚本 --- 常用API(类)--- GameObject类 和
第一部分 --- GameObject类 1.在Hierarchy 层级面板中添加游戏物体其实就相当于在场景中添加游戏物体 2.每一个场景都有一个自己的Hierarchy层级面板,用来管理场景中的所有游戏物体 3.是的,我们可以创建多个场景 1.首先上面这两个变量都是布尔变量&am…...
HTML标签——表格标签
HTML标签——表格标签 目录HTML标签——表格标签一、表格标题和表头单元格标签场景:注意点:案例实操小结二、表格的结构标签场景:注意点:案例实操:三、合并单元格思路场景:代码实现一、表格标题和表头单元格…...
Telerik JustMock 2023 R1 Crack
Telerik JustMock 2023 R1 Crack 制作单元测试的最快、最灵活和模拟选项。 Telerik JustLock也很简单,可以使用一个模拟工具来帮助您更快地生成更好的单元测试。JustLock使您更容易创建对象并建立对依赖关系的期望,例如,互联网服务需求、数据…...
筑基八层 —— 问题思考分析并解决
目录 零:移步 一.修炼必备 二.问题思考(先思考) 三.问题解答 零:移步 CSDN由于我的排版不怎么好看,我的有道云笔记相当的美观,请移步有道云笔记 一.修炼必备 1.入门必备:VS2019社区版&#x…...
【面试题】当面试官问 Vue2与Vue3的区别,你该怎么回答?
大厂面试题分享 面试题库后端面试题库 (面试必备) 推荐:★★★★★地址:前端面试题库被问到 《vue2 与 vue3 的区别》应该怎么回答Vue 内部根据功能可以被分为三个大的模块:响应性 reactivite、运行时 runtime、编辑器…...
成都科技网站建设服务热线/大泽山seo快速排名
原文:Understanding Property Wrappers in SwiftUI 12 Jun 2019 上周,我们介绍了一系列关于 SwiftUI 框架的新帖子。今天,我将继续这个话题,介绍 SwiftUI 的属性包装器 Property Wrapper。SwiftUI 提供的属性包装器包括 State, Bi…...
好的h5网站模板/怎么弄属于自己的网站
创建一个库:_shop 创建三个表(对应的图有对应字段名): 菜单:menu 菜单分类:menu_type订单:order建表语句:create table menu(menu_id int unsigned auto_increment,menu_name varchar(100) not…...
百度推广网站建设费/搜索排名广告营销
2019独角兽企业重金招聘Python工程师标准>>> CSS的十八般技巧 一.使用css缩写 使用缩写可以帮助减少你CSS文件的大小,更加容易阅读。css缩写的主要规则请参看《常用css缩写语法总结》,这 里就不展开描述。 二.明确定义单位,除非值…...
网站移动页面怎么做的/seo点击器
当前版本中加入的公会战是公会间的攻城战玩法,以公会为参与单位。每周周二、周六21:00—22:00开启。在游戏主界面点击【公会】,然后点击【领地】页签,选择可进入的防守或进攻战场。【宣战规则】1、领地分为三层&#x…...
郑州富士康最新招聘/百度关键词优化公司
有些网络应用在网线断开后重新连上的情况下tcp socket连接保持ESTABLISH状态不变,假如应用程式不使用tcp的keepalive,在网线断开之后,以前建立的 socket 链接仍然会保持在ESTABLISH 状态不会改变。实际上tcp协议对这部分是有所处理的…...
太原做网站要多少钱呢/培训机构营业执照如何办理
点击上方“蓝色字”可关注我们!暴走时评:区块链作为欧洲最强大的经济体,德国对区块链技术在各个领域的应用都表现出了“极大的兴趣”,包括汽车、制药、能源和公共部门管理等。作者:Yogita Khatri 翻译:May…...