在ASP.NET Core MVC中自定义响应序列化

19

在 ASP.NET Core MVC 中,是否可以自定义类型在响应中序列化的方式?

在我的特定用例中,我有一个结构体 AccountId,它简单地包装了一个Guid

public readonly struct AccountId
{
    public Guid Value { get; }

    // ... 
}

当我从动作方法中返回它时,毫不奇怪地,它序列化为以下内容:

{ "value": "F6556C1D-1E8A-4D25-AB06-E8E244067D04" }

相反,我希望自动展开Value,使其序列化为纯字符串:

"F6556C1D-1E8A-4D25-AB06-E8E244067D04"

MVC可以配置以实现这一点吗?


3
我认为最好的选择是使用自定义的 JsonConverter。JSON.NET 作为默认的 JSON 序列化器,因此请查阅他们的文档。 - Chris Pratt
从阅读有关 自定义格式化程序 的内容开始。 - Set
@ChrisPratt 看起来这是正确的方法。我原以为有更通用的方式(如果我想返回 XML 而不是 JSON,我就必须配置另一个格式化程序),但这已经足够了。 - Michał Dudak
你可以尝试在你的结构体上重写 ToString 方法。但这会影响到更多的地方,不仅仅是序列化。 - Chris Pratt
我已经尝试过了,但是JSON.NET似乎忽略了它。现在我将使用自定义的JsonConverter,并可能在MVC问题跟踪器上建议更通用的解决方案。 - Michał Dudak
1个回答

36
你可以使用自定义转换器来定制JSON.NET生成的输出。自定义转换器在你的情况下应该是这样的:
[JsonConverter(typeof(AccountIdConverter))]
public readonly struct AccountId
{
    public Guid Value { get; }

    // ... 
}

public class AccountIdConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
        => objectType == typeof(AccountId);

    // this converter is only used for serialization, not to deserialize
    public override bool CanRead => false;

    // implement this if you need to read the string representation to create an AccountId
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        => throw new NotImplementedException();

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        if (!(value is AccountId accountId))
            throw new JsonSerializationException("Expected AccountId object value.");

        // custom response 
        writer.WriteValue(accountId.Value);
    }
}

如果您不想使用JsonConverter属性,可以在ConfigureServices中添加转换器(需要Microsoft.AspNetCore.Mvc.Formatters.Json):

public void ConfigureServices(IServiceCollection services)
{
    services
        .AddMvc()
        .AddJsonOptions(options => {
            options.SerializerSettings.Converters.Add(new AccountIdConverter());
        });
}

4
我差不多就是这样做的。我只是不喜欢JsonConverter属性,所以我在ConfigureServicesAddMvc中将我的转换器添加到SerializerSettings.Converters中。 - Michał Dudak
3
为了完整起见,我已将您的替代方案添加到我的答案中。 - Métoule
1
这也适用于AddControllersWithViews,这是在Visual Studio 2019中使用React.js模板的内容。services.AddControllersWithViews() .AddJsonOptions(options => { options.JsonSerializerOptions.Converters.Add(new MyAwesomeConverter()); }); - Becca Dee

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接