有选择地将Linq2sql模型序列化为JSON

时间:2011-10-06 12:07:08

标签: linq-to-sql c#-4.0 extension-methods json.net

我有很多来自mssql数据库的linq2sql商务模型。表之间存在一些关联,这很好。整个模型是单独组装的。我正在使用JSON.NET库进行序列化。

现在我需要将这些模型序列化为JSON并告诉它使用哪些属性以及现在使用哪些属性。使用if属性是不可能的,但我也不喜欢元数据类的想法。

所以我一直在考虑以这种方式使用扩展方法:

public static class User {
  public static object GetSerializable(this DataModel.User user) {
    return new {
      user.Id, user.LoginName, user.FirstName, user.LastName
    }
  }
}

这很好,但我不知道如何在这样的情况下使用它:

[JsonObject]
public class AuthModel {
  [JsonProperty]
  public DataModel.User { get; set; }
}

您是否知道如何有效地使用这些扩展方法?还是其他一些完全不同的想法?

3 个答案:

答案 0 :(得分:0)

您可以使用Fluent Json将它们转换为json。此配置可以在不使用属性的情况下在代码中完成。

选项2:您可以使用Custom Serializer

选项3:您可以使用KeyValuePairConverter。将持久化类转换为字典并使用它。

答案 1 :(得分:0)

好吧我决定采用基于自定义JsonConverter的方法,结果与上面的方法非常相似。它看起来像这样:

public abstract class SerializeSelectorConverter<TModel> : JsonConverter where TModel: class
{
    protected abstract object GetSerializableObject( TModel model );

    public override bool CanWrite { get { return true; } }

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(TModel);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, GetSerializableObject( value as TModel ));
    }

    public override bool CanRead { get { return false; } }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

然后我就做了一个类:

[JsonObject]
public class AuthModel {
    [JsonProperty]
    [JsonConverter(typeof(UserConverter))]
    public DataModel.User { get; set; }
}

private class UserConverter : SerializeSelectorConverter<DataModel.User>
{
    protected override object GetSerializableObject(DataModel.User model)
    {
        return new
        {
            model.Id,
            model.LoginName,
            model.FirstName,
            model.LastName
        };
    }
}

没有一些复杂的配置或元数据类就足够简单。所有内容都经过编译器的正确验证,因此在发生更改时不会出现拼写错误和问题。

答案 2 :(得分:0)

我编写了一个自定义JsonConverter来处理这种情况,因为源类有一个枚举需要序列化的接口。

您的类加序列化界面:

public interface IUser {
    Guid Id { get; set; }
    string LoginName { get; set; }
    ...
}

public class User : IUser {
    ...implementation...
}

转换器:

public class InterfaceExtractorJsonConverter<T> : JsonConverter {
    private class InterfaceDictionary<T> : Dictionary<string, object> { }

    private PropertyInfo[] InterfaceProperties {
        get { return typeof(T).GetProperties(); }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
        var dictionary = new InterfaceDictionary<T>();
        foreach (var property in InterfaceProperties) {
            dictionary[property.Name] = value.GetType().GetProperty(property.Name).GetValue(value, null);
        }
        serializer.Serialize(writer, dictionary);
    }

    private object ReadNestedObject(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
        while (reader.TokenType == JsonToken.Comment) {
            if (!reader.Read())
                throw new Exception("Unexpected end.");
        }

        switch (reader.TokenType) {
            case JsonToken.StartObject:
            case JsonToken.StartArray:
                return serializer.Deserialize(reader, objectType);
            case JsonToken.Integer:
            case JsonToken.Float:
            case JsonToken.String:
            case JsonToken.Boolean:
            case JsonToken.Null:
            case JsonToken.Undefined:
            case JsonToken.Date:
            case JsonToken.Bytes:
                return reader.Value;
            default:
                throw new Exception(string.Format("Unexpected token when converting object: {0}", reader.TokenType));
        }
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
        var obj = Activator.CreateInstance(objectType);

        while (reader.Read()) {
            switch (reader.TokenType) {
                case JsonToken.PropertyName:
                    string propertyName = reader.Value.ToString();

                    if (!reader.Read())
                        throw new Exception("Unexpected end.");


                    if (!InterfaceProperties.Any(p => p.Name.Equals(propertyName, StringComparison.OrdinalIgnoreCase))) {
                        reader.Skip();
                        continue;
                    }
                    var property = objectType.GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);

                    var innerObj = ReadNestedObject(reader, property.PropertyType, existingValue, serializer);

                    property.SetValue(obj, innerObj, null);
                    break;
                case JsonToken.Comment:
                    break;
                case JsonToken.EndObject:
                    return obj;
            }
        }
        throw new Exception("Unexpected end.");
    }

    public override bool CanConvert(Type objectType) {
        return objectType.GetInterfaces().Contains(typeof(T));
    }
}

可以对转换器进行大量优化......