Универсальная десериализация WCF JSON

Я немного плохо знаком с WCF и попытаюсь ясно описать то, что я пытаюсь сделать.

У меня есть веб-сервис WCF, который использует запросы JSON. Я в порядке, отправляя/получая JSON по большей части. Например, следующий код работает хорошо и как ожидалось.

JSON отправляется:

{ "guy": {"FirstName":"Dave"} }

WCF:

    [DataContract]
    public class SomeGuy
    {
        [DataMember]
        public string FirstName { get; set; }
    }

    [OperationContract]
    [WebInvoke(Method = "POST",
               BodyStyle = WebMessageBodyStyle.WrappedRequest,
               RequestFormat = WebMessageFormat.Json,
               ResponseFormat = WebMessageFormat.Json)]
    public string Register(SomeGuy guy)
    {
        return guy.FirstName;
    }

Это возвращает объект JSON с "Dave" как ожидалось. Проблема состоит в том, что я не могу всегда гарантировать, что JSON, который я получаю, будет точно соответствовать участникам в моем DataContract. Например, JSON:

{ "guy": {"firstname":"Dave"} }

не сериализирует правильно, потому что случай не соответствует. парень. FirstName будет пустым. Это поведение имеет смысл, но я действительно не знаю, как обойти это. Я должен вызвать имена полей на клиенте или есть ли способ, которым я могу согласовать на стороне сервера?

Возможно связанный вопрос: я могу принять и сериализировать универсальный объект JSON в StringDictionary или некоторую простую структуру значения ключа? Таким образом независимо от того, что имена полей отправляются в JSON, я могу получить доступ к именам и значениям, которые были отправлены мне? Прямо сейчас единственный способ, которым я могу считать данные, которые я получаю, состоит в том, если это точно соответствует предопределенному DataContract.

14
задан davidmdem 28 August 2017 в 14:08
поделиться

4 ответа

Как следует из названия, контракт данных представляет собой набор правил. Если вы хотите надежно сопоставить сообщения с операциями, необходимо соблюдать эти правила.

Почему вы не можете гарантировать, что корпус будет правильным? Если вместо этого вы просто хотите использовать идентификаторы в нижнем регистре из JavaScript, вы можете использовать для этого атрибут MessageParameter , но вам все равно нужно выбрать конкретное имя .

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

Я думаю, что вам действительно нужно исправить не тот факт, что контракт данных чувствителен к регистру, а тот факт, что JSON не собирается правильно на стороне клиента.


Если вы хотите принять необработанную строку JSON в своей операции, измените BodyStyle на WebMessageBodyStyle.Bare и измените подпись метода, чтобы он принимал единственный строковый параметр, который будет заполнен любой строкой JSON, отправленной клиентом.

Обратите внимание, что все, что вы получаете, - это одна строка , из которой вы должны выполнять весь синтаксический анализ, сопоставление свойств, проверку и обработку ошибок. Я бы не пошел по этому пути, но если вы готовы взять на себя соответствующие усилия и риск, это один из возможных вариантов.

4
ответ дан 1 December 2019 в 12:52
поделиться

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

Вы могли бы предоставить реализацию IDataContractSurrogate , но для этого потребуется много дополнительной работы с вашей стороны, а также много размышлений (нет возможности сделать это статическим способом, который можно проверить во время компиляции).

Лично я отказался от использования класса DataContractSerializer , когда дело касается JSON. Скорее, я использую Json.NET для всех моих потребностей JSON.Я вижу, где вы могли бы подключить Json.NET к DataContractSerializer через IDataContractSurrogate , но это все равно будет немного грубо.

Json.NET был легким выбором, учитывая сложность использования DataContractSerializer . Кроме того, добавьте к тому факту, что DataContractSerializer для JSON не обрабатывает значения DateTimeOffset правильно, и для меня это не было проблемой, особенно с учетом того, что я работал в ASP. NET MVC (которая позволяет мне формировать результат так, как я хочу).

Это действительно лучший выбор, если вы предоставляете RESTful-сервисы с использованием JSON в качестве кодировки. Вы можете смешивать и сопоставлять это с WCF, чтобы предоставить все конечные точки по всем транспортным протоколам и протоколам сообщений, которые вам нужны.

3
ответ дан 1 December 2019 в 12:52
поделиться

Это действительно зависит от того, для чего вы используете данные. Теоретически вы можете сохранить этот общий тип, указав возвращаемый строковый тип. Однако данные будут представлять объект, и элемент управления на стороне клиента должен знать, как перечислить возвращаемый объект JSON. Вы можете вернуть тип, который также может помочь.

Затем в коде на стороне клиента вы можете иметь функцию, которая знает, как определять и читать различные типы.

0
ответ дан 1 December 2019 в 12:52
поделиться

Да, примеры см. на этой странице .

Отредактируйте

XPCOM и поэтому nsIFile теперь являются устаревшими технологиями:

Использование OS.File является предпочтительным по сравнению с примерами в этой статье. Используйте эти устаревшие интерфейсы только в том случае, если OS.File недоступен.

Вы можете найти новый способ перейти здесь

-121--2853346-

RequeyJS имеет инструмент оптимизации , который может объединить несколько файлов вместе, и он использует компилятор закрытия Google для выполнения minification/comment зачеркивания JavaScript. Инструмент оптимизации был основан на работе, которую я делал в системе Dojo build, но это то, что работает более автономно.

Отказ от ответственности: я разрабатываю требования JS

-121--4378539-

Для достижения моей цели иметь сервис, который может принять совершенно произвольный список пар «key»: «value» в качестве сырой строки JSON, а затем решить, что делать с ними без необходимости знать имена «key» заранее, я объединил каспер и совет Аарона.

1-й, чтобы получить доступ к необработанному ряду JSON, этот блог MSDN был очень полезен.

Мне не удалось без проблем просто изменить параметр одного метода на String и BodyStyle на WebStartBodyStyle.Bare . При установке для BodyStyle значения Bare убедитесь, что для конечной точки behaviorConfiguration задано значение < webHttp/> , а не < enureWebScript/> .

Второе замечание заключается в том, что, как указано в casperOne , метод может иметь только 1 параметр. Для доступа к исходному тексту (см. блог MSDN выше) этот параметр должен иметь значение Stream .

Как только вы получите необработанную последовательность JSON, это просто вопрос десериализации ее в StringDictionary. Я выбрал JSON.Net для этого и это работает замечательно. Вот пример с голыми костями.

[OperationContract]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Bare,
    ResponseFormat = WebMessageFormat.Json)]
public string Register(Stream rawJSON)
{ 
    // Convert our raw JSON string into a key, value
    StreamReader sr = new StreamReader(rawJSON);
    Dictionary<string, string> registration =     
        JsonConvert.DeserializeObject<Dictionary<string, string>>(
            sr.ReadToEnd());

    // Loop through the fields we've been sent.
    foreach (KeyValuePair<string, string> pair in registration)
    {
        switch (pair.Key.ToLower())
        {
            case "firstname":
                return pair.Value;
                break;
        }

    }
}

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

3
ответ дан 1 December 2019 в 12:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: