2011-10-06 4 views
0

나는 mssql 데이터베이스에서 꽤 일반적인 linq2sql 비즈니스 모델을 가지고있다. 테이블 간에는 몇 가지 연관성이 있습니다. 전체 모델은 별도의 어셈블리에 있습니다. 직렬화를 위해 JSON.NET 라이브러리를 사용하고 있습니다.JSON에 선택적으로 Linq2sql 모델 직렬화

이제 JSON에 해당 모델을 직렬화하고 사용할 속성과 현재 적용 할 속성을 지정해야합니다. 속성을 사용할 수 없지만 메타 데이터 클래스에 대한 아이디어가 마음에 들지 않습니다.

그래서 내가 이런 식으로 확장 방법을 사용하여에 대해 생각했다 :

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; } 
} 

마 당신은 그 확장 메소드를 효과적으로 사용하는 방법을 알고 있습니까? 아니면 다른 완전히 다른 아이디어입니까?

답변

0

나는 사용자 정의 JsonConverter를 기반으로 접근법을 결정했는데, 위의 접근법과 매우 비슷한 결과를 얻었습니다. 그것은 다음과 같습니다 일부 복잡한 구성 또는 메타 데이터 클래스없이 충분히

[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 
     }; 
    } 
} 

간단한 :

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(); 
    } 
} 

그럼 난 그냥 같은 클래스를 만든다. 모든 것이 컴파일러에 의해 적절하게 검증되므로 변경이 발생할 때 오타 나 문제가 발생하지 않습니다.

0

Fluent Json을 사용하여 json으로 변환 할 수 있습니다. 이 구성은 속성을 사용하지 않고 코드에서 수행 할 수 있습니다.

옵션 2 : 당신은 Custom Serializer

옵션 3을 사용할 수 있습니다 : 당신은 KeyValuePairConverter을 사용할 수 있습니다. 영속 클래스를 사전으로 변환하고 이것을 사용하십시오.

+0

감사합니다! 유창한 Json은 재미있어 보이는데, json.net 대신에 사용하는 것에 대해 생각할 것입니다. 사용자 지정 변환기는 옵션 일 수 있지만 최후의 수단으로 사용하고 있습니다. 그러나 KeyValuePair는 쓸모가 없거나 정확하게 사용하지 않는다. – FredyC

+0

Allright ... 유창한 Json은 훌륭하지만 너무 지나치다. JSON.NET에서는 기본적으로 구성없이 간단한 객체를 직렬화 할 수 있습니다. 이 목적을 위해 사용자 지정 변환기가 다소 제한되어 있으므로 속성 자체에 대한 참조가 없으므로 serialization에 대한 정보가있는 추가 특성을 읽을 수 없습니다. – FredyC

+0

예 Json.NET은 부드럽고 구성이 필요하지 않습니다. 그러나 귀하의 경우에는 구성이 필요하며 속성을 사용할 수 없습니다. 확실히 Json.NET을 사용하려면 JsonIgnore 등의 모든 Json 속성이 적용된 POCO를 만들고이 POCO에 영구 클래스를 매핑하십시오.따라서 매퍼와 POCO는 json이되는 것을 미세하게 제어 할 것입니다. – Zasz

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)); 
    } 
} 

최적화의 많은 컨버터를 만들 수 있습니다 ...