среда, 4 июля 2012 г.

Генерация классов из XSD файлов с помощью Xsd2Code.

Недавно я интегрировался с веб сервисами компании Verizon. Общение с версисом происходило через XML с определенной структорой. В общем, запрос представлял из себя шапку (header) и сам запрос (body). Пример:

  
    *****
    ********
    **
    MISC
    XML
  
  
    
      ******
      
        HTC
      
    
  


В документации были только примеры XML запросов и ответов для каждого типа запроса, например активация линии, информация о немере, смена тарифного плана и тп. В основном сохранялся только тег request, а внутри него менялся контет.
Сначала я эти запросы формировал руками через XLinq и это было совсем не круто. Потом компания предоставила XSD файлы для каждого запроса и сказала, что мы можем использовать эти файлы для генерации XML запросов. До этого с XSD никогда не сталкивался и пока не нагуглил не знал как оно мне поможет.

В общем помогают эти файлы следующим образом:
1. Cначала с помощью одной из утилит XSD.exe от Microsoft или Xsd2Code на codeplex, можно сгенерить cs или vb файлы.
2. Код в этих файлах будет сгенерен с Xml аттрибутами, необхадимыми для формаирования правильного XML запроса. Чтоб сгенерить Xml, который я показал в примере, используется XmlSerializer.

Так в 2 шага можно сгенерировать валидный XML по XSD файлам.
Когда я дошел до генерации CS файлов из XSD, то выбора было не особо та и примеров как это делать тоже, в основном ссылки на xsd.exe с которым я так и не подружился.
В данной статье я хотел рассказать об утилите Xsd2Code.Чем она хороша ?
  1. Очень много настроек
  2. Интегрируется с студией
  3. Понимает теги xsd:include, которые ссылаются на другие xsd файлы.
  4. Не сложная в использовании
Как использовать ?

Для начала скачать и установить.

Дальше вызвав в консоли Xsd2Code.exe можно увидеть список доступных параметров

Usage: 

    Xsd2Code.exe  [Namespace] [Output file name] [Options]

Where:
                              - Path to an XSD file. Required
    [Namespace]                         - Generated code namespace. Optional. File name without extension if no value is specified
    [Output file name]                  - Name of the output (generated) file. Optional. 
    [Options]                           - Optional. See below for description

Options:
    /o[utput]                 - Name of the output (generated) file. 
                                          By default, name of the source file with extension .Designer.cs 
                                          (.Designer.vb or .Designer.cpp for VisualVasic and Visual C++ respectively)
    /n[s]                    - Generated code CLR namespace. Default: file name without extension
    /l[anguage]               - Generated code language (CS|VB|CPP). Default: CS
    /pl[atform]               - Generated code target platform (Net20|Net30|Net35|Silverlight20). Default: Net20
    /c[ollection]      - Collection base (Array|BindingList|List|ObservableCollection|DefinedType). Default: List
    /cu[customusings]    - Comma-separated of custom usings definition (E.g "Xsd2Code.Library,System.Xml.Linq")
    /sm                      - Serialize method name. Default: Serialize
    /dm                    - Deserialize method name. Default: Deserialize
    /lf[m]                - LoadFromFile method name. Default: LoadFromFile
    /sf[m]                  - SaveToFile methodname. Default: SaveToFile
    /is[+]                              - Include Serialize method
    /is-                                - Do not include Serialize method (default)
    /cl[+]                              - Include Clone method
    /cl-                                - Do not include Clone method (default)

Это не полный список, их раза в 2-3 больше, но нам все не надо.

Дальше генерим CS файл из XSD. Пример:
Xsd2Code.exe POSBizCheckStatus.xsd Ivanov.VerizonIntegration C:\POSBizCheckStatus.cs /pl Net35 /c Array /xa /is /sс
По порядку:
Xsd2Code.exe - путь к файлу или если вы находитесь в папке с утилитой, то просто название запускаемого файла утилиты.
POSBizCheckStatus.xsd - путь к xsd файлу или если он находится в папке с утилитой то просто нзвание файла. Вайжно!!! Лучше чтоб путь к xsd файлу не содержал пробелы, а то может не сработать
 Ivanov.VerizonIntegration - namespace в котором будет сгенерированый класс.
