You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

HotChocolate如何根据不同查询在DI中注入对应接口实现类

HotChocolate按查询域注入不同接口实现方案

完全可以实现该需求,核心是利用HotChocolate的解析上下文配合DI键控服务/工厂模式完成动态实例选择,以下是具体实现步骤:

1. 基础服务注册

首先将两个IPrinter实现以键控服务的形式注入DI容器(.NET 8+原生支持键控服务,低版本可自行实现工厂逻辑代替):

// 注册不同域对应的IPrinter实现
builder.Services.AddKeyedSingleton<IPrinter, PhysicalPrinter>("Customer");
builder.Services.AddKeyedSingleton<IPrinter, Digitalprinter>("Administration");

2. 实现服务动态选择逻辑

方案A:自定义工厂+显式调用

适合需要灵活控制实例选择的场景,先实现工厂类封装选择逻辑:

public interface IPrinterFactory
{
    IPrinter GetPrinter(IResolverContext context);
}

public class PrinterFactory : IPrinterFactory
{
    private readonly IServiceProvider _serviceProvider;

    public PrinterFactory(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public IPrinter GetPrinter(IResolverContext context)
    {
        // 可根据实际业务规则替换判断逻辑
        // 规则示例1:按查询根类型判断(拆分CustomerQuery和AdministrationQuery两个根类的场景)
        if (context.ObjectType.Name == "CustomerQuery")
        {
            return _serviceProvider.GetRequiredKeyedService<IPrinter>("Customer");
        }
        if (context.ObjectType.Name == "AdministrationQuery")
        {
            return _serviceProvider.GetRequiredKeyedService<IPrinter>("Administration");
        }

        // 规则示例2:按查询字段的自定义属性判断(同一根查询下不同字段分域的场景)
        var domainAttr = context.Selection.Field.GetCustomAttribute<DomainAttribute>();
        if (domainAttr != null)
        {
            return _serviceProvider.GetRequiredKeyedService<IPrinter>(domainAttr.DomainName);
        }

        throw new NotSupportedException("当前查询域无匹配的Printer实现");
    }
}

如果使用自定义属性做域标记,需要先定义属性类:

[AttributeUsage(AttributeTargets.Method)]
public class DomainAttribute : Attribute
{
    public string DomainName { get; }
    public DomainAttribute(string domainName) => DomainName = domainName;
}

注册工厂到DI:

builder.Services.AddSingleton<IPrinterFactory, PrinterFactory>();

在查询解析器中使用:

// 拆分根查询场景
public class CustomerQuery
{
    public string GetPrintInfo([Service] IPrinterFactory factory, IResolverContext context)
    {
        var printer = factory.GetPrinter(context);
        return printer.Print();
    }
}

// 同一根查询+自定义属性场景
public class Query
{
    [Domain("Customer")]
    public string CustomerPrint([Service] IPrinterFactory factory, IResolverContext context)
        => factory.GetPrinter(context).Print();

    [Domain("Administration")]
    public string AdminPrint([Service] IPrinterFactory factory, IResolverContext context)
        => factory.GetPrinter(context).Print();
}

方案B:自动注入(无需修改现有解析器入参)

如果希望直接注入IPrinter就自动匹配对应实现,可以在GraphQL服务配置中自定义解析逻辑:

builder.Services.AddGraphQLServer()
    // 注册IPrinter的动态解析规则
    .AddService<IPrinter>(ServiceKind.Resolver, sp =>
    {
        var context = sp.GetRequiredService<IResolverContext>();
        var factory = sp.GetRequiredService<IPrinterFactory>();
        return factory.GetPrinter(context);
    })
    // 其他配置保持不变
    .AddQueryType<Query>();

配置完成后即可直接在解析器中注入IPrinter使用,无需手动调用工厂:

[Domain("Customer")]
public string CustomerPrint([Service] IPrinter printer)
{
    return printer.Print();
}

内容的提问来源于stack exchange,提问作者Makus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.13 19:15:02