Udostępnij za pośrednictwem


WSDL i kontrakty usług

Narzędzie Wsutil.exe generuje wycinkę języka C zgodnie z dostarczonymi metadanymi WSDL, a także definicjami typów danych i opisami typów danych opisanych przez schematy XML utworzone przez użytkownika.

Poniżej przedstawiono przykładowy dokument WSDL i schemat XML, który służy jako podstawa do dyskusji, która jest następująca:

<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://Example.org" 
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:xs="http://www.w3.org/2001/XMLSchema" 
xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" targetNamespace="http://Example.org" 
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
 <wsdl:types>
  <xs:schema xmlns:tns="http://Example.org" elementFormDefault="qualified" 
  targetNamespace="http://Example.org" xmlns:xs="http://www.w3.org/2001/XMLSchema">
   <xs:element name="SimpleMethod">
    <xs:complexType>
     <xs:sequence>
      <xs:element name="a" type="xs:int" />
      <xs:element name="b" type="xs:int" />
     </xs:sequence>
    </xs:complexType>
   </xs:element>
   <xs:element name="SimpleMethodResponse">
    <xs:complexType>
     <xs:sequence>
      <xs:element name="b" type="xs:int" />
      <xs:element name="c" type="xs:int" />
     </xs:sequence>
    </xs:complexType>
   </xs:element>
  </xs:schema>
 </wsdl:types>
 <wsdl:message name="ISimpleService_SimpleMethod_InputMessage">
  <wsdl:part name="parameters" element="tns:SimpleMethod" />
 </wsdl:message>
 <wsdl:message name="ISimpleService_SimpleMethod_OutputMessage">
  <wsdl:part name="parameters" element="tns:SimpleMethodResponse" />
 </wsdl:message>
 <wsdl:portType name="ISimpleService">
  <wsdl:operation name="SimpleMethod">
   <wsdl:input wsaw:Action="http://Example.org/ISimpleService/SimpleMethod" 
   message="tns:ISimpleService_SimpleMethod_InputMessage" />
   <wsdl:output wsaw:Action="http://Example.org/ISimpleService/SimpleMethodResponse" 
   message="tns:ISimpleService_SimpleMethod_OutputMessage" />
  </wsdl:operation>
 </wsdl:portType>
 <wsdl:binding name="DefaultBinding_ISimpleService" type="tns:ISimpleService">
  <soap:binding transport="http://schemas.xmlsoap.org/soap/http" />
  <wsdl:operation name="SimpleMethod">
   <soap:operation soapAction="http://Example.org/ISimpleService/SimpleMethod" 
   style="document" />
   <wsdl:input>
    <soap:body use="literal" />
   </wsdl:input>
   <wsdl:output>
    <soap:body use="literal" />
   </wsdl:output>
  </wsdl:operation>
 </wsdl:binding>
 <wsdl:service name="SimpleService">
  <wsdl:port name="ISimpleService" binding="tns:DefaultBinding_ISimpleService">
   <soap:address location="http://Example.org/ISimpleService" />
  </wsdl:port>
 </wsdl:service>
</wsdl:definitions>

W tym przykładzie przedstawiono kontrakt ISimpleService z pojedynczą metodą SimpleMethod. Parametr "SimpleMethod" ma dwa parametry wejściowe typu liczby całkowitej, i b, które są wysyłane z klienta do usługi. Podobnie simpleMethod ma dwa parametry wyjściowe typu liczby całkowitej, b i c, które są zwracane do klienta po pomyślnym zakończeniu. W składni języka C z adnotacjami SAL definicja metody jest wyświetlana w następujący sposób:

void SimpleMethod(__in int a, __inout int *  b, __out int * c );

W tej definicji usługa ISimpleService jest kontraktem usługi z jedną operacją usługi: SimpleMethod.

Plik nagłówka danych wyjściowych zawiera definicje i opisy zewnętrznych odwołań. Obejmuje to:

  • Definicje struktury języka C dla typów elementów globalnych.
  • Prototyp operacji zdefiniowany w bieżącym pliku.
  • Prototyp tabeli funkcji dla kontraktów określonych w pliku WSDL.
  • Prototypy zastępcze serwera proxy i usługi klienta dla wszystkich funkcji określonych w bieżącym pliku.
  • Struktura danych WS_ELEMENT_DESCRIPTION dla globalnych elementów schematu zdefiniowanych w bieżącym pliku.
  • Struktura danych WS_MESSAGE_DESCRIPTION dla wszystkich komunikatów określonych w bieżącym pliku.
  • Struktura danych WS_CONTRACT_DESCRIPTION dla wszystkich kontraktów określonych w bieżącym pliku.

Jedna struktura globalna jest generowana w celu hermetyzacji wszystkich globalnych opisów typów schematów i typów modeli usług, do których aplikacja może się odwoływać. Struktura nosi nazwę przy użyciu znormalizowanej nazwy pliku. W tym przykładzie Wsutil.exe generuje strukturę definicji globalnych o nazwie "example_wsdl", która zawiera wszystkie opisy usług internetowych. Definicja struktury jest generowana w pliku wycinkowym.

typedef struct _example_wsdl
{
  struct {
    WS_ELEMENT_DESCRIPTION SimpleMethod;
    WS_ELEMENT_DESCRIPTION SimpleMethodResponse;
  } elements;
  struct {
    WS_MESSAGE_DESCRIPTION ISimpleService_SimpleMethod_InputMessage;
    WS_MESSAGE_DESCRIPTION ISimpleService_SimpleMethod_OutputMessage;
  } messages;
  struct {
    WS_CONTRACT_DESCRIPTION DefaultBinding_ISimpleService;
  } contracts;
} _example_wsdl;

extern const _stockquote_wsdl stockquote_wsdl;

W przypadku globalnych definicji elementów w dokumencie schematu XML (XSD), jeden WS_ELEMENT_DESCRIPTION prototyp, a także odpowiednie definicje typu C, są generowane dla każdego z elementów. Prototypy opisów elementów dla elementów SimpleMethod i SimpleMethodResponse są generowane jako elementy członkowskie w strukturze powyżej. Struktury języka C są generowane w następujący sposób:

typedef struct SimpleMethod
{
  int   a;
  int   b;
} SimpleMethod;

typedef struct SimpleMethodResponse
{
  int   b;
  int   c;
} SimpleMethodResponse;

Podobnie w przypadku globalnych typów złożonych Wsutil.exe generuje definicje struktury typu C, takie jak powyżej, bez dopasowywania opisów elementów.

W przypadku danych wejściowych WSDL Wsutil.exe generuje następujące prototypy i definicje:

  • Dla opisu komunikatu jest generowany prototyp WS_MESSAGE_DESCRIPTION. Ten opis może być używany przez model usługi, a także warstwę komunikatów. Struktury opisu komunikatów to pola o nazwie "messagename" w strukturze globalnej. W tym przykładzie opis komunikatu jest generowany jako pole ISimpleService_SimpleMethod_InputMessage w strukturze ISimpleService_SimpleMethod_InputMessage, jak określono w pliku WSDL.
  • WS_CONTRACT_DESCRIPTION prototyp jest generowany dla opisu kontraktu. Ten opis jest używany przez model usługi. Struktury opisu kontraktu to pola o nazwie "contractname" w strukturze globalnej. W tym przykładzie opis kontraktu jest generowany jako pole DefaultBinding_ISimpleService w strukturze "_example_wsdl".

Specyfikacje operacji i typu są wspólne zarówno dla serwera proxy, jak i wycinku, a także są generowane w obu plikach. Wsutil.exe generuje jedną kopię tylko wtedy, gdy zarówno serwer proxy, jak i wycinków są generowane w tym samym pliku.

Generowanie identyfikatorów

Automatycznie wygenerowane struktury języka C wymienione powyżej są tworzone na podstawie nazwy określonej w pliku WSDL. Nazwa NCName XML nie jest powszechnie uważana za prawidłowy identyfikator języka C, a nazwy są znormalizowane zgodnie z potrzebami. Wartości szesnastkowy nie są konwertowane, a typowe litery, takie jak ":", "/" i ""., są konwertowane na znak podkreślenia "_", aby zwiększyć czytelność.

Nagłówek wycinku

Dla każdej operacji w kontrakcie usługi jest generowana jedna rutyna wywołania zwrotnego o nazwie "<operationname>Callback". (Na przykład operacja "SimpleMethod" w przykładowym kontrakcie usługi ma wygenerowane wywołanie zwrotne o nazwie "SimpleMethodCallback".

typedef HRESULT (CALLBACK *SimpleMethodCallback) (
  const WS_OPERATION_CONTEXT * context,
  int a, int *b, int *c,
  const WS_ASYNC_CONTEXT *asyncContext,
  WS_ERROR * error);

Dla każdego portType języka WSDL Wsutil.exe generuje tabelę funkcji reprezentującą portType. Każda operacja na portType ma odpowiedni wskaźnik funkcji do wywołania zwrotnego obecnego w tabeli funkcji.

struct ISimpleServiceMethodTable
{
  ISimpleService_SimpleMethodCallback SimpleMethod;
};

Prototypy serwera proxy są generowane dla wszystkich operacji. Nazwa prototypu to nazwa operacji (w tym przypadku "SimpleMethod") określona w pliku WSDL dla kontraktu usługi.

HRESULT WINAPI SimpleMethod(WS_CHANNEL *channel,
  WS_HEAP *heap,
  int a,
  int *b,
  int *c,
  const WS_ASYNC_CONTEXT * asyncContext,
  WS_ERROR * error );

Generowanie prototypów tylko dla opisu lokalnego

Pliki proxy istub zawierają definicję struktury definicji globalnych, w tym prototypy i definicje struktur zawierających opisy lokalne i implementacje zastępcze serwera proxy/usługi.

Wszystkie prototypy i definicje lokalne w pliku wycinkowym są generowane w ramach struktury hermetyzacji. Ta nadrzędna struktura opisu lokalnego zapewnia wyraźną hierarchię opisów wymaganych przez warstwę serializacji i model usługi. Struktura opisu lokalnego ma prototypy podobne do przedstawionego poniżej:

struct _filenameLocalDefinitions
{
  struct {
  // schema related output for all the embedded 
  // descriptions that needs to describe global complex types.
  } globalTypes;
  // global elements.
  struct {
  // schema related output, like field description
  // structure description, element description etc.
  ...
  } globalElements;
  struct {
  // messages and related descriptions
  } messages;
  struct {
  // contract and related descriptions.
  } contracts;
  struct {
  // XML dictionary entries.
  } dictionary;
} _filenameLocalDefinitions;

Odwoływanie się do definicji z innych plików

Definicje lokalne mogą odwoływać się do opisów wygenerowanych w innym pliku. Na przykład komunikat może być zdefiniowany w pliku kodu C wygenerowany z pliku WSDL, ale element komunikatu może być zdefiniowany w innym miejscu w pliku kodu C wygenerowany z pliku XSD. W tym przypadku Wsutil.exe generuje odwołanie do elementu globalnego z pliku zawierającego definicję komunikatu, jak pokazano poniżej:

{  // WS_MESSAGE_DESCRIPTION
...
(WS_ELEMENT_DESRIPTION *)b_xsd.globalElement.<elementname>
  };

Opisy elementów globalnych

Dla każdego elementu globalnego zdefiniowanego w pliku wsdl:type lub XSD istnieje zgodne pole o nazwie elementName wewnątrz pola GlobalElement. W tym przykładzie jest generowana struktura o nazwie SimpleMethod:

typedef struct _SimpleServiceLocal
{
  struct  // global elements
  {
    struct // SimpleMethod
    {
    ...
    WS_ELEMENT_DESCRIPTION SimpleMethod;
    } SimpleMethod;
    ...
  } globalElements;
}

Inne opisy wymagane przez opis elementu są generowane w ramach struktury zawierającej. Jeśli element jest prostym elementem typu, istnieje tylko jedno pole WS_ELEMENT_DESCRIPTION. Jeśli typ elementu jest strukturą, wszystkie powiązane pola i opisy struktury są generowane w ramach struktury elementów. W tym przykładzie element SimpleMethod to struktura zawierająca dwa pola, i b. Wsutil.exe generuje strukturę w następujący sposób:

...
struct // SimpleMethod
{
  struct // SimpleMethod structure
  {
    WS_FIELD_DESCRIPTION a;
    WS_FIELD_DESCRIPTION b;
    WS_FIELD_DESCRIPTION * SimpleMethodFields [2];
    WS_STRUCT_DESCRIPTION structDesc;
  } SimpleMethoddescs; // SimpleMethod
  WS_ELEMENT_DESCRIPTION elementDesc;
} SimpleMethod;
...

Osadzone struktury i osadzone elementy są generowane jako struktury podrzędne zgodnie z potrzebami.

Wsutil.exe generuje pole w sekcji WSDL dla każdego z portType wartości zdefiniowanych w określonym pliku wsdl:service.

...
struct { // WSDL
    struct { // portTypeName
        struct { // operationName
        } operationName;
    ...
    WS_OPERATION_DESCRIPTION* operations[numOperations];
    WS_CONTRACT_DESCRIPTION contractDesc;
    } portTypeName;
}
...

Wsutil.exe generuje jedno pole f, które zawiera wszystkie opisy wymagane do operacji, tablicę sypki wskaźników do każdej z opisów operacji dla każdej metody, a jeden WS_CONTRACT_DESCRIPTION dla określonego portType.

Wszystkie opisy wymagane przez operacje są generowane wewnątrz pola operationName w określonym portType. Obejmują one pole WS_ELEMENT_DESCRIPTION, a także podstrukturę parametrów wejściowych i wyjściowych. Podobnie pola WS_MESSAGE_DESCRIPTION komunikatu wejściowego i opcjonalny komunikat wyjściowy są uwzględniane wraz z elementem ; WS_PARAMETER_DESCRIPTION pole listy dla wszystkich parametrów operacji i pola WS_OPERATION_DESCRIPTION dla samej operacji. W tym przykładzie struktura kodu dla opisu SimpleMethod jest generowana, jak pokazano poniżej:

...
struct // messages
{
  WS_MESSAGE_DESCRIPTION ISimpleService_SimpleMethod_InputMessage;
  WS_MESSAGE_DESCRIPTION ISimpleService_SimpleMethod_OutputMessage;
} messages;
struct // contracts
{
  struct // DefaultBinding_ISimpleService
  {
    struct // SimpleMethod
    {
      WS_PARAMETER_DESCRIPTION params[3];
      WS_OPERATION_DESCRIPTION SimpleMethod;
    } SimpleMethod;
    WS_OPERATION_DESCRIPTION* operations[1];
    WS_CONTRACT_DESCRIPTION contractDesc;
  } DefaultBinding_ISimpleService;
} contracts;
...

Nazwy i przestrzenie nazw używane w różnych opisach są generowane jako pola typu WS_XML_STRING. Wszystkie te ciągi są generowane jako część słownika stałej dla pliku. Lista ciągów i pola WS_XML_DICTIONARY (o nazwie dict w poniższym przykładzie) są generowane w ramach pola słownika struktury fileNameLocal.

struct { // fileNameLocal
...
  struct { // dictionary
    struct { // XML string list
      WS_XML_STRING firstFieldName;
      WS_XML_STRING firstFieldNS;
      ...
    } xmlStrings;
  WS_XML_DICTIONARY dict;
  } dictionary;
}; // fileNameLocal;

Tablica WS_XML_STRINGs jest generowana jako seria pól typu WS_XML_STRINGo nazwach przyjaznych dla użytkownika. Wygenerowany wycink używa przyjaznych dla użytkownika nazw w różnych opisach, aby uzyskać lepszą czytelność.

Serwer proxy klienta dla operacji WSDL

Wsutil.exe generuje serwer proxy klienta dla wszystkich operacji. Aplikacje mogą zastępować podpis metody przy użyciu opcji wiersza polecenia prefiksu.

HRESULT WINAPI bindingName_SimpleMethod(WS_SERVICE_PROXY *serviceProxy,
  WS_HEAP *heap,
  int a,
  int *b,
  int *c,
  const WS_CALL_PROPERTY* callProperties,
  ULONG callPropertyCount,
  const WS_ASYNC_CONTEXT * asyncContext,
  WS_ERROR * error )
{
  void* argList[] = {&a, &b, &c};
  return WsCall(_serviceProxy,
    (WS_OPERATION_DESCRIPTION*)&example_wsdlLocalDefinitions.contracts.DefaultBinding_ISimpleService.SimpleMethod.SimpleMethod,
    (void **)&_argList,
    callProperties,
    callPropertyCount,
    heap,
    asyncContext,
    error
  );      
}

Obiekt wywołujący operację musi przekazać prawidłowy parametr sterta. Parametry wyjściowe są przydzielane przy użyciu wartości WS_HEAP określonej w parametrze sterta. Funkcja wywołująca może zresetować lub zwolnić stertę, aby zwolnić pamięć dla wszystkich parametrów wyjściowych. Jeśli operacja nie powiedzie się, dodatkowe szczegółowe informacje o błędzie można pobrać z opcjonalnego obiektu błędu, jeśli jest dostępny.

Wsutil.exe generuje wycinkę usługi dla wszystkich operacji opisanych w powiązaniu.

HRESULT CALLBACK ISimpleService_SimpleMethodStub(
  const WS_OPERATION_CONTEXT *context,
  void * stackStruct,
  void * callback,
  const WS_ASYNC_CONTEXT * asyncContext,
  WS_ERROR *error )
{
  SimpleMethodParamStruct *pstack = (SimpleMethodParamStruct *) stackstruct;
  SimpleMethodOperation operation = (SimpleMethodOperation)callback;
  return operation(context, pstack->a, &(pstack->b), &(pstack->c ), asyncContext, error );
}

W powyższej sekcji opisano prototyp struktury lokalnej zawierającej tylko wszystkie definicje lokalne do pliku wycinkowego. W kolejnych sekcjach opisano definicje opisów.

Generowanie definicji WSDL

Wsutil.exe generuje stałą statyczną (const static) strukturę o nazwie *<file_name>*LocalDefinitions typu *<service_name>*Local, która zawiera wszystkie definicje tylko lokalne.

const static _SimpleServiceLocal example_wsdlLocalDefinitions =
{
  {  // global types
  ...
  }, // global types
  {  // global elements
  ...
  }, // global elements
  {  // messages
  ...
  }, //messages
  ...
  {  // dictionary
  ...
  }, // dictionary
},

Obsługiwane są następujące opisy WSDL:

  • wsdl:service
  • wsdl:binding
  • wsdl:portType
  • wsdl:operation
  • wsdl:message

Przetwarzanie pliku wsdl:operation i wsdl:message

Każda operacja określona w dokumencie WSDL jest mapowana na operację usługi przez Wsutil.exe. Narzędzie generuje oddzielne definicje operacji usługi zarówno dla serwera, jak i klienta.

<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://Example.org" 
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:xs="http://www.w3.org/2001/XMLSchema" 
xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" targetNamespace="http://Example.org" 
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
 <wsdl:portType name="ISimpleService">
  <wsdl:operation name="SimpleMethod">
   <wsdl:input wsaw:Action="http://Example.org/ISimpleService/SimpleMethod" 
   message="tns:ISimpleService_SimpleMethod_InputMessage" />
   <wsdl:output wsaw:Action="http://Example.org/ISimpleService/SimpleMethodResponse" 
   message="tns:ISimpleService_SimpleMethod_OutputMessage" />
  </wsdl:operation>
 </wsdl:portType>
 <wsdl:message name="ISimpleService_SimpleMethod_InputMessage">
  <wsdl:part name="parameters" element="tns:SimpleMethod" />
 </wsdl:message>
 <wsdl:message name="ISimpleService_SimpleMethod_OutputMessage">
  <wsdl:part name="parameters" element="tns:SimpleMethodResponse" />
 </wsdl:message>
</wsdl:definitions>

Układ elementów danych komunikatów wejściowych ioutput jest oceniany przez narzędzie w celu wygenerowania metadanych serializacji dla infrastruktury wraz z rzeczywistym podpisem wynikowej operacji usługi, z którą są skojarzone komunikaty wejściowe i wyjściowe.

Metadane dla każdej operacji w ramach określonej portType zawierają dane wejściowe i opcjonalnie komunikat wyjściowy, każdy z tych komunikatów jest mapowany na WS_MESSAGE_DESCRIPTION. W tym przykładzie dane wejściowe i komunikat wyjściowy operacji w porcieType zamapowany na inputMessageDescription i opcjonalnie outputMessageDescription odpowiednio na WS_OPERATION_DESCRIPTION.

Dla każdego komunikatu WSDL narzędzie generuje WS_MESSAGE_DESCRIPTION odwołujące się do definicji WS_ELEMENT_DESCRIPTION, jak pokazano poniżej:

... 
{    // message description for ISimpleService_SimpleMethod_InputMessage
  (WS_XML_STRING*)&example_wsdlLocalDefinitions.dictionary.xmlStrings.DefaultBinding_ISimpleServiceISimpleService_SimpleMethod_InputMessageactionName,
  (WS_ELEMENT_DESCRIPTION*)&(WS_ELEMENT_DESCRIPTION*)&example_wsdl.globalElements.SimpleMethodReponse
},  // message description for ISimpleService_SimpleMethod_InputMessage
...

Opis komunikatu odnosi się do opisu elementu wejściowego. Ponieważ element jest zdefiniowany globalnie, opis komunikatu odwołuje się do definicji globalnej zamiast lokalnego elementu statycznego. Podobnie jeśli element jest zdefiniowany w innym pliku, Wsutil.exe generuje odwołanie do struktury zdefiniowanej globalnie w tym pliku. Jeśli na przykład element SimpleMethodResponse jest zdefiniowany w innym pliku example.xsd, Wsutil.exe zamiast tego generuje następujące elementy:

...
{    // message description for ISimpleService_SimpleMethod_InputMessage
(WS_XML_STRING*)&example_wsdlLocalDefinitions.dictionary.xmlStrings.DefaultBinding_ISimpleServiceISimpleService_SimpleMethod_InputMessageactionName,
(WS_ELEMENT_DESCRIPTION*)&(WS_ELEMENT_DESCRIPTION*)&example_xsd.globalElements.SimpleMethodReponse
},  // message description for ISimpleService_SimpleMethod_InputMessage
...

Każdy opis komunikatu zawiera akcję i określony opis elementu (pole typu WS_ELEMENT_DESCRIPTION) dla wszystkich elementów danych komunikatu. W przypadku komunikatu w stylu RPC lub komunikatu z wieloma częściami element otoki jest tworzony w celu hermetyzacji dodatkowych informacji.

Obsługa stylu RPC

Wsutil.exe obsługuje operacje w stylu dokumentu oraz operacje w stylu RPC zgodnie ze specyfikacją WSDL 1.1 Binding Extension for SOAP 1.2. Operacje rPC i stylu literału są oznaczone jako WS_RPC_LITERAL_OPERATION. Model usługi ignoruje nazwę elementu otoki treści odpowiedzi w operacjach RPC/literału.

Wsutil.exe nie obsługuje natywnie operacji w stylu kodowania. Parametr WS_XML_BUFFER jest generowany dla komunikatów kodowania, a deweloperzy muszą bezpośrednio wypełnić nieprzezroczystym buforem.

Obsługa wielu części komunikatów

Wsutil.exe obsługuje wiele części komunikatów w jednym komunikacie. Komunikat wieloczęściowy można określić w następujący sposób:

<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://Example.org" 
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:xs="http://www.w3.org/2001/XMLSchema" 
xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" targetNamespace="http://Example.org" 
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
 <wsdl:message name="ISimpleService_MutipleParts_InputMessage">
  <wsdl:part name="part1" element="tns:SimpleElement1" />
  <wsdl:part name="part2" element="tns:SimpleElement2" />
 </wsdl:message>
</wsdl:definitions>

Wsutil.exe generuje pole WS_STRUCT_TYPE dla elementu komunikatu, jeśli komunikat zawiera wiele części. Jeśli komunikat jest reprezentowany przy użyciu stylu dokumentu, Wsutil.exe generuje element otoki z typem struktury. Element otoki nie ma nazwy ani określonej przestrzeni nazw, a struktura otoki zawiera wszystkie elementy we wszystkich częściach jako pola. Element otoki jest przeznaczony tylko do użytku wewnętrznego i nie będzie serializowany w treści komunikatu.

Jeśli komunikat używa reprezentacji stylu RPC lub literału , Wsutil.exe tworzy element otoki z nazwą operacji jako nazwą elementu i określoną przestrzenią nazw jako przestrzenią nazw usługi zgodnie ze specyfikacją rozszerzenia protokołu SOAP WSDL. Struktura elementu zawiera tablicę pól reprezentujących typy określone w częściach komunikatów. Element otoki jest mapowany na rzeczywisty górny element w treści komunikatu, jak wskazano w specyfikacji protokołu SOAP.

Po stronie serwera każda operacja powoduje definicję typu wynikowej operacji usługi serwera. Ta definicja typu służy do odwoływania się do operacji w tabeli funkcji zgodnie z wcześniejszym opisem. Każda operacja powoduje również generowanie funkcji wycinkowej, która nfrastruktura wywołuje w imieniu delegata do rzeczywistej metody.

typedef HRESULT (CALLBACK *SimpleMethodCallback) (
  const WS_OPERATION_CONTEXT* context,
  unsigned int  a,
  unsigned int * b,
  unsigned int * c,
  const WS_ASYNC_CONTEXT* asyncContext,
  WS_ERROR* error
  );

W przypadku operacji SimpleMethod definicja typu SimpleMethodOperation jest zdefiniowana powyżej. Należy pamiętać, że metoda wygenerowana ma rozszerzoną listę argumentów z częścią komunikatu dla komunikatu wejściowego i wyjściowego dla operacji SimpleMethod jako nazwanych parametrów.

Po stronie klienta każda operacja jest mapowana na operację usługi serwera proxy.

HRESULT WINAPI SimpleMethod (
  WS_SERVICE_PROXY* serviceProxy,
  ws_heap *heap,
  unsigned int  a,
  unsigned int * b,
  unsigned int * c,
  const WS_ASYNC_CONTEXT* asyncContext,
  WS_ERROR* error);

Przetwarzanie pliku wsdl:binding

Model usługi WWSAPI obsługuje rozszerzenie powiązania protokołu SOAP. Dla każdego powiązania istnieje skojarzony portType.

Transport określony w rozszerzeniu powiązania mydła jest tylko poradą. Aplikacja musi dostarczać informacje o transporcie podczas tworzenia kanału. Obecnie obsługujemy powiązania WS_HTTP_BINDING i WS_TCP_BINDING.

<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://Example.org" 
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:xs="http://www.w3.org/2001/XMLSchema" 
xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" targetNamespace="http://Example.org" 
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
 <wsdl:binding name="DefaultBinding_ISimpleService" type="tns:ISimpleService">
  <soap:binding transport="http://schemas.xmlsoap.org/soap/http" />
  <wsdl:operation name="SimpleMethod">
   <soap:operation soapAction="http://Example.org/ISimpleService/SimpleMethod" 
   style="document" />
   <wsdl:input>
    <soap:body use="literal" />
   </wsdl:input>
   <wsdl:output>
    <soap:body use="literal" />
   </wsdl:output>
  </wsdl:operation>
 </wsdl:binding>
</wsdl:definitions>

W naszym przykładowym dokumencie WSDL mamy tylko jeden portType dla usługi ISimpleService. Podane powiązanie protokołu SOAP wskazuje transport HTTP, który jest określony jako WS_HTTP_BINDING. Zauważ, że ta struktura nie ma statycznej dekoracji, ponieważ ta struktura musi być dostępna dla aplikacji.

Przetwarzanie pliku wsdl:portType

Każdy portType w języku WSDL składa się z co najmniej jednej operacji. Operacja powinna być zgodna z rozszerzeniem powiązania protokołu SOAP wskazanym w pliku wsdl:binding.

<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://Example.org" 
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:xs="http://www.w3.org/2001/XMLSchema" 
xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" targetNamespace="http://Example.org" 
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
 <wsdl:portType name="ISimpleService">
  <wsdl:operation name="SimpleMethod">
   ...
  </wsdl:operation>
 </wsdl:portType>
</wsdl:definitions>

W tym przykładzie usługa ISimpleService portType zawiera tylko operację SimpleMethod. Jest to zgodne z sekcją powiązania, w której istnieje tylko jedna operacja WSDL, która mapuje na akcję PROTOKOŁU SOAP.

Ponieważ usługa ISimpleService portType ma tylko jedną operację — SimpleMethod — odpowiadająca tabela funkcji zawiera tylko operację SimpleMethod jako usługa.

Pod względem metadanych każdy portType jest mapowany przez Wsutil.exe na WS_CONTRACT_DESCRIPTION. Każda operacja w portType jest mapowana na WS_OPERATION_DESCRIPTION.

W tym przykładzie portType narzędzie generuje WS_CONTRACT_DESCRIPTION dla usługi ISimpleService. Ten opis kontraktu zawiera określoną liczbę operacji dostępnych w usłudze ISimpleService portType wraz z tablicą WS_OPERATION_DESCRIPTION reprezentującą poszczególne operacje zdefiniowane na porcieType dla usługi ISimpleService. Ponieważ dla usługi ISimpleService istnieje tylko jedna operacja portType dla usługi ISimpleService, istnieje również tylko jedna definicja WS_OPERATION_DESCRIPTION.

...  part of LocalDefinitions structure
{    // array of operations for DefaultBinding_ISimpleService
(WS_OPERATION_DESCRIPTION*)&example_wsdlLocalDefinitions.contracts.DefaultBinding_ISimpleService.SimpleMethod.SimpleMethod,
},    // array of operations for DefaultBinding_ISimpleService
{    // contract description for DefaultBinding_ISimpleService
1,
(WS_OPERATION_DESCRIPTION**)example_wsdlLocalDefinitions.contracts.DefaultBinding_ISimpleService.operations,
WS_HTTP_CHANNEL_BINDING,
},  // end of contract description for DefaultBinding_ISimpleService
},    // DefaultBinding_ISimpleService       ...

Przetwarzanie pliku wsdl:service

WsUtil.exe używa usług do znajdowania powiązań/porttypów i generuje strukturę kontraktu, która opisuje typy, komunikaty, definicje porttypów itd. Opisy kontraktów są dostępne zewnętrznie i są generowane w ramach globalnej struktury definicji określonej za pomocą wygenerowanego nagłówka.

WsUtil.exe obsługuje rozszerzenia EndpointReference zdefiniowane w pliku wsdl:port. Odwołanie do punktu końcowego jest definiowane w WS-ADDRESSING jako sposób opisywania punktów końcowych informacji o usłudze. Tekst rozszerzenia odwołania do wejściowego punktu końcowego zapisany jako WS_XML_STRING, wraz z pasującymi WS_ENDPOINT_ADDRESS_DESCRIPTION są generowane w sekcji endpointReferences w strukturze globalnej.

<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://Example.org" 
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:xs="http://www.w3.org/2001/XMLSchema" 
xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" targetNamespace="http://Example.org" 
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
 <wsdl:service name="SimpleService">
  <wsdl:port name="ISimpleService" binding="tns:DefaultBinding_ISimpleService">
   <soap:address location="http://Example.org/ISimpleService" />
   <wsa:EndpointReference>
    <wsa:Address>http://example.org/wcfmetadata/WSHttpNon</wsa:Address>
   </wsa:EndpointReference> 
  </wsdl:port>
 </wsdl:service>
</wsdl:definitions>
  const _example_wsdl example_wsdl =
  {
  ... // global element description
  {// messages
  {    // message description for ISimpleService_SimpleMethod_InputMessage
  (WS_XML_STRING*)&example_wsdlLocalDefinitions.dictionary.xmlStrings.ISimpleService_SimpleMethod_InputMessageactionName,
  (WS_ELEMENT_DESCRIPTION*)&example_wsdl.globalElements.SimpleMethod,
},    // message description for ISimpleService_SimpleMethod_InputMessage
{    // message description for ISimpleService_SimpleMethod_OutputMessage
(WS_XML_STRING*)&example_wsdlLocalDefinitions.dictionary.xmlStrings.ISimpleService_SimpleMethod_OutputMessageactionName,
  (WS_ELEMENT_DESCRIPTION*)&example_wsdl.globalElements.SimpleMethodResponse,
},    // message description for ISimpleService_SimpleMethod_OutputMessage
}, // messages
{// contracts
{   // DefaultBinding_ISimpleService
1,
(WS_OPERATION_DESCRIPTION**)example_wsdlLocalDefinitions.contracts.DefaultBinding_ISimpleService.operations,
WS_HTTP_CHANNEL_BINDING,
},    // end of DefaultBinding_ISimpleService
    }, // contracts
    {
        {
            {   // endpointAddressDescription
                WS_ADDRESSING_VERSION_0_9,
            },                    
            (WS_XML_STRING*)&xml_string_generated_in_stub // endpointReferenceString
        }, //DefaultBinding_ISimpleService
    }, // endpointReferences
}

Aby utworzyć WS_ENDPOINT_ADDRESS przy użyciu metadanych wygenerowanych przez program WsUtil:

WsCreateReader      // Create a WS_XML_READER
Initialize a WS_XML_READER_BUFFER_INPUT
WsSetInput          // Set the encoding and input of the reader to generate endpointReferenceString
WsReadType        // Read WS_ENDPOINT_ADDRESS from the reader
    // Using WS_ELEMENT_TYPE_MAPPING, WS_ENDPOINT_ADDRESS_TYPE and generated endpointAddressDescription, 

Ciągi stałe na serwerze proxy klienta lub wycinku usługi są generowane jako pola typu WS_XML_STRING i istnieje stały słownik dla wszystkich ciągów w pliku proxy lub wycinku. Każdy ciąg w słowniku jest generowany jako pole w części słownika struktury lokalnej w celu zapewnienia lepszej czytelności.

... // dictionary part of LocalDefinitions structure
{    // xmlStrings
  { // xmlStrings
    WS_XML_STRING_DICTIONARY_VALUE("a",&example_wsdlLocalDefinitions.dictionary.dict, 0), 
    WS_XML_STRING_DICTIONARY_VALUE("http://Sapphire.org",&example_wsdlLocalDefinitions.dictionary.dict, 1), 
    WS_XML_STRING_DICTIONARY_VALUE("b",&example_wsdlLocalDefinitions.dictionary.dict, 2), 
    WS_XML_STRING_DICTIONARY_VALUE("SimpleMethod",&example_wsdlLocalDefinitions.dictionary.dict, 3),
    ...
  },  // end of xmlStrings
  {   // SimpleServicedictionary
    // 45026280-d5dc-4570-8195-4d66d13bfa34
    { 0x45026280, 0xd5dc, 0x4570, { 0x81, 0x95, 0x4d,0x66, 0xd1, 0x3b, 0xfa, 0x34 } },
    (WS_XML_STRING*)&example_wsdlLocalDefinitions.dictionary.xmlStrings,
    stringCount,
    TRUE,
  },
}
...

Przetwarzanie wsdl:type

Wsutil.exe obsługuje tylko dokumenty schematu XML (XSD) w specyfikacji wsdl:type. Jeden szczególny przypadek polega na tym, że port komunikatu określa definicję elementu globalnego. Więcej szczegółów dotyczących heurystyki używanych w tych przypadkach można znaleźć w poniższej sekcji.