C:\POSBizCheckStatus.cs - путь и название cs файла в котором будет сгенереный класс по XSD схеме.
/pl Net35 - версия .NET для кода в данном случае 3.5
/c Array - как мы хотим видеть колекции, на выбоор несколько опций, в моем случае хочу чтоб колекции были как обычные массивы.
/xa - именно с этой опцией добавляются xml аттрибуты, которые помогу XmlSerializer'у правилно сгенерировать XML. Эту опцию можно отключить. Пример

    [GeneratedCode("Xsd2Code", "3.4.0.38968")]
    [Serializable]
    [DesignerCategory("code")]
    [XmlType(AnonymousType = true, Namespace = "http://pos.odc.vzwcorp.com")]
    public class miscResponseAccessoryList
    {
        private static XmlSerializer serializer;
        private miscResponseAccessoryListAccessoryInfo[] accessoryInfoField;
        private string countField;

        [XmlElement(DataType = "integer", Order = 0)]
        public string count
        {
            get { return countField; }
            set { countField = value; }
        }

        [XmlElement("accessoryInfo", Order = 1)]
        public miscResponseAccessoryListAccessoryInfo[] accessoryInfo
        {
            get { return accessoryInfoField; }
            set { accessoryInfoField = value; }
        }

/is - этот ключ добавляет в файл метод Serialize / Deserialize. Очень удобно, самому уже не надо писать.

 
public virtual string Serialize()
        {
            StreamReader streamReader = null;
            MemoryStream memoryStream = null;
            try
            {
                memoryStream = new MemoryStream();
                Serializer.Serialize(memoryStream, this);
                memoryStream.Seek(0, SeekOrigin.Begin);
                streamReader = new StreamReader(memoryStream);
                return streamReader.ReadToEnd();
            }
            finally
            {
                if ((streamReader != null))
                {
                    streamReader.Dispose();
                }
                if ((memoryStream != null))
                {
                    memoryStream.Dispose();
                }
            }
        }


/sc  - добавляет коментарии к свойствам.

Остальные ключи добавляются по мере необходимости. Есть настроки для WCF, Linq, DataBinding и тп.


Если у вас несколько XSD файлов и для них всех нужно сгенерить классы, например как у меня
















то можно использовать bat файл.

@echo off

set XsdPath="c:\Path\To\Xsd\Files"
set OutPath=%XsdPath%\Code
set ExePath="c:\Program Files (x86)\Xsd2Code\"
set Namespace=MyProject.Namespace
echo.Starting processing XSD files ...
for /f %%a IN ('dir %XsdPath%\*.xsd /a-d /b /s') do call:ProcessXsd %%a

echo.Finished processing XSD files ...
echo.&pause&
goto:eof

:ProcessXsd
%ExePath%\Xsd2Code %~1 %Namespace% %XsdPath%\Code\%~n1%.cs /pl Net35 /c Array /xa /is
echo.Processed %~n1
goto:eof

Нужно подставить значение XsdPath, OutPath, ExePath и Namespace. В моем случае я получил список файлов в папке Code.


















Это важно!
OutPath папка должна существовать, иначе провал.
XsdPath путь не должен содержать пробелов, иначе тоже пробвал

Пример использования в коде

logger.Info("Building XML for REASSIGN ACCOUNT request.");

            POSBizServices requestMessage = serviceRequestFactory.CreateReassignAccountRequest(request);

            logger.Info("Sending REASSIGN ACCOUNT request.");

            string requestXml = requestMessage.Serialize();
            string responseXml = SendRequest(requestXml);

            logger.Debug("REASSIGN ACCOUNT response: {0}.", responseXml);

            POSBizServices responseMessage;

            try
            {
                logger.Info("Deserializing XML response to POSBizServices as LINE STATUS response.");
                POSBizServices.Deserialize(responseXml, out responseMessage);
            }
            catch (Exception e)
            {
                logger.ErrorException("Error while deserializing LINE STATUS XML response to POSBizServices", e);
                throw;
            }

Пользуйтесь! Будут вопросы - отвечу.

Комментариев нет:

Отправить комментарий