Как я могу принимать произвольные объекты JSON в моей службе REST WCF?

Я хочу реализовать такой сервисный метод:

[OperationContract]
[WebInvoke(RequestFormat = WebMessageFormat.Json, ResponseFormat=WebMessageFormat.Json)]
public void MakeShape(string shape, string color, IDictionary moreArgs)
{
    if (shape == "circle")
    {
        MakeCircle(color, moreArgs);
    }
}

Объекты POST моих клиентов, такие как:

{
    "shape":"circle",
    "color": "blue",    
    "radius": 42,
    "filled":true,
    "annotation": {"date":"1/1/2012", "owner":"George"}
}

При вызове MakeCircle moreArgs будет иметь 3 записи («радиус», «заполненный» и словарь с именем «аннотация», который содержит 2 пары ключевых -значений.)


Лучшее, что у меня есть, это:

//Step 1: get the raw JSON by accepting a Stream with BodyStyle=WebMessageBodyStyle.Bare
[OperationContract]
[WebInvoke(RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle=WebMessageBodyStyle.Bare)]
public void MakeShape(Stream jsonStream)
{
    //Step 2: parse it into a Dictionary with JavaScriptSerializer or JSON.net
    StreamReader reader = new StreamReader(jsonStream);
    JavaScriptSerializer jsSerializer = new JavaScriptSerializer();
    Dictionary args = jsSerializer.Deserialize>(reader.ReadToEnd());            

    //Step 3: manually lookup and cast the "standard" arguments, and remove them from the Dictionary
    string shape = (string)args["shape"];
    string color = (string)args["color"];            

    //Step 4: make the original call, passing the remaining Dictionary as moreArgs
    MakeShape(shape,color,args);
}

Я мог бы жить с таким решением, за исключением того, что шаг 3 будет болезненным для синхронизации десятков методов. Очевидно что-то должно открывать словарь и использовать дополнительные аргументы, но я предпочитаю не использовать этот код в своем коммуникационном уровне. ИМО, это входит в бизнес-логику, которая знает об аргументах (, в данном случае представленных MakeCircle ).

Мне очень нравится автоматическая привязка WCF, потому что она устраняет эти склонные к ошибкам -ручные переводы. Хотелось бы, чтобы был способ использовать его для почти всего, за исключением указания небольшой дополнительной логики для аргументов, которые он не знает, как отображать. Возможно, есть какое-то поведение службы, которое говорит: «Передайте их [этому коду], и я разберусь с этим»?


Я рассмотрел поддержку «кругового -отключения», предлагаемую IExtensibleDataObject, но, похоже, она не дает моему коду доступа к неизвестным свойствам -, которые они завернуты с единственной целью отправки обратно клиенту..http://msdn.microsoft.com/en-us/library/ms731083.aspx


Другой вариант — использовать пользовательский класс, содержащий IDictionary, и каким-то образом взять на себя десериализацию. Таким образом, метод обслуживания будет :[Контракт операции] [WebInvoke (RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest )] public void MakeShape (форма строки, цвет строки, MoreArgs moreArgs)

И мне пришлось бы принуждать клиентов к более строгой структуре:

{
    "shape":"circle",
    "color": "blue",
    "moreArgs":{
        "radius": 42,
        "filled":true
        "annotation": {"date":"1/1/2012", "owner":"George"}
        }
}

Это не идеально, но я мог бы жить с этим. Возникает вопрос, как определить MoreArgs и правильно заполнить его.Моя следующая попытка:

[DataContract]
public class MoreArgs : ISerializable
{
    public Dictionary Properties;
    public MoreArgs(SerializationInfo info, StreamingContext context)  
    {
        Properties = new Dictionary();  
        foreach (var entry in info)  
        {                      
        Properties.Add(entry.Name, entry.Value);  
        }
    }  
    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        foreach (string key in Properties.Keys)
        {
        info.AddValue(key, Properties[key]);
        }  
    }
}

Это создает исключение InvalidDataContractException при запуске службы (... MoreArgs не может быть ISerializable и иметь атрибут DataContractAttribute.)

Удаление атрибута [DataContract] вызывает исключение InvalidDataContractException. Я ожидаю, что (...MoreArgs не может быть сериализован. Попробуйте пометить его атрибутом DataContractAttribute... ).

Также, как и ожидалось, удаление наследования ISerializable очищает исключение, но приводит к тому, что moreArgs.Properties становится нулевым при вызове MakeCircle.


Мне также интересно, есть ли какое-то гибридное решение, которое я могу использовать? Возможно:

  • Принять поток и создать словарь аргументов, как в моей первой попытке
  • Определите метод с аргументом MoreArgs, как в моей более поздней попытке
  • Заполните объект MoreArgs из словаря, извлеченного из потока
  • . Каким-то образом повторно -вызовите WCF, сказав «вызовите метод, который будет вызван, если у вас есть эти аргументы» (, указав исходный словарь аргументов, а также новый -правильно заполненный MoreArgs ).

Тогда MoreArgs также будет содержать исходные аргументы, но это, вероятно, не катастрофа. Я думаю, что, вероятно, мог бы сделать нужный мне вызов с помощью отражения, но это выглядит глупо, когда WCF должен иметь эту функцию внутри, отлаженную и оптимизированную для загрузки.

8
задан solublefish 13 July 2012 в 07:18
поделиться