Какие существуют опции для сериализации при возврате экземпляров пользовательских классов из WebService?
У нас есть несколько классов с рядом свойств класса дочерней коллекции, а также другие свойства, которые могут устанавливаться или не устанавливаться в зависимости от использования. Эти объекты возвращаются из ASP.NET.asmx WebService, украшенного атрибутом ScriptService, поэтому сериализуются через сериализацию JSON при возврате различными WebMethods.
Проблема заключается в том, что внесетевая сериализация возвращает все общедоступные свойства независимо от того, используются они или нет, а также возвращает имя класса и другую информацию более подробно, чем это было бы желательно, если бы вы хотели ограничить количество трафика.
В настоящее время для возвращаемых классов мы добавили пользовательские javascript-конвертеры, которые обрабатывают сериализацию JSON, и добавили их в web.config, как показано ниже:
<system.web.extensions>
<scripting>
<webServices>
<jsonSerialization>
<converters>
<add name="CustomClassConverter" type="Namespace.CustomClassConverter" />
</converters>
</jsonSerialization>
</webServices>
</scripting>
</system.web.extensions>
Но для этого требуется специальный конвертер для каждого класса. Есть ли другой способ изменить сериализацию JSON из коробки, либо путем расширения службы, создания пользовательского сериализатора или тому подобного?
Follow Up
@marxidad:
Мы используем класс DataContractJsonSerializer в других приложениях, однако мне не удалось выяснить, как применить его к этим службам. Вот пример настройки служб:
[ScriptService]
public class MyService : System.Web.Services.WebService
{
[WebMethod]
public CustomClass GetCustomClassMethod
{
return new customClass();
}
}
WebMethods вызывается javascript и возвращает данные, сериализованные в JSON. Единственный способ, которым мы смогли изменить сериализацию, - использовать конвертеры javascript, как указано выше?
Есть ли способ сказать WebService использовать пользовательский DataContractJsonSerializer? Будь то конфигурация web.config, украшая сервис атрибутами и т.д.?
Update
Ну, мы не смогли найти какой-либо способ переключить JavaScript-сериализатор, за исключением создания отдельных JavaScriptConverters, как указано выше.
Что мы сделали с этой целью, чтобы предотвратить создание отдельного конвертера, был создан общий JavaScriptConverter. Мы добавили пустой интерфейс к классам, которые мы хотели обработать, и SupportedTypes, который вызывается при запуске веб-сервиса, использует отражение, чтобы найти любые типы, которые реализуют вид интерфейса следующим образом:
public override IEnumerable<Type> SupportedTypes
{
get
{
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
AssemblyBuilder dynamicAssemblyCheck = assembly as AssemblyBuilder;
if (dynamicAssemblyCheck == null)
{
foreach (Type type in assembly.GetExportedTypes())
{
if (typeof(ICustomClass).IsAssignableFrom(type))
{
yield return type;
}
}
}
}
}
}
Фактическая реализация немного отличается, поэтому тип кэшируется, и мы, скорее всего, реорганизуем его для использования пользовательских атрибутов, а не пустого интерфейса.
Однако при этом мы столкнулись с несколько иной проблемой при работе с пользовательскими коллекциями. Обычно они просто расширяют общий список, но пользовательские классы используются вместо самого List < > , потому что в классах коллекции обычно есть обычная логика, сортировка и т.д.
Проблема заключается в том, что метод Serialize для JavaScriptConverter возвращает словарь, который сериализуется в JSON как пары значений имени с ассоциированным типом, тогда как список возвращается как массив. Таким образом, сборники не могли быть легко сериализованы с помощью конвертера. Решением для этого было просто не включать эти типы в конвертер SupportedTypes, и они идеально сериализуются как списки.
Итак, сериализация работает, но когда вы пытаетесь передать эти объекты другим способом в качестве параметра для вызова веб-службы, десериализация прерывается, потому что они не могут быть входными данными, рассматриваются как список словарей строки/объекта, который не может быть преобразован в список любого настраиваемого класса, содержащегося в коллекции. Единственный способ, с помощью которого мы могли бы справиться с этим, - создать общий класс, который представляет собой список словарей строки/объекта, который затем преобразует список в соответствующий пользовательский класс коллекции, а затем изменяет любые параметры веб-службы, чтобы вместо этого использовать общий класс.
Я уверен, что здесь есть множество проблем и нарушений "лучших практик", но это делает работу для нас без создания тонны пользовательских классов конвертеров.