WebAPI 暂时从 OnActionExecuted 覆盖 JsonFormatter
WebAPI Temporarily Override JsonFormatter from OnActionExecuted
我正在尝试创建一个属性,该属性将以不同方式从操作return序列化数据
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;
}
如何设置动作执行时的内容?我无法将默认序列化器全局更改为 DefaultContract,因为它可能会出现线程问题。
此外,我不希望创建新的响应并从旧响应中复制 Headers,这似乎太过分了。
实现此目的的一种方法是定义自定义格式化程序。
首先,定义您的属性:
[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 方法。我发现基于这些直接类型会得到更好的结果,因为它不是一个通用的格式化程序,您可能需要根据类型应用自定义逻辑,但上面的答案应该能满足您的需求。
如果有人想知道,Response Content 是一个 HTTPContent,它继承自 ByteArrayContent。因此,如果您已经将 JSON 序列化,您所要做的就是将其放入字节数组中。
filterContext.ActionContext.Response.Content = new ByteArrayContent(Encoding.ASCII.GetBytes(pageJson));
我正在尝试创建一个属性,该属性将以不同方式从操作return序列化数据
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;
}
如何设置动作执行时的内容?我无法将默认序列化器全局更改为 DefaultContract,因为它可能会出现线程问题。
此外,我不希望创建新的响应并从旧响应中复制 Headers,这似乎太过分了。
实现此目的的一种方法是定义自定义格式化程序。
首先,定义您的属性:
[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 方法。我发现基于这些直接类型会得到更好的结果,因为它不是一个通用的格式化程序,您可能需要根据类型应用自定义逻辑,但上面的答案应该能满足您的需求。
如果有人想知道,Response Content 是一个 HTTPContent,它继承自 ByteArrayContent。因此,如果您已经将 JSON 序列化,您所要做的就是将其放入字节数组中。
filterContext.ActionContext.Response.Content = new ByteArrayContent(Encoding.ASCII.GetBytes(pageJson));