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

如何让强类型ID与Refit框架兼容?

强类型ID与Refit协同工作的解决方案

问题核心是Refit处理URL查询/路由参数时依赖TypeConverter,而非JsonConverter——你配置的JsonConverter仅作用于请求体/响应体序列化,对URL参数无效。以下是具体解决步骤:

1. 注册强类型ID的TypeConverter

Meziantou.Framework.StronglyTypedId生成的UserIdTypeConverter需要被注册到.NET类型描述器中,让框架识别其转换逻辑。

在UserId结构体中添加静态构造函数完成注册:

[StronglyTypedId(typeof(Guid))]
public partial struct UserId
{
    public partial class UserIdTypeConverter { }
    public partial class UserIdJsonConverter { }
    public partial class UserIdNewtonsoftJsonConverter { }

    static UserId()
    {
        TypeDescriptor.AddAttributes(typeof(UserId), new TypeConverterAttribute(typeof(UserIdTypeConverter)));
    }
}

或者在应用启动时全局注册(如Program.cs/Startup.cs):

TypeDescriptor.AddAttributes(typeof(UserId), new TypeConverterAttribute(typeof(UserIdTypeConverter)));

2. 对齐Refit参数与路由规则

如果你的路由模板包含{userId}占位符(例如/users/{userId}/audio-sources),需确保参数名与占位符一致;若名称不匹配,需显式指定别名:

public interface IAudioSourceRefitClient
{
    [Get($"{Routes.AudioSourceRoutes.BaseRoute}/{Routes.AudioSourceRoutes.GetAllByUserRoute}")]
    // 若路由占位符为userId,参数名一致则无需额外配置;否则添加AliasAs指定对应名称
    Task<IEnumerable<AudioSource>> GetAllByUserId(UserId userId, CancellationToken cancellationToken);
    // 示例:若路由占位符是user_id,需改为
    // Task<IEnumerable<AudioSource>> GetAllByUserId([AliasAs("user_id")] UserId userId, CancellationToken cancellationToken);
}

3. 备选方案:自定义Refit参数转换器

若TypeConverter注册后仍不生效,可直接给Refit添加专属参数转换器,强制处理UserId类型:

public class UserIdParameterConverter : IParameterConverter
{
    public string Convert(object value)
    {
        return value is UserId userId ? userId.Value.ToString() : 
            throw new InvalidOperationException("参数必须是UserId类型");
    }
}

在RefitConfigurator中添加该转换器:

public RefitSettings GetRefitSettings(IEnumerable<JsonConverter> converters, params Assembly[] assemblies)
{
    var knownTypes = assemblies.SelectMany(assembly => assembly.GetTypes()).ToList();
    var foundConverters = assemblies.SelectMany(assembly => assembly.GetTypes())
        .Where(type => type.IsSubclassOf(typeof(JsonConverter)))
        .Select(type => (JsonConverter)Activator.CreateInstance(type)!)
        .ToList();

    return new RefitSettings
    {
        ContentSerializer = new NewtonsoftJsonContentSerializer(new JsonSerializerSettings
        {
            Converters = converters.Concat(foundConverters).ToList(),
            TypeNameHandling = TypeNameHandling.Objects,
            SerializationBinder = new KnownTypesBinder(knownTypes)
        }),
        // 添加自定义参数转换器
        ParameterConverters = new List<IParameterConverter> { new UserIdParameterConverter() }
    };
}

4. 调试验证

开启Refit日志(如使用Serilog等框架),查看实际生成的URL参数,确认UserId是否被转换为正确的Guid字符串,排查参数传递是否符合后端接口要求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 19:22:54