Какие есть варианты для сериализации при возврате экземпляров пользовательских классов из 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, либо путем расширения службы, создания настраиваемого сериализатора и т. П.?
Сопровождение
@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, украшение службы атрибутами и т. Д.?
Обновление
Ну, мы не смогли найти какой-либо способ переключить из коробки JavaScriptSerializer, кроме как для создания отдельных JavaScriptConverter, как указано выше.
Что мы сделали для того, чтобы избежать создания отдельного конвертера, - это создание общего 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 конвертера, и они отлично сериализуются в виде списков.
Итак, сериализация работает, но когда вы пытаетесь передать эти объекты другим способом в качестве параметра для вызова веб-службы, десериализация прерывается, потому что они не могут быть введены, обрабатывается как список словарей строк / объектов , который не может быть преобразован в список любого пользовательского класса, который содержит коллекция. Единственный способ справиться с этим - создать универсальный класс, представляющий собой список строковых / объектных словарей, который затем преобразует список в соответствующий пользовательский класс коллекции, а затем изменяет любые параметры веб-службы, чтобы вместо них использовать универсальный класс. .
Я уверен, что здесь есть масса проблем и нарушений "лучших практик", но он выполняет работу за нас, не создавая тонны пользовательских классов конвертера.