Heurystyka przetwarzania parametrów

W modelu usługi komunikaty WSDL są mapowane na określone parametry w metodzie. Wsutil.exe ma dwa style generowania parametrów: w pierwszym stylu operacja ma jeden parametr komunikatu wejściowego i jeden parametr komunikatu wyjściowego (jeśli to konieczne); w drugim stylu Wsutil.exe używa heurystycznego do mapowania i rozwijania pól w strukturach zarówno dla komunikatów wejściowych, jak i komunikatów wyjściowych do różnych parametrów operacji. Zarówno komunikaty wejściowe, jak i wyjściowe muszą mieć elementy komunikatów typu struktury w celu wygenerowania tego drugiego podejścia.

Wsutil.exe używa następujących reguł podczas generowania parametrów operacji z komunikatów wejściowych i wyjściowych:

  • W przypadku komunikatów wejściowych i wyjściowych z wieloma częściami komunikatów każda część komunikatu jest oddzielnym parametrem w operacji z nazwą części komunikatu jako nazwą parametru.
  • W przypadku komunikatu stylu RPC z jedną częścią komunikatu część komunikatu jest parametrem operacji z nazwą części komunikatu jako nazwą parametru.
  • W przypadku komunikatów wejściowych i wyjściowych w stylu dokumentu z jedną częścią komunikatu:
    • Jeśli nazwa części komunikatu to "parametry", a typ elementu jest strukturą, każde pole w strukturze jest traktowane jako oddzielny parametr o nazwie pola będącej nazwą parametru.
    • Jeśli nazwa części komunikatu nie jest "parameters", komunikat jest parametrem operacji z nazwą komunikatu używaną jako odpowiadającą nazwę parametru.
  • W przypadku danych wejściowych i wyjściowych w stylu dokumentu z elementem nillable komunikat jest mapowany na jeden parametr z nazwą części komunikatu jako nazwą parametru. Dodawany jest jeden dodatkowy poziom pośredni, aby wskazać, że wskaźnik może być wartości NULL.
  • Jeśli pole pojawi się tylko w elemecie komunikatu wejściowego, pole jest traktowane jako parametr [in].
  • Jeśli pole pojawi się tylko w elemecie komunikatu wyjściowego, pole jest traktowane jako parametr [out].
  • Jeśli istnieje pole o tej samej nazwie i tym samym typie, które pojawia się zarówno w komunikacie wejściowym, jak i w komunikacie wyjściowym, pole jest traktowane jako parametr [in,out].

Następujące narzędzia służą do określania kierunku parametrów:

  • Jeśli pole jest wyświetlane tylko w elemecie komunikatu wejściowego, pole jest traktowane jako tylko w parametrze.
  • Jeśli pole pojawi się tylko w elemecie komunikatu wyjściowego, pole jest traktowane jako tylko parametr out.
  • Jeśli istnieje pole o tej samej nazwie i tym samym typie, które pojawia się zarówno w komunikacie wejściowym, jak i wyjściowym, pole jest traktowane jako parametr in,out.

Wsutil.exe obsługuje tylko sekwencjonowane elementy. Odrzuca nieprawidłowe kolejność w odniesieniu do parametrów [in,out], jeśli Wsutil.exe nie może połączyć parametrów w parametrach i na liście pojedynczych parametrów. Sufiksy mogą być dodawane do nazw parametrów, aby uniknąć kolizji nazw.

<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://Example.org" 
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:xs="http://www.w3.org/2001/XMLSchema" 
xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" targetNamespace="http://Example.org" 
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
 <wsdl:message name="ISimpleService_SimpleMethod_InputMessage">
  <wsdl:part name="parameters" element="tns:SimpleMethod" />
 </wsdl:message>
 <wsdl:message name="ISimpleService_SimpleMethod_OutputMessage">
  <wsdl:part name="parameters" element="tns:SimpleMethodResponse" />
 </wsdl:message>
</wsdl:definitions>

Wsutil.exe uwzględnia pola w parametrach tns:SimpleMethod i tns:SimpleMethodResponse ato jako parametry, jak pokazano w poniższych definicjach parametrów:

<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://Example.org" 
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:xs="http://www.w3.org/2001/XMLSchema" 
xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" targetNamespace="http://Example.org" 
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
 <wsdl:types>
  <xs:schema xmlns:tns="http://Example.org" elementFormDefault="qualified" 
  targetNamespace="http://Example.org" xmlns:xs="http://www.w3.org/2001/XMLSchema">
   <xs:import namespace="http://Example.org" />
   <xs:element name="SimpleMethod">
    <xs:complexType>
     <xs:sequence>
      <xs:element name="a" type="xs:unsignedInt" />
      <xs:element name="b" type="xs:unsignedInt" />
     </xs:sequence>
    </xs:complexType>
   </xs:element>
   <xs:element name="SimpleMethodResponse">
    <xs:complexType>
     <xs:sequence>
      <xs:element name="b" type="xs:unsignedInt" />
      <xs:element name="c" type="xs:unsignedInt" />
     </xs:sequence>
    </xs:complexType>
   </xs:element>
  </xs:schema>
 </wsdl:types>
</wsdl:definitions>

Wsutil.exe rozwija listę parametrów z pól na powyższej liście i generuje strukturę ParamStruct w poniższym przykładzie kodu. Model usługi w czasie wykonywania może używać tej struktury do przekazywania argumentów do wycinków klienta i serwera.

typedef struct SimpleMethodParamStruct {
  unsigned int   a;  
  unsigned int   b;
  unsigned int   c;
} ;

