Este artículo proviene de un motor de traducción automática.
Windows con C++
Servicios web de Windows
Kenny Kerr
Descargar el ejemplo de código
Una de las principales razones que muchos desarrolladores flocked a Microsoft .NET Framework y Java para menor grado, fue el hecho de que realizan mucho más fácil de escribir software para Internet. Si estuviera escribiendo una HTTP aplicación de cliente o servidor, .NET Framework tenía cubierto con clases para realizar solicitudes HTTP y procesar XML fácilmente. Incluso podría generar a clientes SOAP desde los documentos WSDL y implementar servidores SOAP con ASP.NET. Como los estándares alrededor de servicios Web madurados, Microsoft desarrolló Windows Communications Foundation (WCF), también se basa en el .NET Framework, para que sea más fácil utilizar los estándares Web cada vez más complejos para controlar diferentes transportes, como TCP y UDP y proporcionar más versátiles de las opciones de seguridad.
Sin embargo, los desarrolladores de C++, se dejaron preguntando si era incluso práctico utilizar C++ para escribir aplicaciones Web. Microsoft tenía proporcionado un par de soluciones temporales en el formulario de clases ATL y un Toolkit basadas en COM, pero al final de que éstas no se pudieron mantener el progreso que había realizado las pilas SOAP administradas y, por lo tanto, en gran medida se han abandonado.
A pesar de foco aparentemente single-minded en .NET Framework, los desarrolladores de Microsoft no han olvidado acerca el desarrollador de C++. De hecho, muchos de ellos son todavía y seguirán estando apasionados los desarrolladores de C++. Como resultado, las soluciones que ayudan a los desarrolladores de C++ son una parte clave en la estrategia de Microsoft para la plataforma Windows. Por supuesto, muchas de las API destinadas a los desarrolladores de C++ también acaban asistencia muchos de los marcos de trabajo administrados.
Aunque hay demasiadas para enumerar aquí, unos merece la pena mencionar. Los servicios HTTP de Windows (WinHTTP) API proporciona una solución eficaz y flexible para escribir clientes HTTP. Puede leer más acerca de WinHTTP en mi columna de agosto de 2008. El servidor HTTP (HTTP.sys) API proporciona los fundamentos para la creación de servidores de alto rendimiento HTTP sin depender de un servidor Web completo como servicios de Internet Information Server (IIS). De hecho, el propio IIS se basa en esta misma API. Y, por supuesto la API de XmlLite ofrece un analizador XML pequeño y rápido para código nativo. Puede leer más acerca de XmlLite en mi artículo de la característica de abril de 2007.
Dado todo esto, es aún bastante una tarea desalentadora para escribir un cliente SOAP o servidor. Aunque SOAP iniciado desactivar “ simple ” (que es lo que significa la “ S ”), no permanezca así de ese modo durante mucho tiempo. WinHTTP, HTTP.sys y XmlLite pueden obtendrá un largo camino controlando el transporte HTTP y analizar el XML, pero todavía hay una tonelada de código para que escriba para controlar la capa de comunicaciones: cosas como formato e interpretar los encabezados SOAP, no para mencionar auxiliares otros transportes como TCP o UDP. Incluso si algún modo, se puede administrar todo esto, todavía está dejó con sobres SOAP en lugar de ser capaz de tratar las operaciones lógicas de SOAP como llamadas a funciones de análisis.
Bien, estos problemas son un cosa al pasado. Con la presentación de la API de los Servicios web de Windows (WWS) API, los desarrolladores de C++ ya no se consideran como ciudadanos de segunda clase en el mundo de los servicios web. WWS está diseñada desde cero hasta ser una implementación de código nativo completamente de SOAP, incluida la compatibilidad con muchos de WS-* protocolos. WWS, estrictamente hablando, expuesto a través de una API de C, que hace la interoperabilidad con otros lenguajes y tiempos de ejecución muy sencillo, pero es el programador de C++ que probablemente se beneficiará más. De hecho, con un poco de Ayuda de C++, puede ser una alegría real para utilizar, como se deben ver en este artículo.
Arquitectura y principios
WWS incluye todo lo que no son bibliotecas basadas en .NET Framework. Está diseñado para código nativo. Está diseñado para introducir a un número mínimo de dependencias. Está diseñado para utilizar como poca memoria como sea posible. Y está diseñado para ser rápido. Realmente rápida. El equipo responsable de desarrollar WWS ejecuta pruebas de rendimiento en cada nueva versión, comparación con WCF y RPC. RPC se utiliza como una ordenación de línea de base, ya que nada podría ser más rápido, pero proporciona un modo confiable de regresiones de velocidad de seguimiento. Sin embargo, lo es, ilumina cuando se comparan WCF y WWS. Figura 1 muestra una comparación del conjunto de trabajo para un cliente con WCF y WWS respectivamente. Que es un margen bastante drástico, pero quizás no que sorprendente cuando piensa que .NET Framework está implicada. Figura 2, sin embargo, debería ser sorprendente si, al igual que muchos otros, considera WCF para ser el de estado de arte. Muestra el rendimiento de operaciones por segundo para un servidor con WCF y WWS respectivamente. WWS es más de dos veces tan rápido! No me malinterpreten: No hay nada malo con WCF o .NET Framework, pero cuando necesite algo pequeño y rápido, es difícil batir C++ y código nativo. Pero sabe ya!
Figura 1 comparar el trabajo de cliente (inferior es mejor)
El motor en tiempo de ejecución WWS se empaqueta en WebServices.dll, que se incluye con Windows 7 y Windows Server 2008 R2. También está disponible como una actualización del sistema para Windows XP y posterior. Las funciones exportadas de WebServices.dll representan la API de WWS y puede tener acceso a ellos mediante la vinculación a WebServices.lib y incluido el archivo de encabezado WebServices.h desde el Windows SDK. Hasta ahora, todo perfecto. Pero ¿qué la API aspecto? Bueno, a diferencia de la API de estilo COM como el de XmlLite o Direct2D, esta API de C requiere imagine un conjunto de objetos que viven en segundo plano y están esperando para dividir y capas lógicas. Let’s primero eche un vistazo lo en términos de capas. Figura 3 ilustra las capas de funcionalidad expuesta por la API WWS, con cada capa de creación de la uno debajo de él. Cada capa se representa mediante un número de funciones y las estructuras y proporciona un conjunto de abstracciones. Como puede imaginar, puede hacer que la aplicación utilizar cualquiera de las capas, pero la mayoría de los casos deseará cíñase con el modelo de servicio que proporciona el modelo de programación más simple y oculta muchos de los detalles para usted. La capa de transportes es simplemente un aviso que debajo de él existe todo será algunos protocolo de red. WWS utilizará WinHTTP, HTTP.sys o Winsock, dependiendo de si se utiliza para implementar un cliente o servidor y el transporte seleccionado.
Figura 2 Comparar rendimiento Server (posterior es mejor)
Figura 3 de Layered API
Como sugiere su nombre, la capa del modelo de servicio totalmente abstrae los intercambios de mensajes SOAP y modela las operaciones lógicas de servicio Web como llamadas de función. No, sin embargo, independiente, pero se basa en el uso de una herramienta de línea de comandos denominada Wsutil.exe desde el Windows SDK. Dado un archivo WSDL, esta herramienta generará un archivo de encabezado, así como un archivo de código fuente de C con la mayor parte del código necesario para ambos conectarse a un servicio Web de la descripción proporcionada y para implementar como un servicio Web, teniendo cuidado para garantizar el enlace del canal está configurado correctamente y mensajes son el formato correcto. Esto es con diferencia el enfoque más sencillo y proporciona un modelo de programación que es muy parecido a lo que podría esperar de RPC tradicional.
La capa de canal, por otro lado, expone los mensajes envían y reciben en un transporte concreto, pero todavía opcionalmente protege de tener que realmente formatear los mensajes. Aquí la ventaja es que están aislados del transporte concreto y codificación que se utiliza. La capa de canal es donde controlar información de enlace y puede proteger la comunicación para autenticación o privacidad.
La capa XML expone para el formato de mensajes y la serialización de datos. Tiene acceso completo al contenido de mensajes, pero son apantallados desde la codificación concreta si se está comunicando con texto, binario o MTOM. Quizás se sorprenda para oír que WWS tiene su propio analizador XML. ¿Por qué no simplemente utiliza XmlLite? Aunque XmlLite es ciertamente ligera y muy rápido, no es bastante encajan perfectamente en una serie de razones. La razón más obvia es que debe admitir codificaciones diferentes mientras XmlLite sólo admite texto WWS. Los mensajes SOAP también normalmente se codifican mediante UTF-8, mientras que XmlLite expone todas las propiedades con cadenas Unicode y esto introduce costo innecesario al copiar valores. WWS también tiene objetivos de consumo de memoria muy estricto (no hay realmente una API para esto, como veremos más adelante) que no se puede cumplir con XmlLite. Al final, el equipo de WWS fue capaz de implementar un analizador personalizado específicamente para SOAP, que es considerablemente más rápido que XmlLite. Tenga en cuenta que el Analizador WWS no pretende reemplazar XmlLite. Como un analizador XML de propósito general, es difícil batir, pero la capa de WWS XML proporciona a los desarrolladores con características muy específicas dirigidas a serializar los datos eficazmente dentro y fuera de un mensaje SOAP mediante el subconjunto de XML requerida por SOAP.
Aparte de las funciones y las estructuras de datos que lógicamente pertenecen a estas tres capas, la API de WWS proporciona un número de instalaciones que son comunes a todas las capas, incluyendo el control de errores, finalización asincrónica, cancelación, administración de memoria y más. Ya dispone de espacio limitado y desea ayudarle comenzar rápidamente, voy a limitar el resto de este artículo para el uso del modelo de servicio para la creación de un cliente de servicios Web y servidor. En un próximo artículo, pondré profundizar más profundamente en las otras partes de WWS.
Introducción
Para empezar, usaré la definición del servicio Web mínimo de de figura 4. Este documento WSDL define tipos, los mensajes, operaciones, extremos y los enlaces de canal del servicio. Lo primero que hay que hacer es ejecutarlo a través de Wsutil.exe como sigue:
Wsutil.exe Calculator.wsdl
Esto producirá un archivo de encabezado denominado Calculator.wsdl.h y un archivo de código fuente de C denominado Calculator.wsdl.c.
Figura 4 de definición del servicio Web
<wsdl:definitions xmlns:wsdl="https://schemas.xmlsoap.org/wsdl/"
xmlns:soap="https://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xsd="ttp://www.w3.org/2001/XMLSchema"
xmlns:tns="http://calculator.example.org/"
targetNamespace="http://calculator.example.org/">
<wsdl:types>
<xsd:schema elementFormDefault="qualified"
targetNamespace="http://calculator.example.org/">
<xsd:element name="AddRequest">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="first" type="xsd:double" />
<xsd:element name="second" type="xsd:double" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="AddResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="result" type="xsd:double" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
</wsdl:types>
<wsdl:message name="AddRequestMessage">
<wsdl:part name="parameters" element="tns:AddRequest" />
</wsdl:message>
<wsdl:message name="AddResponseMessage">
<wsdl:part name="parameters" element="tns:AddResponse" />
</wsdl:message>
<wsdl:portType name="CalculatorPort">
<wsdl:operation name="Add">
<wsdl:input message="tns:AddRequestMessage" />
<wsdl:output message="tns:AddResponseMessage" />
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="CalculatorBinding" type="tns:CalculatorPort">
<soap:binding transport="https://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="Add">
<soap:operation soapAction=
"http://calculator.example.org/Add" 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="CalculatorService">
<wsdl:port name="CalculatorPort" binding="tns:CalculatorBinding">
<soap:address location="http://localhost:81/calculator"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
Echamos un vistazo a lo que se generó, necesitamos obtener algún lugar de trabajo hecho, independientemente de si está implementando el cliente o el servidor. Lo primero que necesitará es una forma de expresar la información de error. La API de WWS expone valiosa información de errores tanto para sus propias funciones, así como los errores de SOAP a través de un objeto error. Este objeto que se va a una API C, está representado por un identificador opaco y un conjunto de funciones. En este caso, WS_ERROR * representa un identificador a un objeto error y WsCreateError es la función que lo crea. El objeto se libera llamando a la función WsFreeError. Puede almacenar un número de cadenas con diferentes niveles de información sobre un error en el objeto de error. Para recuperar estos, deberá determinar primero cuántos cadenas están presentes. Esto se hace llamando a la función WsGetErrorProperty, asignándole el identificador para el objeto de error y especificando la constante WS_ERROR_PROPERTY_STRING_COUNT. Armado con esta información, se llama a la función WsGetErrorString, asignándole el identificador para el objeto de error, así como el índice de base cero de la cadena que se va a recuperar. También puede utilizar las funciones de API para rellenar sus propios objetos de error. Naturalmente, un poco C++ irá un largo camino para que esto hace más sencillo y más confiable. Figura 5 proporciona un contenedor de objeto de error simple. Puede enumerar fácilmente las cadenas en un objeto error, como se muestra en la figura 6 de.
Figura 5 de contenedor de objetos de error
class WsError
{
WS_ERROR* m_h;
public:
WsError* m_h(0)
{}
~WsError()
{
if (0 != m_h)
}
HRESULT Create(const WS_ERROR_PROPERTY* properties,
ULONG propertyCount)
{
return WsCreateError(properties, propertyCount, &m_h);
}
HRESULT GetProperty(WS_ERROR_PROPERTY_ID id, void* buffer,
ULONG bufferSize)
{
return WsGetErrorProperty(m_h, id, buffer, bufferSize);
}
template <typename T>
HRESULT GetProperty(WS_ERROR_PROPERTY_ID id, out T* buffer)
{
return GetProperty(id, buffer, sizeof(T));
}
HRESULT GetString(ULONG index, WS_STRING* string)
{
return WsGetErrorString(m_h, index, string);
}
operator WS_ERROR*() const
{
return m_h;
}
};
Figura 6 de enumerar las cadenas en un objeto Error
WsError error;
HR(error.Create(0, 0));
// Something goes wrong . . .
ULONG stringCount = 0;
HR(error.GetProperty(WS_ERROR_PROPERTY_STRING_COUNT,&stringCount));
for (ULONG i = 0; i < stringCount; ++i)
{
WS_STRING string;
HR(error.GetString(i, &string));
wprintf(L"Error %d: %.*s\n", i, string.length, string.chars);
}
Lo siguiente que necesitaremos es un objeto del montón. El objeto del montón proporciona un control preciso sobre la asignación de memoria al generar o consumir mensajes y cuando la necesidad de asignar varias otras estructuras de API. También simplifica el modelo de programación ya que no hay necesidad de saber con exactitud la cantidad de memoria se requiere para cualquier función determinada se realice correctamente. Muchas funciones más antiguas en el Windows SDK serán, por ejemplo, requieren que adivinar cuánto espacio de almacenamiento es necesaria o para llamar primero a una función de una manera determinada para determinar cuánta memoria debe asignar para que la función tenga éxito. El uso del objeto del montón WWS quita este código adicional y proporciona una forma agradable para controlar el uso de memoria de la API. Esto también resulta útil desde una perspectiva de seguridad donde puede que desee especificar límites esperados en cuánto puede asignar la API. WS_HEAP * representa un identificador para un objeto del montón y WsCreateHeap es la función que lo crea. El objeto se libera llamando a la función WsFreeHeap. Una vez creado, puede asignar memoria desde el montón mediante la función WsAlloc, pero para este artículo va simplemente pasamos el identificador para el objeto del montón a otras funciones de API para su uso como sea necesario.
Figura 7 proporciona un contenedor de objeto del montón simple. Dado esto, puede crear un objeto del montón limitado a 250 bytes como sigue:
WsHeap heap;
HR(heap.Create(250, // max size
0, // trim size
0, // properties
0, // property count
error));
Observe cómo estoy pasando el objeto de error al método Create del objeto del montón. Debe nada equivocarse al crear el objeto del montón, podré interrogar el objeto error para averiguar la causa.
Figura 7 de contenedor de objetos de montón
class WsError
{
WS_ERROR* m_h;
public:
WsError* m_h(0)
{}
~WsError()
{
if (0 != m_h)
}
HRESULT Create(const WS_ERROR_PROPERTY* properties,
ULONG propertyCount)
{
return WsCreateError(properties, propertyCount, &m_h);
}
HRESULT GetProperty(WS_ERROR_PROPERTY_ID id, void* buffer,
ULONG bufferSize)
{
return WsGetErrorProperty(m_h, id, buffer, bufferSize);
}
template <typename T>
HRESULT GetProperty(WS_ERROR_PROPERTY_ID id, out T* buffer)
{
return GetProperty(id, buffer, sizeof(T));
}
HRESULT GetString(ULONG index, WS_STRING* string)
{
return WsGetErrorString(m_h, index, string);
}
operator WS_ERROR*() const
{
return m_h;
}
};
class WsHeap
{
WS_HEAP* m_h;
public:
WsHeap() : m_h(0)
{}
~WsHeap()
{
if (0 != m_h) WsFreeHeap(m_h);
}
HRESULT Create(SIZE_T maxSize, SIZE_T trimSize,
const WS_HEAP_PROPERTY* properties,
ULONG propertyCount,
in_opt WS_ERROR* error)
{
return WsCreateHeap(maxSize, trimSize, properties, propertyCount,
&m_h, error);
}
operator WS_HEAP*() const
{
return m_h;
}
};
El cliente
El cliente del modelo de servicio se centra en el objeto de proxy de servicio. El código fuente generado incluye una función denominada CalculatorBinding_CreateServiceProxy. El nombre se deriva de el del extremo o nombre de enlace definido en el documento WSDL. Esta función crea un objeto de proxy de servicio y devuelve un que representa un identificador opaco a ese objeto WS_SERVICE_PROXY *. El objeto se libera llamando a la función WsFreeServiceProxy. Una vez creado, la aplicación puede abrir el extremo de servicio mediante la función WsOpenServiceProxy y a continuación, hacer llamadas a través de proxy del servicio al servicio Web. Lo que hace exactamente WsOpenServiceProxy depende de en el transporte que se está utilizando. También debe tener cuidado para cerrar al proxy de servicio antes para liberar el objeto mediante la función WsCloseServiceProxy. Naturalmente, todo este mantenimiento puede perfectamente ajustarse hacia arriba en una clase simple proporcionada en de figura 8. Dado esto, puede crear y abrir al proxy de servicio, como se muestra en de figura 9.
Figura 8 de contenedor proxy de servicio
class WsServiceProxy
{
WS_SERVICE_PROXY* m_h;
public:
WsServiceProxy() : m_h(0)
{}
~WsServiceProxy()
{
if (0 != m_h)
{
Close(0, 0); // error
WsFreeServiceProxy(m_h);
}
}
HRESULT Open(const WS_ENDPOINT_ADDRESS* address,
const WS_ASYNC_CONTEXT* asyncContext,
WS_ERROR* error)
{
return WsOpenServiceProxy(m_h, address, asyncContext, error);
}
HRESULT Close(const WS_ASYNC_CONTEXT* asyncContext,
WS_ERROR* error)
{
return WsCloseServiceProxy(m_h, asyncContext, error);
}
WS_SERVICE_PROXY** operator&()
{
return &m_h;
}
operator WS_SERVICE_PROXY*() const
{
return m_h;
}
};
Figura 9 de crear y abrir el proxy de servicio
WsServiceProxy serviceProxy;
HR(CalculatorBinding_CreateServiceProxy(0, // template value
0, // properties
0, // property count
&serviceProxy,
error));
WS_ENDPOINT_ADDRESS address =
{
{
static_cast<ULONG>(wcslen(url)),
const_cast<PWSTR>(url)
}
};
HR(serviceProxy.Open(&address,
0, // async context
error));
Se utiliza la estructura WS_ENDPOINT_ADDRESS para tratar los mensajes que se envían. Se suele utilizar esta estructura al programar en el nivel de canal. En este caso, nos rellenar sólo la parte de URL y el proxy de servicio se encarga del resto.
En este punto, podemos utilizar otra función generada CalculatorBinding_Add es decir, que representa la operación Add del servicio Web de unsurprisingly. Realmente no obtener mucho más fácil que esto:
const double first = 1.23;
const double second = 2.34;
double result = 0.0;
HR(CalculatorBinding_Add(serviceProxy,
first,
second,
&result,
heap,
0, // properties
0, // property count
0, // async context
error));
ASSERT(3.57 == result);
Una vez haya terminado de interactuar con el servicio Web sólo necesita cerrar el canal de comunicación del proxy de servicio:
HR(serviceProxy.Close(0, // async context
error));
El servidor
Mientras el modelo de programación de cliente se centra en el proxy de servicio, el servidor crea y administra un host de servicio, que proporciona el motor en tiempo de ejecución necesario para escuchar en los diversos extremos según la información del canal especificadas en su lugar. De nuevo, porque estamos utilizando el modelo de servicio, la mayoría de los detalles se abstrae lejos y nos estamos izquierdas sólo a crear el extremo de servicio y host. WWS hará el resto.
El primer paso es crear el extremo de servicio. El modelo de servicio se ocupa de esto en el formulario de otra función generada, concretamente CalculatorBinding_CreateServiceEndpoint, como de figura 10 muestra. Crear el extremo requiere especificar la dirección en el que el extremo se va a escuchar. Esto es proporcionado por el WS_STRING terminada estructura, que es una cadena Unicode de longitud fija y no es necesario que sea null. Puesto que el extremo es responsable del cumplimiento de las solicitudes, debe proporcionar una tabla de punteros de función para las operaciones expuestas por el servicio de asignación. Se utiliza la estructura de CalculatorBindingFunctionTable generada para este propósito. Por último, el propio extremo está representado por la estructura WS_SERVICE_ENDPOINT y se asigna en el montón proporcionado.
Figura 10 de CalculatorBinding_CreateServiceEndpoint
class WsServiceHost
{
WS_SERVICE_HOST* m_h;
public:
WsServiceHost() : m_h(0)
{}
~WsServiceHost()
{
if (0 != m_h)
{
Close(0, 0);
WsFreeServiceHost(m_h);
}
}
HRESULT Create(const WS_SERVICE_ENDPOINT** endpoints,
const USHORT endpointCount,
const WS_SERVICE_PROPERTY* properties,
ULONG propertyCount, WS_ERROR* error)
{
return WsCreateServiceHost(endpoints, endpointCount, properties,
propertyCount, &m_h, error);
}
HRESULT Open(const WS_ASYNC_CONTEXT* asyncContext, WS_ERROR* error)
{
return WsOpenServiceHost(m_h, asyncContext, error);
}
HRESULT Close(const WS_ASYNC_CONTEXT* asyncContext, WS_ERROR* error)
{
return WsCloseServiceHost(m_h, asyncContext, error);
}
operator WS_SERVICE_HOST*() const
{
return m_h;
}
};
WsServiceProxy serviceProxy;
const WS_STRING address =
{
static_cast<ULONG>(wcslen(url)),
const_cast<PWSTR>(url)
};
CalculatorBindingFunctionTable functions =
{
AddCallback
};
WS_SERVICE_ENDPOINT* endpoint = 0;
HR(CalculatorBinding_CreateServiceEndpoint(0, // template value
&address,
&functions,
0, // authz callback
0, // properties
0, // property count
heap,
&endpoint,
error));
El siguiente paso es crear el host de servicio. WS_SERVICE_HOST * representa un identificador para un objeto de host de servicio y WsCreateServiceHost es la función que lo crea. El objeto se libera llamando a la función WsFreeServiceHost. La función WsCreateServiceHost crea el objeto de host de servicio dado una lista de extremos. En este momento, puede iniciar los agentes de escucha en todos los extremos mediante la función WsOpenServiceHost. Detener la comunicación mediante la función WsCloseServiceHost. Como con el proxy de servicio, asegúrese de cerrar el host de servicio prior to liberarlo. De nuevo, todo este mantenimiento puede perfectamente ajustarse hacia arriba en una clase simple proporcionada en de figura 11. Dado esto, puede iniciar el servicio Web como sigue:
const WS_SERVICE_ENDPOINT* endpoints[] = { endpoint };
WsServiceHost serviceHost;
HR(serviceHost.Create(endpoints,
_countof(endpoints),
0, // properties
0, // property count
error));
HR(serviceHost.Open(0, // async context
error));
En este caso, hay sólo un único extremo pero puede ver lo fácil que sería agregar extremos adicionales para el host de servicio. Cuando llegue el momento para detener el servicio, sólo necesita cerrar canales de comunicación del host de servicio.
HR(serviceHost.Close(0, // async context
error));
En realidad la implementación de la operación del servicio Web es acerca de la parte más fácil:
HRESULT CALLBACK AddCallback(__in const WS_OPERATION_CONTEXT*,
__in double first,
__in double second,
__out double* result,
__in_opt const WS_ASYNC_CONTEXT* /*asyncContext*/,
__in_opt WS_ERROR* /*error*/)
{
*result = first + second;
return S_OK;
}
La firma para la función AddCallback también se proporciona por el código fuente generado, si tiene dudas acerca de cómo especificarla.
Y eso es todo lo que hay espacio para este mes, pero ahora debe tener una buena idea de las características y ventajas que ofrece la API de servicios Web de Windows. Como puede ver, los desarrolladores de C++ finalmente tienen una pila SOAP moderna derecha fuera del cuadro de. Ofrece la mejor posible rendimiento y la utilización de memoria y es un placer para utilizar con un poco de Ayuda de C++.
Figura 11 de Service Host Wrapper
class WsServiceHost
{
WS_SERVICE_HOST* m_h;
public:
WsServiceHost() : m_h(0)
{}
~WsServiceHost()
{
if (0 != m_h)
{
Close(0, 0);
WsFreeServiceHost(m_h);
}
}
HRESULT Create(const WS_SERVICE_ENDPOINT** endpoints,
const USHORT endpointCount,
const WS_SERVICE_PROPERTY* properties,
ULONG propertyCount, WS_ERROR* error)
{
return WsCreateServiceHost(endpoints, endpointCount, properties,
propertyCount, &m_h, error);
}
HRESULT Open(const WS_ASYNC_CONTEXT* asyncContext, WS_ERROR* error)
{
return WsOpenServiceHost(m_h, asyncContext, error);
}
HRESULT Close(const WS_ASYNC_CONTEXT* asyncContext, WS_ERROR* error)
{
return WsCloseServiceHost(m_h, asyncContext, error);
}
operator WS_SERVICE_HOST*() const
{
return m_h;
}
};
¿Quién es Using It?
Varios equipos de Microsoft ya ha iniciado la adopción de la API servicios de Web de Windows (WWS) dentro de sus propios productos o tecnologías. En muchos casos, esto reemplaza personalizadas pilas SOAP y algunas incluso ha elegido reemplazar las implementaciones comerciales como Windows Communication Foundation (WCF) con WWS. Estos son sólo unos ejemplos.
Los servicios Web de Microsoft en dispositivos (WSD) API permite a los programadores escribir clientes y servidores basados en el perfil de dispositivos para servicios Web (DPWS). En Windows 7, se ha iniciado la API de WSD utilizando WWS para la creación y la canonicalización de XML en los mensajes SOAP que envía el motor en tiempo de ejecución WSD. El equipo de WSD planea ampliar su uso de WWS a medida que agregan nuevas características y refactorizar el código existente.
Windows CardSpace es la implementación de Microsoft de un sistema de identidad basado en estándares de servicio Web. Se implementó originalmente con WCF, es que se va a escribirlo utilizando código nativo y WWS para cumplir los requisitos empresariales muy estricta en el tamaño del instalador descargable y el conjunto de trabajo del motor en tiempo de ejecución.
El Microsoft Forefront Threat Management Gateway (TMG) es una plataforma de seguridad que proporciona el servidor de seguridad y las características para proteger y mejorar el rendimiento de redes de almacenamiento en caché. Su característica de filtrado de URL utiliza WWS para conectarse al servicio de reputación de Microsoft para categorizar direcciones URL.
Por último, el cliente de la infraestructura de claves públicas (PKI) proporciona administración automática del ciclo de vida de certificados con inscripción automática, así como la inscripción de certificados por usuario y la aplicación. Windows 7 presenta un nuevo conjunto de servicios Web que permiten para la inscripción de certificados se complete sin las limitaciones de traditional de LDAP y DCOM. El cliente PKI hace uso de WWS para todas las operaciones, incluido un nuevo protocolo de directiva de inscripción de certificados (MS-XCEP) y una extensión de WS-Trust para la inscripción de certificados (MS-WSTEP). El cliente WWS se comunica con un nuevo conjunto de servicios de Active Directory certificados en Windows Server 2008 R2 que se implementan con WCF, así como con servicios Web proporcionados por emisores de certificados pública.
Kenny Kerr es un artesano del software especializado en desarrollo de software para Windows. Sus pasiones son la escritura y la enseñanza a los desarrolladores acerca de la programación y del diseño de software. Se puede llegar a Kerr en weblogs.asp.net/kennykerr de.