>我的反序列化对象的名称有问题,我想返回它。
目前,我正在编写一个 Web 服务,它从另一个 Web 服务请求数据,然后将此数据返回到应用程序。
例:
public class UserController
{
public HttpResponseMessage GetUser()
{
// Get Data from WebService
string jsonString = @"{'key': 'A45', 'field1': 'John', 'field2': 'Doe', address{'field3': 'HelloWorld Ave.', 'field4': 'Somewhere'}}";
// Make Object from JSON-String
User user = JsonConvert.DeserializeObject<User>(jsonString);
// Return Object to Application
return Request.CreateResponse(HttpStatusCode.OK, user);
}
}
public class User
{
[JsonProperty("key")]
public string Key { get; set; }
[JsonProperty("field1")]
public string FirstName { get; set; }
[JsonProperty("field2")]
public string LastName { get; set; }
[JsonProperty("address")]
public Address Address { get; set; }
}
public class Address
{
[JsonProperty("field3")]
public string Street { get; set; }
[JsonProperty("field4")]
public string City { get; set; }
}
目前为止,一切都好。我的 Web 服务创建对象"用户"并将其返回到应用程序。
现在我的问题:
返回的 JSON 字符串将字段名称更改回其原始名称。
而不是:
"{'key': 'A45', 'field1': 'John', 'field2': 'Doe', Address {'Street': 'HelloWorld Ave.', 'City': 'Somewhere'}}"
我得到:
"{'key': 'A45', 'field1': 'John', 'field2': 'Doe', Address {'Street': 'HelloWorld Ave.', 'City': 'Somewhere'}}"
我知道 JsonProperty 中的 PropertyName 不区分大小写,所以我可以用大写的"K"写[JsonProperty("Key")]
,返回的 Json-String 将包含大写的"K"。
但是我的田地呢?有什么方法可以将"字段1"更改为"名字",将"字段2"更改为"姓氏"?
编辑 1 - 2015-01-28:向示例添加了更多代码。
我建议执行 2 个步骤
- 按原样(反)序列化 DTO(数据传输对象)
- 实现一个程序集层,您可以在其中控制域对象的创建。
在您的情况下,DTO和DomainModel之间似乎是1:1的关系,只是具有不同的属性名称 - 因此您只需要以这种方式进行投影。我可以强烈推荐自动映射器投影,或者如果它是嵌套的自动映射器嵌套投影。
这里最大的优势是您可以将整个域层与外部服务分离,因此即使您的 Web 服务被破坏/更改,也不会影响您的业务逻辑。
@stefankmitph和@nhaberl的答案都是很好的答案,但最终我使用了略有不同的技术。
我的两个类现在都有私有字段,用于将 JSON 字符串的值设置为公共字段。
私有字段获取传入 JSON 字符串的属性名称,公共字段获取传出 JSON 字符串的属性名称:
public class User
{
#region private
[JsonProperty("key")]
private string _Key { set { Key = value; } }
[JsonProperty("field1")]
private string _FirstName { set { FirstName = value; } }
[JsonProperty("field2")]
private string _LastName { set { LastName = value; } }
[JsonProperty("address")]
private Address _Address { set { Address = value; } }
#endregion
#region public
[JsonProperty("Key")]
public string Key { get; private set; }
[JsonProperty("FirstName")]
public string FirstName { get; private set; }
[JsonProperty("LastName")]
public string LastName { get; private set; }
[JsonProperty("Address")]
public Address Address { get; private set; }
#endregion
}
public class Address
{
#region private
[JsonProperty("field3")]
private string _Street { set { Key = value; } }
[JsonProperty("field4")]
private string _City { set { FirstName = value; } }
#endregion
#region public
[JsonProperty("Street")]
public string Street { get; private set; }
[JsonProperty("City")]
public string City { get; private set; }
#endregion
}
示例输出:
"{'Key': 'A45', 'FirstName': 'John', 'LastName': 'Doe', Address {'Street': 'HelloWorld Ave.', 'City': 'Somewhere'}}"
使用此方法,我还可以将所有数据从无错误类获取到主类:
public class User
{
#region private
// Other fields, see above. \
[JsonProperty("address")]
private Address _Address
{
set
{
City = value.City;
Street = value.Street;
}
}
#endregion
#region public
// Other fields, see above. \
[JsonProperty("City")]
public string City { get; private set; }
[JsonProperty("Street")]
public string Street { get; private set; }
#endregion
}
public class Address
{
// Address fields. See above.
}
示例输出:
"{'Key': 'A45', 'FirstName': 'John', 'LastName': 'Doe', 'Street': 'HelloWorld Ave.', 'City': 'Somewhere'}"
通过编写自己的序列化程序并向属性添加自定义属性,可以强制序列化程序在序列化回 JSON 时采用自定义名称。
public class JsonSerializeProperty : Attribute
{
public string PropertyName { get; set; }
}
// derive from JsonConverter and override WriteJson (serialize)
// and ReadJson (deserialize)
// note: i have not implemented CanConvert
public class CustomUserSerializer : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var user = value as User;
if(user == null)
throw new NullReferenceException("user");
var properties = user.GetType().GetProperties();
writer.WriteStartObject();
foreach (var property in properties)
{
// get the attribute assigned to the property [JsonSerializeProperty]
object customAttributes = property.GetCustomAttributes(typeof(JsonSerializeProperty), false).SingleOrDefault();
JsonSerializeProperty attribute = customAttributes as JsonSerializeProperty;
if(attribute != null)
{
// JsonSerializeProperty
string propertyName = attribute.PropertyName;
// just write new property name and value
writer.WritePropertyName(propertyName);
writer.WriteValue(property.GetValue(value, new object[] {}));
}
}
writer.WriteEndObject();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
// just map every JProperty from the Json string to the
// JsonProperty of the user class. I know this is kind of ugly... but it may serve your purpose
JObject jsonObject = JObject.Load(reader);
List<JProperty> properties = jsonObject.Properties().ToList();
// create an instance of User to assign the values of the
// Json string
object instance = Activator.CreateInstance(objectType);
// loop through the user properties and get the
// JsonProperty customattribute. then set the value of the JProperty
PropertyInfo[] objectProperties = objectType.GetProperties();
foreach (var objectProperty in objectProperties)
{
var customAttribute = objectProperty.GetCustomAttributes(typeof(JsonPropertyAttribute), false).SingleOrDefault();
JsonPropertyAttribute attribute = customAttribute as JsonPropertyAttribute;
if (attribute != null)
{
JProperty jsonProperty = properties.SingleOrDefault(prop => prop.Name == attribute.PropertyName);
if (jsonProperty != null)
{
objectProperty.SetValue(instance, jsonProperty.Value.ToString(), new object[] {});
}
}
}
return instance;
// {
// _Key = "A45",
// _FirstName = "John",
// _LastName = "Doe"
// }
}
public override bool CanConvert(Type objectType)
{
throw new NotImplementedException();
}
}
[JsonConverter(typeof(CustomUserSerializer))]
public class User
{
[JsonProperty(PropertyName = "key")]
[JsonSerializeProperty(PropertyName = "_Key")]
public string Key { get; set; }
[JsonProperty("field1")]
[JsonSerializeProperty(PropertyName = "_FirstName")]
public string FirstName { get; set; }
[JsonProperty("field2")]
[JsonSerializeProperty(PropertyName = "_LastName")]
public string LastName { get; set; }
}