Ta struktura służy tylko do opisywania ramki stosu po stronie klienta i serwera. Nie ma żadnych zmian w opisie komunikatu ani opisach elementów, do których odwołuje się opis wiadomości.

  // following are local definitions for the complex type
  { // field description for a
  WS_ELEMENT_FIELD_MAPPING,
  (WS_XML_STRING*)&example_wsdlLocalDefinitions.dictionary.xmlStrings.aLocalName,
(WS_XML_STRING*)&example_wsdlLocalDefinitions.dictionary.xmlStrings.aNamespace,
  WS_INT32_TYPE,
  0,
  WsOffsetOf(_SimpleMethod, a),
  0,
  0,
  },    // end of field description for a
  { // field description for b
  WS_ELEMENT_FIELD_MAPPING,
  (WS_XML_STRING*)&example_wsdlLocalDefinitions.dictionary.xmlStrings.bLocalName,
(WS_XML_STRING*)&example_wsdlLocalDefinitions.dictionary.xmlStrings.aNamespace,
  WS_INT32_TYPE,
  0,
  WsOffsetOf(_SimpleMethod, b),
  0,
  0,
  },    // end of field description for b
  {    // fields description for _SimpleMethod
  (WS_FIELD_DESCRIPTION *)&example_wsdlLocalDefinitions.globalElements.SimpleMethod._SimpleMethoddescs.a,
  (WS_FIELD_DESCRIPTION *)&example_wsdlLocalDefinitions.globalElements.SimpleMethod._SimpleMethoddescs.b,
  },
  {  // structure definition
  sizeof(_SimpleMethod),
  __alignof(_SimpleMethod),
  (WS_FIELD_DESCRIPTION**)&example_wsdlLocalDefinitions.globalElements.SimpleMethod._SimpleMethoddescs._SimpleMethodFields,
  WsCountOf(example_wsdlLocalDefinitions.globalElements.SimpleMethod._SimpleMethoddescs._SimpleMethodFields),
  (WS_XML_STRING*)&example_wsdlLocalDefinitions.dictionary.xmlStrings._SimpleMethodTypeName,
(WS_XML_STRING*)&example_wsdlLocalDefinitions.dictionary.xmlStrings.aNamespace,
  0,
  },   // struct description for _SimpleMethod
  // following are global definitions for the out parameter
  ...
  {  // element description
  (WS_XML_STRING*)&example_wsdlLocalDefinitions.dictionary.xmlStrings._SimpleMethodTypeName,
  (WS_XML_STRING*)&example_wsdlLocalDefinitions.dictionary.xmlStrings.aNamespace,
  WS_STRUCT_TYPE,
  (void *)&example_wsdlLocalDefinitions.globalElements.SimpleMethod._SimpleMethoddescs.structDesc,
  },
  {    // message description for ISimpleService_SimpleMethod_InputMessage
  (WS_XML_STRING*)&example_wsdlLocalDefinitions.dictionary.xmlStrings.ISimpleService_SimpleMethod_InputMessageactionName,
(WS_ELEMENT_DESCRIPTION*)&example_wsdl.globalElements.SimpleMethod,
  },    // message description for ISimpleService_SimpleMethod_InputMessage

Ogólnie rzecz biorąc, jeden poziom pośredni jest dodawany dla wszystkich parametrów [out] i [in,out].

Operacja bez parametrów

W przypadku operacji dokumentu i literału Wsutil.exe traktuje operację jako parametr wejściowy i jeden parametr wyjściowy, jeśli:

  • Komunikat wejściowy lub wyjściowy ma więcej niż jedną część.
  • Istnieje tylko jedna część komunikatu, a nazwa części komunikatu nie jest "parameters".

.. W powyższym przykładzie przy założeniu, że części komunikatów mają nazwę ParamIn" i ParamOut, sygnatura metody staje się następującym kodem:

typedef struct SimpleMethod{
unsigned int a;
unsigned int b;
};

typedef struct SimpleMethodResponse {
unsigned int b;
unsigned int c;
};

typedef  struct ISimpleService_SimpleMethodParamStruct
{
SimpleMethod  * SimpleMethod;
SimpleMethodResponse  * SimpleMethodResponse;
} ISimpleService_SimpleMethodParamStruct;

Wsutil.exe generuje sygnaturę wersji dla opisu operacji, tak aby aparat modelu usług WsCall i po stronie serwera mógł sprawdzić, czy wygenerowany opis ma zastosowanie dla bieżącej platformy.

Te informacje o wersji są generowane w ramach struktury WS_OPERATION_DESCRIPTION. Numer wersji może być traktowany jako selektor ramienia unii, aby rozszerzać strukturę. Obecnie versionID jest ustawiona na 1 bez kolejnych pól. W przyszłości versiosn może zwiększać numer wersji i uwzględniać więcej pól zgodnie z potrzebami. Na przykład Wsutil.exe obecnie generuje następujący kod na podstawie identyfikatora wersji:

{ // SimpleMethod
{ // parameter descriptions for SimpleMethod
{ WS_PARAMETER_TYPE_NORMAL, (USHORT)0, (USHORT)-1 },
{ WS_PARAMETER_TYPE_NORMAL, (USHORT)1, (USHORT)-1 },
{ WS_PARAMETER_TYPE_NORMAL, (USHORT)-1, (USHORT)1 },
},    // parameter descriptions for SimpleMethod
{    // operation description for SimpleMethod
1,
(WS_MESSAGE_DESCRIPTION*)&example_wsdl.messages.ISimpleService_SimpleMethod_InputMessage,
(WS_MESSAGE_DESCRIPTION*)&example_wsdl.messages.ISimpleService_SimpleMethod_OutputMessage,
3,
(WS_PARAMETER_DESCRIPTION*)example_wsdlLocalDefinitions.contracts.DefaultBinding_ISimpleService.SimpleMethod.params,
SimpleMethodOperationStub
}, //operation description for SimpleMethod
},  // SimpleMethod

W przyszłości można ją rozszerzyć w następujący sposób:

WS_OPERATION_DESCRIPTION simpleMethodOperationDesc =
{
  2,
  &ISimpleService_SimpleMethod_InputputMessageDesc,
  &ISimpleService_SimpleMethod_OutputMessageDesc,
  WsCountOf(SimpleMethodParameters),
  SimpleMethodParameters,
  ISimpleService_SimpleMethod_Stub,
  &forwardToString;   // just as an example.
};

Bezpieczeństwo

Zobacz sekcję zabezpieczeń w temacie narzędzia kompilatora Wsutil.