C# 使用ResolveType的GraphQL.NET接口

C# 使用ResolveType的GraphQL.NET接口,c#,graphql,graphql-dotnet,C#,Graphql,Graphql Dotnet,我是GraphQL新手,目前正在尝试为现有库构建api 在那里我有一个唯一的别名,一个可以是不同类型的值和一些属性的标记 为了处理不同的值类型,我定义了一个包含别名和属性的接口,以及4个具有不同类型值字段的实现 GraphQL模式如下所示: schema { query: Query mutation: Mutation } type Query { allTags: [Tag!] tags(aliases: [ID!]!): [Tag] tag(alias:

我是GraphQL新手,目前正在尝试为现有库构建api

在那里我有一个唯一的别名,一个可以是不同类型的值和一些属性的标记

为了处理不同的值类型,我定义了一个包含别名和属性的接口,以及4个具有不同类型值字段的实现

GraphQL模式如下所示:

schema {
  query: Query
  mutation: Mutation
}

type Query {
    allTags: [Tag!]
    tags(aliases: [ID!]!): [Tag]
    tag(alias: ID!): Tag
}

interface Tag {
    alias: ID! @isUnique
    properties: [TagProperty]
}

type StringTag implements Tag {
    alias: ID! @isUnique
    properties: [TagProperty]
    value: String
}

type IntegerTag implements Tag {
    alias: ID! @isUnique
    properties: [TagProperty]
    value: Int
}

type FloatTag implements Tag {
    alias: ID! @isUnique
    properties: [TagProperty]
    value: Float
}

type BooleanTag implements Tag {
    alias: ID! @isUnique
    properties: [TagProperty]
    value: Boolean
}

type TagProperty {
    name: String!
    value: String!
}
在C#中的接口实现中,我希望按照graphql dotnet入门文档中的建议使用

接口实现的代码:

public TagInterface(
    BooleanTag booleanTag, 
    IntegerTag integerTag, 
    FloatTag floatTag, 
    StringTag stringTag)
{
    Name = "Tag";
    Description = "A resource which points to a value";

    Field<IdGraphType>(
        "alias",
        "the unique alias of the tag"
    );
    Field<ListGraphType<TagPropertyType>>(
        "properties",
        "the properties of a tag defined in the config XML"
    );

    ResolveType = obj =>
    {
        if (obj is HtTag)
        {
            switch ((obj as HtTag).DataType) {
                case EDataType.Bool:

                    return booleanTag;

                case EDataType.Byte:
                case EDataType.Sbyte:
                case EDataType.Short:
                case EDataType.Ushort:
                case EDataType.Int:
                case EDataType.Uint:
                case EDataType.Long:
                case EDataType.Ulong:
                    return integerTag;

                case EDataType.Double:
                case EDataType.Float:
                case EDataType.Decimal:
                    return floatTag;

                default:
                    return stringTag;
            }
        }

        throw new ArgumentOutOfRangeException($"Could not resolve graph type for {obj.GetType().Name}");
    };
}
我得到以下错误:

{
    "errors": [
        {
            "message": "Für dieses Objekt wurde kein parameterloser Konstruktor definiert."
        }
    ]
}
这似乎是因为接口定义中有4个构造函数参数(根据文档中的示例)。如果在ResolveType实现中删除它们并返回
new StringTag()
等,则会得到正确数量的结果,但没有内容:

{
    "data": {
        "tags": [
            {
                "__typename": "StringTag",
                "alias": null,
                "value": null
            },
            {
                "__typename": "StringTag",
                "alias": null,
                "value": null
            }
        ]
    }
}
有人能告诉我我做错了什么吗

更新 我通过使用无参数构造函数并返回解析对象使其工作,如下所示:

