2012-04-25 2 views
0

У меня есть запрос на конечную точку, используя в Web API:веб отказ апи JSON десериализации

public HttpResponseMessage Create(IList<SlideContent> l) 
    { 
     ... 
    } 

я отправить параметр как JSON и веб-апи упорядочивает его IList

SlideContent является:

public abstract class SlideItem 
    { 
     ... 
    } 

и у меня есть специализированные классы

public class TitleSlideItem : SlideItem 
    { 
     ... 
    } 


    public class ParagraphSlideItem : SlideItem 
    { 
     ... 
    } 

просто нравится, что я не могу вызвать функцию Create, потому что я получаю

MissingMethodException: не может создать абстрактный класс

поэтому я не могу десериализации параметр JSon. если я удаляю абстрактный модификатор, то у меня нет специализированных объектов, каждый тип объекта будет SlideContent. Я даже помещал аннотации в json, но это тоже не помогает.

Если я не ошибаюсь, мне нужно написать настраиваемое связующее для абстрактного класса, но как я могу это сделать?

С уважением,

Золи

ответ

1

Одним из возможных вариантов является замена встроенного JSON сериализатором с пользовательским форматировщиком с использованием Json.NET, как показано на following blog post.

public class JsonNetFormatter : MediaTypeFormatter 
{ 
    private JsonSerializerSettings _jsonSerializerSettings; 

    public JsonNetFormatter(JsonSerializerSettings jsonSerializerSettings) 
    { 
     _jsonSerializerSettings = jsonSerializerSettings ?? new JsonSerializerSettings(); 

     // Fill out the mediatype and encoding we support 
     SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json")); 
     Encoding = new UTF8Encoding(false, true); 
    } 

    protected override bool CanReadType(Type type) 
    { 
     if (type == typeof(IKeyValueModel)) 
     { 
      return false; 
     } 

     return true; 
    } 

    protected override bool CanWriteType(Type type) 
    { 
     return true; 
    } 

    protected override Task<object> OnReadFromStreamAsync(Type type, Stream stream, HttpContentHeaders contentHeaders, FormatterContext formatterContext) 
    { 
     // Create a serializer 
     JsonSerializer serializer = JsonSerializer.Create(_jsonSerializerSettings); 

     // Create task reading the content 
     return Task.Factory.StartNew(() => 
     { 
      using (StreamReader streamReader = new StreamReader(stream, Encoding)) 
      { 
       using (JsonTextReader jsonTextReader = new JsonTextReader(streamReader)) 
       { 
        return serializer.Deserialize(jsonTextReader, type); 
       } 
      } 
     }); 
    } 

    protected override Task OnWriteToStreamAsync(Type type, object value, Stream stream, HttpContentHeaders contentHeaders, FormatterContext formatterContext, TransportContext transportContext) 
    { 
     // Create a serializer 
     JsonSerializer serializer = JsonSerializer.Create(_jsonSerializerSettings); 

     // Create task writing the serialized content 
     return Task.Factory.StartNew(() => 
     { 
      using (JsonTextWriter jsonTextWriter = new JsonTextWriter(new StreamWriter(stream, Encoding)) { CloseOutput = false }) 
      { 
       serializer.Serialize(jsonTextWriter, value); 
       jsonTextWriter.Flush(); 
      } 
     }); 
    } 
} 

затем в Application_Start при регистрации форматировщик можно настроить сериалайзер использовать информацию о типе в формате JSON:

var formatters = GlobalConfiguration.Configuration.Formatters; 
formatters.Remove(formatters.XmlFormatter); 
formatters.Remove(formatters.JsonFormatter); 

var serializerSettings = new JsonSerializerSettings(); 
serializerSettings.TypeNameHandling = TypeNameHandling.Objects; 
serializerSettings.Converters.Add(new IsoDateTimeConverter()); 
formatters.Add(new JsonNetFormatter(serializerSettings)); 

, а затем вы можете ВЫВЕСИТЬ следующий JSON:

[ 
    { 
     "$type":"AppName.Models.TitleSlideItem, AppName", 
     "Id":1, 
     "Title":"some title" // this is a specific property of the TitleSlideItemclass 
    }, 
    { 
     "$type":"AppName.Models.ParagraphSlideItem, AppName", 
     "Id":2, 
     "Paragraph":"some paragraph" // this is a specific property of the ParagraphSlideItem class 
    } 
] 

который будет успешно десериализован внутри этого действия:

public HttpResponseMessage Post(IList<SlideItem> l) 
{ 
    ... 
} 
+0

спасибо, но я хотел бы сделать это с помощью специального связующего. –

1

JsonFx создает пользовательские связующие. Например, посмотрите на:

https://code.google.com/p/jsonfx/source/browse/trunk/JsonFx/JsonFx.MvcTemplate/Global.asax.cs

Посмотрите на RegisterBinders() функцию в этом файле и источник в вяжущих или просто установить JsonFx и создать проект, используя свой шаблон MVC и посмотреть, как они это делают или просто используйте свою библиотеку, если это сработает для вас. Это то, что я сделал бы.

Смежные вопросы