Сериализация модели Linq2sql выборочно в JSON - PullRequest
0 голосов
/ 06 октября 2011

У меня довольно распространенная бизнес-модель linq2sql из базы данных mssql. Между таблицами есть некоторые ассоциации, и это хорошо. Вся модель находится в отдельной сборке. Я использую библиотеку 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 голосов
/ 07 октября 2011

Хорошо, я выбрал подход, основанный на пользовательском 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
        };
    }
}

Достаточно просто без каких-либо сложных классов конфигурации или классов метаданных.Все правильно проверено компилятором, поэтому никаких опечаток и проблем при внесении изменений.

0 голосов
/ 20 марта 2012

Я написал собственный 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));
    }
}

Можно сделать много оптимизаций для конвертера ...

0 голосов
/ 07 октября 2011

Вы можете использовать Свободный Json , чтобы преобразовать их в JSON. Эта конфигурация может быть выполнена в коде без использования атрибутов.

Вариант 2: Вы можете использовать Пользовательский сериализатор

Вариант 3: Вы можете использовать KeyValuePairConverter . Преобразуйте свой постоянный класс в словарь и используйте его.

...