如何让ServiceStack按预期序列化隐式字符串重载类型?
问题描述
我编写了一个Base64UrlString类,用于确保服务收发的字符串无需额外编码即可保持URL安全,期望只需在DTO中使用该类型,ServiceStack就能自动识别并使用其隐式运算符。
DTO代码:
public class MyDto { Base64UrlString myString; } var dto = new MyDto() { myString = "hello i am url safe"; }
但客户端接收时,myString的值为{}。是否有更优雅的实现方式?原本以为这样使用类型就能“直接生效”。
Base64UrlString类代码:
// used only for Base64UrlEncoder using Microsoft.IdentityModel.Tokens; namespace MyDto.ServiceModel.Types { public class Base64UrlString { private readonly string _base64UrlString; public Base64UrlString(string str) { _base64UrlString = Base64UrlEncoder.Encode(str); } public static implicit operator string(Base64UrlString base64UrlString) => base64UrlString.ToString(); public static implicit operator Base64UrlString(string str) => new(str); public override string ToString() => Base64UrlEncoder.Decode(_base64UrlString); } }
解决方案
出现{}的原因有两个:一是DTO中的字段未设为公共成员,ServiceStack默认只序列化公共属性/字段;二是ServiceStack无法自动识别自定义类型的隐式转换,需要明确告知序列化器如何处理该类型。
步骤1:修正DTO的访问权限
将DTO中的字段改为公共属性,确保ServiceStack能识别并序列化:
public class MyDto { public Base64UrlString MyString { get; set; } }
步骤2:让自定义类型支持ServiceStack序列化
修改Base64UrlString类,实现ServiceStack的ISerializeToString接口,同时调整构造逻辑避免重复编码:
using Microsoft.IdentityModel.Tokens; using ServiceStack; namespace MyDto.ServiceModel.Types { public class Base64UrlString : ISerializeToString { private string _base64UrlEncoded; // 用于原始字符串编码的构造函数 public Base64UrlString(string str) { _base64UrlEncoded = Base64UrlEncoder.Encode(str); } // 用于反序列化的私有构造函数,避免重复编码 private Base64UrlString() { } public static implicit operator string(Base64UrlString value) => value.ToString(); public static implicit operator Base64UrlString(string str) => new(str); public override string ToString() => Base64UrlEncoder.Decode(_base64UrlEncoded); // 序列化时输出编码后的Base64Url安全字符串 public string SerializeToString() => _base64UrlEncoded; // 反序列化时从已编码的字符串创建实例 public static Base64UrlString FromEncodedString(string encodedStr) { return new Base64UrlString { _base64UrlEncoded = encodedStr }; } } }
步骤3:注册反序列化转换器
在ServiceStack的AppHost配置中,注册Base64UrlString的反序列化逻辑:
public override void Configure(Container container) { // 注册自定义类型的反序列化转换器 TypeSerializer.RegisterDeserializer<Base64UrlString>(Base64UrlString.FromEncodedString); }
补充说明
- 实现
ISerializeToString后,ServiceStack序列化时会直接调用SerializeToString()输出编码后的安全字符串,无需手动编码。 - 注册反序列化转换器后,ServiceStack接收字符串时会自动转换为
Base64UrlString实例,无需额外处理。 - 新增私有构造函数是为了在反序列化时直接复用已编码的字符串,避免重复执行编码逻辑。
内容的提问来源于stack exchange,提问作者Jan Martin
相关产品推荐
相关产品推荐

