Использование WCF из WPF очень медленно при первом использовании

Я несколько дней боролся с проблемами с нашими приложениями WPF, и мне интересно, кто-то сталкивался с этим раньше и может помочь? Проблема, похоже, сводится к тому, что клиент генерирует "на лету" сериализатор для обработки типов в этом вызове веб-метода. Когда этот метод вызывается в первый раз (сам веб-сервис уже запущен), он может принимать, например, 8 секунд, последующие вызовы могут принимать, например. 20мс. Процессор в процессе WPF клиента v. Высокий во время этой задержки.

При использовании XmlSerializer существует способ предварительной генерации этих сборок сериализации, используя svcutil. Когда (как мы) используем обычный WCF DataContractSerializer, этот параметр, похоже, не присутствует.

Я хотел бы иметь возможность предварительно сгенерировать эту сборку для всех типов во всех моих контрактах с данными (много) или, альтернативно, заменить этот процесс на пользовательский, который я могу кодировать и передавать данные в бинарный (у нас есть оба конца этого веб-сервиса/клиента, и они оба являются .NET 4). Я уже использовал сжатие BinaryForamtter и GZip, и, хотя это ускоряет передачу данных, он всегда восстанавливается, чтобы XML был де-сериализован каркасом, поэтому эта проблема остается.

Любые идеи?

Ответ 1

Вы можете использовать двоичную библиотеку, такую ​​как protobuf-net, что довольно быстро, даже если есть начальная стоимость запуска, потому что код должен быть сгенерирован для каждого типа, он по-прежнему лучше, чем DataContractSerializer или BinaryFormatter. Вы должны получить несколько секунд и иметь общий более плавный опыт. Он может быть легко интегрирован с WCF. Имейте в виду, что WCF по-прежнему будет проверять ваши различные контракты для создания правильного WSDL и различных метаданных.

Есть другие вещи, которые могут замедлить запуск WCF, например, определить веб-прокси по умолчанию. Убедитесь, что useDefaultWebProxy false в вашей конфигурации привязки, если вы не используете его.

Тем не менее, вы обнаружите, что запуск WCF обычно медленный, независимо от того, что вы делаете, чтобы его оптимизировать. Лично, усталый от борьбы с медлительностью в подобном сценарии (я контролировал оба конца, а клиент был WPF-приложением), я просто отбросил WCF и пошел на ServiceStack + protobuf-net. Первый вызов длился от 2-3 секунд до ~ 100 мс, и все последующие HTTP-вызовы действительно мгновенно. Общий пользовательский интерфейс значительно улучшился. Обратите внимание, что я никоим образом не связан с ServiceStack, это только мой опыт.

Ответ 2

Вы подтвердили, просмотрев созданную ссылку на службу, которую действительно использует DataContractSerializer? Возможно, из-за несоответствия какой-либо схемы во время операции добавления ссылки на службу код XmlSerializer был сгенерирован вместо стандартного DataContractSerializer, который вызывает это поведение, типичное для XmlSerializer. В этом случае, как вы отметили, вы можете предварительно генерировать код сериализации для улучшения холодного запуска: http://msdn.microsoft.com/en-us/library/aa751883.aspx. Благодарю.

Ответ 3

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

Просто несколько идей... которые "могут" помочь ускорить работу в области сериализации.

Что касается предварительного генерации сериализационных сборок для ваших типов сервисов... есть опция в Project | Build, называемая "Generate Serialization Assembly".... если переключатель "On", то он генерирует сборки в Build а не динамически во время выполнения.

Неясно, является ли эта опция только для предварительной генерации сериализационных сборок для сериализаторов на основе XMLSerializer или для DataContractSerializers. Вы можете попробовать переключить его на "On", чтобы узнать, не изменилось ли оно.

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

DataContractSerializer ps = new DataContractSerializer(typeof(Person));
DataContractSerializer cs = new DataContractSerializer(typeof(Company));
etc...

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