【问题标题】:WebAPI Temporarily Override JsonFormatter from OnActionExecutedWebAPI 临时覆盖 OnActionExecuted 中的 JsonFormatter
【发布时间】:2016-05-05 15:16:19
【问题描述】:

我正在尝试创建一个属性,以不同方式序列化从操作返回的数据

public override void OnActionExecuted(HttpActionExecutedContext filterContext)
{
    var content = (filterContext.Response.Content as ObjectContent);

    if (content == null)
    {
        return;
    }

    if (content.ObjectType.IsGenericType 
        && content.ObjectType.GetGenericTypeDefinition() == typeof (Page<>))
    {
        var pageObject = (content.Value as IPage);
        var jsonFormatterRule = new JsonFormatterRule();
        var pageJson = JsonConvert.SerializeObject(pageObject.ItemsArray, 
                                                jsonFormatterRule.GetPascalCasedSettings());

       //How do I set the content that \/ doesn't compile?
       //filterContext.Response.Content = pageJson;
   }
}

这是 JsonFormatterRules 以防万一有人想看到它们。

public JsonSerializerSettings GetDefaultSettings()
{
    var settings = new JsonSerializerSettings()
    {
        Formatting = Formatting.Indented,
        ContractResolver = new CamelCasePropertyNamesContractResolver(),
        DateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind,
    };

    settings.Converters.AddRange(defaultConfiguredConverters);
    return settings;
}

public JsonSerializerSettings GetPascalCasedSettings()
{
    var settings = this.GetDefaultSettings();
    settings.ContractResolver = new DefaultContractResolver();

    return settings;
}

如何在执行操作时设置内容?我无法将默认序列化程序更改为全局默认合同,因为它可能会出现线程问题。

此外,我不希望不必创建新响应并从旧响应中复制标题,这似乎已经过时了。

【问题讨论】:

  • 你到底想做什么?对某些操作有不同的序列化程序?
  • @dotctor 是的,序列化程序与基于属性的某些操作不同

标签: c# asp.net-web-api action-filter onactionexecuted


【解决方案1】:

一种方法是定义一个自定义格式化程序。

首先,定义你的属性:

[AttributeUsage(AttributeTargets.Class)]
public sealed class SpecialSerializeAttribute : Attribute
{
}

现在创建一个可以找到属性的格式化程序:

public class SpecialSerializeFormatter : MediaTypeFormatter
{
    public SpecialSerializeFormatter()
    {
        //You can add any other supported types here.
        this.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json"));
    }

    public override bool CanReadType(Type type)
    {
        //you can just return false if you don't want to read any differently than your default way
        //if you return true here, you should override the ReadFromStreamAsync method to do custom deserialize
        return type.IsDefined(typeof(SpecialSerializeAttribute), true));
    }

    public override bool CanWriteType(Type type)
    {
        return type.IsDefined(typeof(SpecialSerializeAttribute), true));
    }

    public override async Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content,
        TransportContext transportContext)
    {

        //value will be your object that you want to serialize

        //add any custom serialize settings here
        var json = JsonConvert.SerializeObject(value);

        //Use the right encoding for your application here
        var byteArray = Encoding.UTF8.GetBytes(json);
        await writeStream.WriteAsync(byteArray, 0, byteArray.Length);
    }
}

在你的 WebApiConfig.cs 中注册格式化程序

您也可以直接为每种类型构建一个格式化程序,然后您不必执行属性。只需更改您的 CanRead 和 CanWrite 方法。我发现基于这些直接类型可以提供更好的结果,因为它不是通用格式化程序,您可能需要根据类型应用自定义逻辑,但上述答案应该可以满足您的需求。

【讨论】:

  • 哇,我什至不知道你可以那样做。我现在要测试一下
【解决方案2】:

如果有人想知道,响应内容是一个 HTTPContent,它继承自 ByteArrayContent。因此,如果您已经序列化了 JSON,您所要做的就是将它放入一个字节数组中。

filterContext.ActionContext.Response.Content = new ByteArrayContent(Encoding.ASCII.GetBytes(pageJson));

【讨论】:

  • 很高兴知道。确保 ASCII 是您想要的。如果您有任何需要序列化的用户生成内容,您将需要 UTF8,以便可以序列化任何特殊字符。
猜你喜欢
  • 1970-01-01
  • 2012-09-18
  • 2016-04-05
  • 2013-09-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-17
  • 2016-06-11
  • 1970-01-01
相关资源
最近更新 更多