Медленный конструктор SoapHttpClientProtocol
-
05-07-2019 - |
Вопрос
Я провожу некоторые эксперименты с Microsoft Dynamics CRM.Вы взаимодействуете с ним через веб-сервисы, и я добавил в свой проект веб-ссылку.Интерфейс веб-сервиса очень богат, а сгенерированный файл «Reference.cs» занимает около 90 тыс. мест.
Я использую веб-ссылку в консольном приложении.Я часто что-то меняю, перекомпилирую и запускаю.Компиляция происходит быстро, но обновление ссылки на веб-сервис происходит очень медленно и занимает около 15-20 секунд:
CrmService service = new CrmService();
Профилирование показывает, что все время тратится на конструктор SoapHttpClientProtocol.
Виновником, по-видимому, является тот факт, что код сериализации XML (не включенный в упомянутый выше блок 90k) генерируется во время выполнения перед JIT-обработкой.Это происходит во время вызова конструктора.Ожидание довольно неприятно, когда играешь и пробуешь что-то.
Я пробовал различные комбинации sgen.exe, ngen и XGenPlus (что занимает несколько часов и генерирует 500 МБ дополнительного кода), но безрезультатно.Я рассматривал возможность реализации службы Windows, имеющей несколько экземпляров CrmService, готовых к использованию при необходимости, но это кажется чрезмерным.
Есть идеи?
Решение
Из этой темы на форумах VMWare извлекается следующее:
Привет, ребята,
Мы обнаружили, что sgen.exe работает. Просто есть несколько дополнительных шагов помимо предварительной генерации dll-файлов сериализатора, которые мы пропустили в этой теме. Вот подробная инструкция
ПРОБЛЕМА
При использовании VIM 2.0 SDK из .NET требуется длительное время для создания экземпляра класса VimService. (Класс VimService - это прокси-класс, сгенерированный с помощью запуска wsdl.exe vim.wsdl vimService.wsdl)
Другими словами, следующая строка кода:
_service = new VimService();
Выполнение может занять около 50 секунд.
ПРИЧИНА
Очевидно, что .NET XmlSerializer
использует атрибуты System.Xml.Serialization. *
, аннотирующие прокси-классы для генерации кода сериализации во время выполнения. Когда прокси-классов много и много, как в VimService.cs, генерация кода сериализации может занять много времени.
Решение
Это известная проблема с работой сериализатора Microsoft .NET.
Вот некоторые ссылки, которые MSDN предоставляет для решения этой проблемы:
http://msdn2.microsoft.com/en-us/library/ bk3w6240.aspx http://msdn2.microsoft.com/en-us /library/system.xml.serialization.xmlserializerassemblyattribute.aspx р>
К сожалению, ни одна из вышеперечисленных ссылок не описывает полное решение проблемы. Вместо этого они сосредоточены на том, как предварительно сгенерировать код сериализации XML.
Полное исправление включает в себя следующие шаги:
<Ол>Создать сборку (DLL) с предварительно сгенерированным кодом XML-сериализатора
Удалите все ссылки на атрибуты System.Xml.Serialization. * из прокси-кода (т. е. из файла VimService.cs)
Аннотируйте основной прокси-класс с помощью атрибута XmlSerializerAssemblyAttribute, чтобы указать, где находится сборка XML-сериализатора.
Пропуск шага 2 приводит только к 20% -ному улучшению времени создания класса VimService
. Пропуск шага 1 или 3 приводит к неправильному коду. За все три этапа достигается улучшение на 98%.
Вот пошаговые инструкции:
Прежде чем начать, убедитесь, что вы используете инструменты .NET версии 2.0. Это решение не будет работать с версией 1.1 .NET, поскольку инструмент sgen и XmlSerializationAssemblyAttribute
доступны только в версии 2.0 .NET
Создайте файл VimService.cs из WSDL, используя wsdl.exe:
wsdl.exe vim.wsdl vimService.wsdl
Это выведет файл VimService.cs в текущий каталог
Скомпилируйте VimService.cs в библиотеку
csc / t: library /out:VimService.dll VimService.cs
Используйте инструмент sgen для предварительной генерации и компиляции сериализаторов XML:
sgen / p VimService.dll
Это выведет VimService.XmlSerializers.dll в текущий каталог
Вернитесь в файл VimService.cs и удалите все атрибуты System.Xml.Serialization. *
. Поскольку код кода большой, лучший способ достичь этого - использовать какой-либо инструмент подстановки регулярных выражений. Будьте осторожны при этом, потому что не все атрибуты появляются в строке сами по себе. Некоторые встроены как часть объявления метода.
Если вам сложно выполнить этот шаг, вот упрощенный способ сделать это:
Предполагая, что вы пишете на C #, выполните глобальную замену следующей строки:
<код> [System.Xml.Serialization.XmlIncludeAttribute код>
и замените его на
// [System.Xml.Seri
Другие советы
Возможно, вы захотите заглянуть в <код> Sgen.exe , поставляемый с .NET. В свойствах проекта Visual Studio C # есть небольшая удобная штука " Build " в самом низу страницы «Сборка сборки сериализации» который автоматически запускает Sgen
для вас.
Я считаю, что это не проблема SGEN. Я посмотрел на код конструктора и вижу, что он много размышляет (основан на XmlIncludeAttribute в классе). Это отражается на всех них и может занять очень много времени.
Существует предварительно сгенерированная сборка XmlSerializer, которая поставляется с CRM. Проверьте, есть ли у вас в GAC файлы SdkTypeProxy.XmlSerializers.dll и SdkProxy.XmlSerializers.dll.
Если этого не сделать, это означает, что при создании CrmService .net сгенерирует сборку XmlSerializer, что может занять некоторое время. Надеюсь, это поможет
Я наткнулся на эту тему, когда пытался выяснить, почему мои первоначальные вызовы SoapHttpClientProtocol
занимали так много времени. Р>
Я обнаружил, что установка прокси-сервера на ноль / пустое состояние остановила автоматическое обнаружение прокси - это занимало до 7 секунд при первоначальном вызове:
this.Proxy = GlobalProxySelection.GetEmptyWebProxy();
Я использовал приведенный выше подробный ответ в качестве руководства и сделал несколько шагов вперед, создав сценарий для автоматизации процесса.Скрипт состоит из двух файлов:
генерировать прокси.bat:
REM if your path for wsdl, csc or sgen is missing, please add it here (it varies from machine to machine)
set PATH=%PATH%;C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools;C:\Program Files (x86)\MSBuild\14.0\Bin
wsdl http://localhost:57237/VIM_WS.asmx?wsdl REM create source code out of WSDL
PowerShell.exe -ExecutionPolicy Bypass -Command "& '%~dpn0.ps1'" REM proces source code (remove annotations, add other annotation, put class into namespace)
csc /t:library /out:references\VIM_Service.dll VIM_WS.cs REM compile source into dll
sgen /p references\VIM_Service.dll /force REM generate serializtion dll
генерировать прокси.ps1
(Get-Content VIM.cs) |
ForEach-Object {
$_ -replace "(?<attr>\[global::System.Xml.Serialization.[^\]]*\])", "/*${attr}*/" `
-replace "public partial class VIM", "[System.Xml.Serialization.XmlSerializerAssemblyAttribute(AssemblyName = ""VIM_Service.XmlSerializers"")] `npublic partial class VIM" `
-replace "using System;", "namespace Classes.WS_VIM { `n`nusing System;"
} |
Set-Content VIM.cs
Add-Content VIM.cs "`n}"
Я добавил эти два файла в клиентский проект, а в событии перед сборкой добавил строки
cd..\..
generateproxy
Таким образом, перед каждой сборкой прокси-классы перегенерируются, и разработчику (почти) не нужно об этом думать.Во время сборки WS должен быть запущен и работать, а его URL-адрес должен находиться в bat-файле.В результате предварительной сборки два файла DLL будут восстановлены в подпапке клиентского проекта. Рекомендации.После первого выполнения скриптов необходимо добавить ссылку на новую dll.