使用ResolveType的GraphQL.NET接口

时间:2017-11-15 18:08:50

标签: c# graphql graphql-dotnet

我是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入门文档中的建议使用ResolveType

接口实现的代码:

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}");
    };
}

}

当我运行以下查询时

query {
    tags(aliases:["TagID_S1A02_IN","TagID_S1A03_IN"]) {
      __typename
      alias
      ... on StringTag {
        value
        }
      ... on IntegerTag {
        value
        }
      ... on BooleanTag {
        value
        }
      ... on FloatTag {
        value
        }
    }
}

我收到以下错误:

{
    "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}");
    };

这是应该使用的方式吗?

1 个答案:

答案 0 :(得分:1)

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

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

services.AddSingleton<ISchema>(
  s => new StarWarsSchema(new FuncDependencyResolver(type => (IGraphType)s.GetRequiredService(type))));

https://github.com/graphql-dotnet/graphql-dotnet/blob/master/src/GraphQL.GraphiQLCore/Startup.cs#L29

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

services.AddSingleton<ISchema>(
  s => new StarWarsSchema(type => (IGraphType)s.GetRequiredService(type)));

有关详细信息,请参阅这些文档(尚未更新至2.0 alpha):

https://graphql-dotnet.github.io/docs/getting-started/dependency-injection

如果您的架构中的其他位置未公开,则可能还需要在RegisterType上使用Schema注册这些代码类型。

  

构建Schema时,它会查看“root”类型(Query,   Mutation,Subscription)并收集它们公开的所有GraphType。   通常在使用接口时键入具体类型   不会暴露在根类型(或任何子代)上。以来   这些具体类型永远不会在Schema的类型图中公开   不知道他们存在。这就是RegisterType&lt;&gt;关于。的方法   架构是为了。通过使用RegisterType&lt;&gt;,它告诉Schema有关   特定类型,它将正确地将其添加到PossibleTypes   初始化Schema时接口类型的集合。

https://graphql-dotnet.github.io/docs/getting-started/interfaces#registertype