ResolveType = obj =>
    {
        if (obj is HtTag)
        {
            switch ((obj as HtTag).DataType) {
                case EDataType.Bool:
                    return (from t in PossibleTypes where t is BooleanTag select t).First();

                case EDataType.Byte:
                case EDataType.Sbyte:
                case EDataType.Short:
                case EDataType.Ushort:
                case EDataType.Int:
                case EDataType.Uint:
                case EDataType.Long:
                case EDataType.Ulong:
                    return (from t in PossibleTypes where t is IntegerTag select t).First();

                case EDataType.Double:
                case EDataType.Float:
                case EDataType.Decimal:
                    return (from t in PossibleTypes where t is FloatTag select t).First();

                default:
                    return (from t in PossibleTypes where t is StringTag select t).First();
            }
        }

        throw new ArgumentOutOfRangeException($"Could not resolve graph type for {obj.GetType().Name}");
    };

这就是它应该使用的方式吗?

为了能够解析您的
TagInterface
类型,您需要使用某种形式的依赖项注入。您的
TagInterface
和所有其他
GraphType
架构类型都需要在DI容器中注册

如果使用2.0预发行版,请使用以下(.NET核心示例):

services.AddSingleton(
s=>new StarWarsSchema(新的FuncDependencyResolver(类型=>(IGraphType)s.GetRequiredService(类型));

旧版本可以直接使用func(.NET核心示例):

services.AddSingleton(
s=>newstarwarsschema(type=>(IGraphType)s.GetRequiredService(type));
有关更多信息,请参阅这些文档(尚未更新到2.0 alpha版本):

如果这些标记类型未在架构中的其他地方公开,您可能还需要使用
Schema
上的
RegisterType
注册它们

构建模式时,它会查看“根”类型(查询、, 突变、订阅)并收集它们公开的所有图形类型。 在使用接口类型时,通常会使用具体类型 未暴露在根类型(或其任何子类型)上。自从 这些具体类型永远不会在模式的类型图中公开 不知道他们的存在。这就是 模式是用于。通过使用RegisterType,它告诉模式 它将正确地将其添加到可能的类型中 初始化架构时接口类型上的集合


嗨,乔,谢谢你的回复。我已经使用
RegisterType()
注册了接口实现。这些类型也得到了正确的解析(请参阅orig.post中的最后一个代码片段)。当我在
StringTag
的alias resolve函数中设置断点时,正确的数据也在那里。但它不会在响应中返回!我很困惑,因为只有当它试图使用默认实现
Activator.CreateInstance
创建类型时,您才会遇到您发布的错误。您是说
TagInterface
及其所有构造函数参数都已解析?你用的是什么DI容器?玩了一会儿。您需要确保将DI解析器传递给基类
Schema
class<代码>标记模式(IDependencyResolver解析器):基本(resolver)。您还需要确保您的*标记类型注册为单例,因为在
ctor
中解析的实例可能与在
模式
查找中注册的实例不同。这可能是你遇到的两个问题。嗯,我目前没有使用任何DI容器,我在没有ASP.Net的纯.NET4.5上。。。我也不直接使用依赖解析程序。使用
ctor
注入的唯一方法是使用DI容器(graphql dotnet没有为您提供),因此这将是您的问题。
ResolveType = obj =>
    {
        if (obj is HtTag)
        {
            switch ((obj as HtTag).DataType) {
                case EDataType.Bool:
                    return (from t in PossibleTypes where t is BooleanTag select t).First();

                case EDataType.Byte:
                case EDataType.Sbyte:
                case EDataType.Short:
                case EDataType.Ushort:
                case EDataType.Int:
                case EDataType.Uint:
                case EDataType.Long:
                case EDataType.Ulong:
                    return (from t in PossibleTypes where t is IntegerTag select t).First();

                case EDataType.Double:
                case EDataType.Float:
                case EDataType.Decimal:
                    return (from t in PossibleTypes where t is FloatTag select t).First();

                default:
                    return (from t in PossibleTypes where t is StringTag select t).First();
            }
        }

        throw new ArgumentOutOfRangeException($"Could not resolve graph type for {obj.GetType().Name}");
    };
services.AddSingleton<ISchema>(
  s => new StarWarsSchema(new FuncDependencyResolver(type => (IGraphType)s.GetRequiredService(type))));
services.AddSingleton<ISchema>(
  s => new StarWarsSchema(type => (IGraphType)s.GetRequiredService(type)));