- 后端
【免费下载链接】graphql-dotnet
GraphQL for .NET
GraphQL.NET(graphql-dotnet)从 7.7 版本起内置了一组基于 Roslyn 的 C# 源码分析器(Analyzers),通过GQL001–GQL020一系列规则帮助开发者在编译期发现 GraphQL schema 定义中的常见错误。本文以仓库中的发布清单 AnalyzerReleases.Shipped.md 为骨架,逐条梳理每一版发布的规则、严重级别与用途,并结合 src/GraphQL.Analyzers 目录下的分析器源码与 docs2/site/docs/analyzers 的官方文档,讲清楚如何用.editorconfig配置这些规则、如何在项目中启用或禁用它们,以及规则背后的源码级实现原理。
一、GraphQL.NET 分析器是什么
GraphQL.NET 分析器是一组随 GraphQL.NET 一起分发的 Roslyn 诊断工具,它们在你编写 C# 代码(尤其是使用 Code-First 方式定义 GraphQL schema)时实时分析代码,识别潜在问题或改进点,并给出对应诊断信息(Diagnostic)。部分规则还附带代码修复(Code Fix),可以在 IDE 中一键自动修改。
从仓库结构看,分析器的全部实现位于 src/GraphQL.Analyzers 目录,包括 17 个分析器类、公共辅助类(DiagnosticIds.cs、DiagnosticCategories.cs)以及配套的代码修复项目 src/GraphQL.Analyzers.CodeFixes。分析器项目以netstandard2.0为目标框架(见 GraphQL.Analyzers.csproj),因此可以被旧版 .NET SDK 加载。
一个值得注意的工程细节是:该项目通过<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>启用了 Roslyn 分析器自身的扩展规则校验,并且在项目文件中把AnalyzerReleases.Shipped.md与AnalyzerReleases.Unshipped.md声明为AdditionalFiles,让发布追踪分析器(ReleaseTrackingAnalyzers)自动校验规则的增删是否被正确记录。这正是本文要解读的这份"发货清单"文件在整个工程中的角色。
二、发布时间线总览:规则如何演进
AnalyzerReleases.Shipped.md 按版本记录了所有已发布的分析器规则。从 v7.7 到 v8.1,规则经历了三次新增和一次移除:
| 版本 | 新增规则 | 移除规则 |
|---|---|---|
| 7.7.0 | GQL001、GQL002、GQL003、GQL004、GQL005、GQL006、GQL007、GQL008、GQL009、GQL011 | 无 |
| 7.9.0 | GQL015 | 无 |
| 8.0.0 | GQL010、GQL012、GQL013、GQL014、GQL016 | GQL005(ResolverAnalyzer) |
| 8.1.0 | GQL017、GQL018、GQL019、GQL020 | 无 |
全部 20 条规则都属于Usage类别(见 DiagnosticCategories.cs 中的USAGE常量)。规则的严重级别分为Warning与Error两档:早期的命名类规则(GQL001–GQL004、GQL006–GQL008)为警告级别,而涉及执行行为正确性的规则(GQL005、GQL009–GQL020)几乎全部是错误级别。
另外,AnalyzerReleases.Unshipped.md 用于登记尚未随正式版本发布的规则;截至当前仓库内容,该文件中的 New Rules 表格为空,说明没有处于"未发布"状态的规则。
三、规则速查表:GQL001–GQL020 一览
下表整合了发布清单、分析器类名与官方文档(位于 docs2/site/docs/analyzers,每个规则一份gqlXXX.md)中的信息,便于快速检索:
| 规则 ID | 规则名称 | 对应分析器 | 默认严重级别 | 引入版本 |
|---|---|---|---|---|
| GQL001 | 应在Field、Connection或ConnectionBuilder.Create方法中定义名称 | FieldNameAnalyzer | Warning | v7.7 |
| GQL002 | Name方法调用可以移除 | FieldNameAnalyzer | Warning | v7.7 |
| GQL003 | Field、Connection或ConnectionBuilder.Create与Name方法定义的名称不一致 | FieldNameAnalyzer | Warning | v7.7 |
| GQL004 | 不要使用过时的Field方法 | FieldBuilderAnalyzer | Warning | v7.7 |
| GQL005 | 非法的 resolver 用法(v8.0 起移除) | ResolverAnalyzer | Error | v7.7 |
| GQL006 | 无法将输入字段匹配到源字段 | InputGraphTypeAnalyzer | Warning | v7.7 |
| GQL007 | 无法设置源字段 | InputGraphTypeAnalyzer | Warning | v7.7 |
| GQL008 | 不要使用过时的Argument方法 | FieldArgumentAnalyzer | Warning | v7.7 |
| GQL009 | 使用异步 resolver | AwaitableResolverAnalyzer | Error | v7.7 |
| GQL010 | 无法解析输入源类型的构造函数 | InputGraphTypeAnalyzer | Error | v8.0 |
| GQL011 | 类型不得可转换为IGraphType | NotAGraphTypeAnalyzer | Error | v7.7 |
| GQL012 | 非法的属性(Attribute)用法 | AllowedOnAnalyzer | Error | v8.0 |
| GQL013 | OneOf字段必须可空(nullable) | OneOfAnalyzer | Error | v8.0 |
| GQL014 | OneOf字段不得有默认值 | OneOfAnalyzer | Error | v8.0 |
| GQL015 | 无法从表达式推断Field名称 | FieldBuilderAnalyzer | Error | v7.9 |
| GQL016 | 需要无参构造函数 | RequireParameterlessConstructorAnalyzer | Error | v8.0 |
| GQL017 | 找不到指定方法 | ParserValidatorAttributeAnalyzer | Error | v8.1 |
| GQL018 | Parser方法必须有效 | ParserAttributeAnalyzer | Error | v8.1 |
| GQL019 | Validator方法必须有效 | ValidatorAttributeAnalyzer | Error | v8.1 |
| GQL020 | ValidateArguments方法必须有效 | ValidateArgumentsAttributeAnalyzer | Error | v8.1 |
所有规则 ID 都被定义为常量,集中在 DiagnosticIds.cs 中;例如DEFINE_THE_NAME_IN_FIELD_METHOD = "GQL001"、PARSER_METHOD_MUST_BE_VALID = "GQL018"。从源码结构还可以看到,GQL005 的 ID 位置已保留注释// placeholder for ILLEGAL_RESOLVER_USAGE = "GQL005",印证了该规则在 v8.0 被移除的事实。
四、按版本逐条详解
4.1 v7.7.0:第一批命名与类型规则
v7.7 是分析器首次随 GraphQL.NET 发布的版本,一次性带来了 10 条规则,主要覆盖三类问题:schema 字段命名、过时 API 使用、输入类型与源类型的匹配。
GQL001 / GQL002 / GQL003(FieldNameAnalyzer)是一组关于字段命名的规则,均出自 FieldNameAnalyzer.cs。在 Code-First 方式下,开发者的常见写法是先调用Field<T>()再链式调用.Name("xxx"),而 GQL001 要求在Field、Connection或ConnectionBuilder.Create方法的重载中直接传入名称参数,因为不带名称的重载已过时且将在未来版本移除。以 gql001.md 中的示例为例:
// 违规写法 Field<StringGraphType>().Name("Name"); Connection<StringGraphType>().Name("Name"); ConnectionBuilder<string>.Create<StringGraphType>().Name("Name"); ConnectionBuilder.Create<StringGraphType, string>().Name("Name"); // 修复后 Field<StringGraphType>("Name"); Connection<StringGraphType>("Name"); ConnectionBuilder<string>.Create<StringGraphType>("Name"); ConnectionBuilder.Create<StringGraphType, string>("Name");GQL002 用于提示已经传入名称却又调用Name方法的冗余调用可以移除;GQL003 则针对Field("xxx").Name("yyy")这种两个名称不一致的冲突。从 FieldNameAnalyzer.cs 的源码可以看到,这三个规则各自定义了一个DiagnosticDescriptor,默认严重级别均为Warning且默认启用(isEnabledByDefault: true),并注册了对SimpleMemberAccessExpression语法节点的分析。
GQL004(FieldBuilderAnalyzer)提示不要使用过时的Field方法。GQL005(ResolverAnalyzer)用于检测非法的 resolver 用法,是当时唯一作为 Error 发布的早期规则,不过在 v8.0 被移除(详见 4.3)。
GQL006 / GQL007(InputGraphTypeAnalyzer)针对自动注册的输入对象类型:当输入字段无法匹配到源类型的属性、或设置了无法设置的源字段时触发。GQL008(FieldArgumentAnalyzer)提示不要使用过时的Argument方法。GQL009(AwaitableResolverAnalyzer)检测应该返回Task/ValueTask却写成同步返回的 resolver 用法,要求使用异步 resolver,默认 Error 级别。
GQL011(NotAGraphTypeAnalyzer)是 v7.7 中规则编号最大的一条,检测类型不得可转换为IGraphType。这与 NotAGraphTypeAttribute 等代码分析标记配合使用,避免将不应暴露为 Graph 类型的 CLR 类型误注册到 schema 中。
4.2 v7.9.0:表达式推断补充
v7.9 只新增了一条规则:GQL015(FieldBuilderAnalyzer),默认 Error 级别。当使用Field(x => x.Prop)这类表达式重载却无法从表达式推断出字段名称时触发,要求显式提供名称,例如:
// 无法从表达式推断名称时的修复方式 Field<StringGraphType>("Name", x => x.Prop);4.3 v8.0.0:OneOf 与构造函数规则,以及 GQL005 的移除
v8.0 新增 5 条规则,同时移除了 GQL005:
GQL010(InputGraphTypeAnalyzer)无法解析输入源类型的构造函数时触发。GQL012(AllowedOnAnalyzer)与 AllowedOnAttribute 相关,检测对特性(Attribute)的非法使用位置。
GQL013 / GQL014(OneOfAnalyzer)是针对 GraphQLoneOf输入对象的约束检查,对应 OneOfAttribute:
- GQL013:
oneOf输入对象的字段必须声明为可空(nullable); - GQL014:
oneOf输入对象的字段不得设置默认值。
这两条规则保证了oneOf语义的正确性——即请求中必须恰好提供一个字段。
GQL016(RequireParameterlessConstructorAnalyzer)与 RequireParameterlessConstructorAttribute 对应,要求标注了该特性的类型必须提供无参构造函数,否则会在运行时实例化失败。
移除 GQL005:发布清单明确将GQL005 | Usage | Error | ResolverAnalyzer列入 v8.0 的 Removed Rules。从 DiagnosticIds.cs 中的占位注释可以推断,该规则对应的诊断逻辑已从发布规则集中移除。对于升级到 v8.0 的开发者而言,这意味着原先 GQL005 的告警不再出现。
4.4 v8.1.0:Type-First 扩展点方法校验
v8.1 新增的 4 条规则(GQL017–GQL020)全部围绕 Type-First 方式下通过特性指定扩展方法这一场景,它们共享同一个基类实现。在 ParserAttributeAnalyzer.cs 中可以看到,ParserAttributeAnalyzer继承自ParserValidatorAttributeAnalyzer,并只向基类传入自己对应的DiagnosticDescriptor。
GQL017(ParserValidatorAttributeAnalyzer)是这三类扩展点的"找不到方法"检查。Validator、Parser、ValidateArguments三个特性都可以通过"类型 + 方法名"来指定要调用的方法(分别对应 ValidatorAttribute、ParserAttribute、ValidateArgumentsAttribute)。当指定名称的方法在目标类型上不存在时触发。以 gql017.md 中的示例:
// 违规:Parsers 类中没有名为 Parse 的方法 public class TestClass { [Parser(typeof(Parsers), "Parse")] public string Hello { get; set; } } public static class Parsers { public static object ParseValue(object value) => value; } // 修复:将特性参数改为真实方法名 "ParseValue" [Parser(typeof(Parsers), "ParseValue")]GQL018(ParserAttributeAnalyzer)校验Parser特性指定方法的签名。根据 gql018.md,该方法必须满足:static、返回object、且只有一个object类型的参数;如果方法定义在特性所在类之外的另一个类中,则还必须声明为public。这一点在源码的消息模板中也有印证(Parser method '{0}' signature must be '{1}static object {0}(object value)')。典型违规与修复:
// 违规:参数类型是 string 而非 object;外部类方法未声明为 public private static object Parse(string value) => Convert.ToInt32(value); internal static object ParseValue(object value) => Convert.ToInt32(value); // 修复 private static object Parse(object value) => Convert.ToInt32(value); public static object ParseValue(object value) => Convert.ToInt32(value);GQL019(ValidatorAttributeAnalyzer)校验Validator方法签名,GQL020(ValidateArgumentsAttributeAnalyzer)校验ValidateArguments方法签名,规则逻辑与 GQL018 同构。这四条规则默认均为 Error 级别,且不提供代码修复(从发布清单的 Notes 列可以看出,v8.1 的四条规则没有关联 Code Fix 条目)。
五、用 .editorconfig 配置分析器规则
分析器的使用方式与所有 Roslyn 分析器一致:通过.editorconfig文件调整规则严重级别。配置语法见 docs2/site/docs/analyzers/overview.md:
dotnet_diagnostic.<rule ID>.severity = <severity>例如将 GQL001 完全关闭:
dotnet_diagnostic.GQL001.severity = none常用取值包括none(禁用)、suggestion、warning、error。配置键不区分大小写,dotnet_diagnostic.GQL001.severity = none与dotnet_diagnostic.gql001.severity = NONE等价。
如果想针对文件、文件夹或整个项目关闭规则,可以在.editorconfig中结合 section 头使用:
[*.cs] dotnet_diagnostic.GQL001.severity = none如果只是临时屏蔽单个违规,可以使用 C# 预处理指令(以 GQL001 为例,所有规则通用):
#pragma warning disable GQL001 // 触发该规则的那一行代码 #pragma warning restore GQL001需要特别说明的是:发布清单中列出的严重级别是"默认值",例如 GQL001–GQL004、GQL006–GQL008 默认是 Warning,GQL009–GQL020 默认是 Error。默认启用与否由分析器源码中的isEnabledByDefault: true决定(见 FieldNameAnalyzer.cs)。开发者既可以通过.editorconfig整体降级/禁用规则,也可以通过分析器项目的诊断选项做更细粒度的控制。
六、源码级实现:发布追踪与规则注册机制
理解这份发货清单,需要把它放回 Roslyn 分析器工程的上下文中看:
发布追踪文件作为构建输入。在 GraphQL.Analyzers.csproj 中,两个发布追踪文件被声明为AdditionalFiles。Roslyn 的 ReleaseTrackingAnalyzers 会读取这些文件,校验新增规则是否已登记到AnalyzerReleases.Unshipped.md、发布版本后是否移入AnalyzerReleases.Shipped.md,并检查DiagnosticDescriptor的 ID、类别、严重级别是否与清单一致。这正是"发货清单"这一文件名的工程含义——它是分析器版本发布流程中受构建校验的一部分。
规则 ID 与类别的常量集中管理。DiagnosticIds.cs 为 20 条规则各定义了一个字符串常量;DiagnosticCategories.cs 定义了统一的Usage类别。每个分析器类通过DiagnosticDescriptor把这些常量组合起来,形成一条完整规则的定义。
诊断描述符与清单的一致性。以 FieldNameAnalyzer 为例,FieldNameAnalyzer.cs 中定义了三个DiagnosticDescriptor,其 ID(GQL001/002/003)、类别(Usage)、默认严重级别(Warning)、默认启用(true)与发货清单中的记录一一对应;SupportedDiagnostics属性将其暴露给 Roslyn 运行时。
测试保障。每条规则的诊断与代码修复行为都有对应的单元测试,位于 src/GraphQL.Analyzers.Tests,例如FieldNameAnalyzerTests.cs、ParserAttributeAnalyzerTests.cs、OneOfAnalyzerTests.cs、RequireParameterlessConstructorAnalyzerTests.cs等,可以作为规则行为的权威参考。
七、在项目中安装与使用
GraphQL.NET 分析器随 GraphQL.NET 包一起分发,同时也提供独立的安装包项目 src/GraphQL.Analyzers.Package(其tools目录下带有 install.ps1 与 uninstall.ps1,支持通过 NuGet 工具方式在项目中启用或卸载分析器)。启用后,IDE(Visual Studio / Rider / VS Code 的 C# 扩展)会在编辑时实时显示诊断,dotnet build也会在编译输出中报告这些规则。
每一条规则都有独立的官方文档页面,位于仓库的 docs2/site/docs/analyzers 目录,命名格式为gqlXXX.md(如 gql001.md、gql017.md、gql018.md),内容统一包含:规则 ID / 类别 / 默认严重级别 / 默认启用状态 / 是否提供 Code Fix / 引入版本、触发原因(Cause)、规则描述、违规示例与修复示例、屏蔽方法以及相关规则链接。汇总入口是 overview.md。当某个规则命中时,IDE 中的诊断消息可以直接跳转到对应页面。
八、总结
AnalyzerReleases.Shipped.md 表面上看只是一张规则登记表,实际上它是 GraphQL.NET 分析器能力演进的权威索引:从 v7.7 覆盖字段命名与输入类型匹配的基础规则,到 v7.9 补充表达式推断检查,再到 v8.0 引入oneOf约束、无参构造函数检查并移除 GQL005,最后在 v8.1 为 Type-First 的Parser/Validator/ValidateArguments扩展点补齐方法存在性与签名校验。开发者可以把这份清单当作速查手册,结合 docs2/site/docs/analyzers 下每个规则的文档页,在.editorconfig中按项目实际需要调整规则严重级别,让这些编译期检查在 schema 定义阶段就拦截常见错误,而不是等到运行时才暴露问题。
- 后端
【免费下载链接】graphql-dotnet
GraphQL for .NET
相关推荐
OrchardCore 源码生成器分析器发布清单解读:OCSG001 与 OCSG002 规则实战
OrchardCore 源码生成器分析器发布清单解读:OCSG001 与 OCSG002 规则实战 OrchardCore 在 src/OrchardCore/
CMS后端Web框架MessagePack-CSharp 诊断分析器全解析:MsgPack001~MsgPack018 规则清单、发布演进与修复指南
MessagePack CSharp 诊断分析器全解析:MsgPack001~MsgPack018 规则清单、发布演进与修复指南 导读 本文以 Analyzer
序列化后端FiftyOne Dataset Zoo 实战:使用 kinetics-400 动作识别数据集与部分下载机制
FiftyOne Dataset Zoo 实战:使用 kinetics 400 动作识别数据集与部分下载机制 导读 本文聚焦 FiftyOne 数据集动物园(D
后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考