我有一些使用ASP的C#代码。Net MVC,它正在使用Json。Net来序列化一些DTO。为了减少负载,我在序列化过程中使用了[JsonProperty(PropertyName="shortName")]属性来使用较短的属性名称。
当客户是另一个时,这非常有效。Net应用程序或服务,因为反序列化将对象层次结构重新组合在一起,使用更长更友好的名称,同时保持较低的实际传输负载。
当客户端通过浏览器使用javascript/ajax时,问题就出现了。它发出请求,并获取json。。。但json使用的是不太友好的缩写名称。
如何使json.net序列化引擎以编程方式忽略[JsonProperty(PropertyName="shortName")]属性?理想情况下,我的MVC服务将在那里运行,并通常使用缩短的属性名称进行序列化。当我的代码检测到一个特定的参数时,我希望使用较长的名称序列化数据,并忽略[JsonProperty()]属性。
有什么建议吗?
谢谢,
Kevin
使用自定义合约解析程序可以很容易地完成这项工作。以下是您需要的所有代码:
class LongNameContractResolver : DefaultContractResolver
{
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
// Let the base class create all the JsonProperties
// using the short names
IList<JsonProperty> list = base.CreateProperties(type, memberSerialization);
// Now inspect each property and replace the
// short name with the real property name
foreach (JsonProperty prop in list)
{
prop.PropertyName = prop.UnderlyingName;
}
return list;
}
}
以下是使用解析器的快速演示:
class Program
{
static void Main(string[] args)
{
Foo foo = new Foo
{
CustomerName = "Bubba Gump Shrimp Company",
CustomerNumber = "BG60938"
};
Console.WriteLine("--- Using JsonProperty names ---");
Console.WriteLine(Serialize(foo, false));
Console.WriteLine();
Console.WriteLine("--- Ignoring JsonProperty names ---");
Console.WriteLine(Serialize(foo, true));
}
static string Serialize(object obj, bool useLongNames)
{
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.Formatting = Formatting.Indented;
if (useLongNames)
{
settings.ContractResolver = new LongNameContractResolver();
}
return JsonConvert.SerializeObject(obj, settings);
}
}
class Foo
{
[JsonProperty("cust-num")]
public string CustomerNumber { get; set; }
[JsonProperty("cust-name")]
public string CustomerName { get; set; }
}
输出:
--- Using JsonProperty names ---
{
"cust-num": "BG60938",
"cust-name": "Bubba Gump Shrimp Company"
}
--- Ignoring JsonProperty names ---
{
"CustomerNumber": "BG60938",
"CustomerName": "Bubba Gump Shrimp Company"
}
只想用反序列化程序类"扩展"Brian的答案
static T Deserialize<T>(string json)
{
return JsonConvert.DeserializeObject<T>(json, new JsonSerializerSettings()
{
ContractResolver = new LongNameContractResolver()
});
}
如果您正在使用。Net7和System.Text.Json
,并试图实现相同的结果,这里有一个利用DefaultJsonTypeInfoResolver
的解决方案(从另一篇文章中找到并简化了一点):
1-定义自定义属性,而不是使用JsonPropertyName进行反序列化:
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, Inherited = true)]
public sealed class JsonAlternativeNameAttribute : Attribute
{
public JsonAlternativeNameAttribute(string? name) => this.Name = name;
public string? Name { get; private set; }
}
2-添加一个具有以下实现的扩展类:
using System.Reflection;
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
using System.Linq;
namespace MyApp.Core.Extension;
public static class JsonSerializationExtensions
{
private static Action<JsonTypeInfo> AlternativeNamesContract() =>
static typeInfo =>
{
if (typeInfo.Kind != JsonTypeInfoKind.Object)
return;
foreach (var property in typeInfo.Properties)
{
if (property.AttributeProvider?.GetCustomAttributes(typeof(JsonAlternativeNameAttribute), true) is { } list && list.Length > 0)
property.Name = list.OfType<JsonAlternativeNameAttribute>().FirstOrDefault()?.Name ?? property.GetMemberName() ?? property.Name;
}
};
private static string? GetMemberName(this JsonPropertyInfo property) => (property.AttributeProvider as MemberInfo)?.Name;
public static JsonSerializerOptions DefaultDeserializerOptions =
new ()
{
TypeInfoResolver = new DefaultJsonTypeInfoResolver
{
Modifiers = { AlternativeNamesContract() }
}
};
public static JsonSerializerOptions DefaultSerializerOptions =
new()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
PropertyNameCaseInsensitive = true,
WriteIndented = true
};
}
3-使用扩展类中的DefaultDeserializerOptions
基于JsonAlternativeName属性中的修饰名称来反序列化模型
class Foo
{
[JsonAlternativeName("cust-num")]
public string CustomerNumber { get; set; }
[JsonAlternativeName("cust-name")]
public string CustomerName { get; set; }
}
var foo = JsonSerializer.Deserialize<Foo>("your foo json here", JsonSerializationExtensions.DefaultDeserializerOptions);
4-要根据属性名称序列化对象,可以使用自定义的JsonSerializerOptions,而无需设置TypeInfoResolver。扩展类中的DefaultSerializerOptions
是一个可以在这里使用的示例:
var jsonString = JsonSerializer.Serialize(new Foo {CustomerName="Joe", CustomerNumber="123"}, JsonSerializationExtensions.DefaultSerializerOptions);
序列化结果为:
{
"customerNumber": "123",
"customerName": "Joe"
}