如何让强类型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
相关产品推荐
相关产品推荐

