Consumo de un servicio web Windows Communication Foundation (WCF)

Ejemplo de descarga Descarga del ejemplo

WCF es el marco unificado de Microsoft para compilar aplicaciones orientadas a servicios. Permite a los desarrolladores crear aplicaciones distribuidas seguras, confiables, con transacciones e interoperables. En este artículo se muestra cómo consumir un servicio SOAP (Protocolo simple de acceso a objetos) de WCF desde una Xamarin.Forms aplicación.

WCF describe un servicio con una variedad de contratos diferentes, entre los que se incluyen:

  • Contratos de datos: definen las estructuras de datos que forman la base del contenido dentro de un mensaje.
  • Contratos de mensajes: redactar mensajes a partir de contratos de datos existentes.
  • Contratos de error: permiten especificar errores SOAP personalizados.
  • Contratos de servicio: especifique las operaciones que admiten los servicios y los mensajes necesarios para interactuar con cada operación. También especifican cualquier comportamiento de error personalizado que se pueda asociar a las operaciones en cada servicio.

Hay diferencias entre ASP.NET Web Services (ASMX) y WCF, pero WCF admite las mismas funcionalidades que proporciona ASMX: mensajes SOAP a través de HTTP. Para obtener más información sobre cómo consumir un servicio ASMX, vea Consumir ASP.NET Web Services (ASMX).

Importante

La compatibilidad de la plataforma Xamarin con WCF se limita a los mensajes SOAP codificados por texto a través de HTTP/HTTPS mediante la BasicHttpBinding clase .

La compatibilidad con WCF requiere el uso de herramientas solo disponibles en un entorno Windows para generar el proxy y hospedar TodoWCFService. La creación y prueba de la aplicación iOS requerirá la implementación de TodoWCFService en un Windows o como un servicio web de Azure.

Xamarin Forms Las aplicaciones nativas suelen compartir código con una .NET Standard de clases. Sin embargo, .NET Core no admite actualmente WCF, por lo que el proyecto compartido debe ser una biblioteca de clases portable heredada. Para obtener información sobre la compatibilidad de WCF en .NET Core, vea Elegir entre .NET Core y .NET Framework aplicaciones de servidor.

La solución de aplicación de ejemplo incluye un servicio WCF que se puede ejecutar localmente y se muestra en la captura de pantalla siguiente:

Aplicación de ejemplo

Nota:

En iOS 9 y superior, App Transport Security (ATS) exige conexiones seguras entre los recursos de Internet (como el servidor back-end de la aplicación) y la aplicación, lo que impide la divulgación accidental de información confidencial. Puesto que ATS está habilitado de forma predeterminada en las aplicaciones creadas para iOS 9, todas las conexiones estarán sujetas a los requisitos de seguridad de ATS. Si las conexiones no cumplen estos requisitos, se producirá un error con una excepción.

SE puede rechazar ATS si no es posible usar el protocolo y proteger HTTPS la comunicación con los recursos de Internet. Esto se puede lograr actualizando el archivo Info.plist de la aplicación. Para obtener más información, vea App Transport Security.

Consumo del servicio web

El servicio WCF proporciona las siguientes operaciones:

Operación Descripción Parámetros
GetTodoItems Obtención de una lista de tareas pendientes
CreateTodoItem Creación de un nuevo elemento de trabajo TodoItem serializado xml
EditTodoItem Actualizar una tarea pendiente TodoItem serializado xml
DeleteTodoItem Eliminar una tarea pendiente TodoItem serializado xml

Para obtener más información sobre el modelo de datos usado en la aplicación, vea Modelado de los datos.

Se debe generar un proxy para consumir un servicio WCF, lo que permite a la aplicación conectarse al servicio. El proxy se construye mediante el consumo de metadatos de servicio que definen los métodos y la configuración de servicio asociada. Estos metadatos se exponen en forma de documento WSDL (Lenguaje de descripción de servicios Web) generado por el servicio web. El proxy se puede crear mediante el Microsoft WCF Web Service Reference Provider de Visual Studio 2017 para agregar una referencia de servicio para el servicio web a una biblioteca .NET Standard cliente. Una alternativa a la creación del proxy mediante Microsoft WCF Web Service Reference Provider en Visual Studio 2017 es usar la herramienta utilidad de metadatos ServiceModel (svcutil.exe). Para obtener más información, vea ServiceModel Metadata Utility Tool (Svcutil.exe).

Las clases de proxy generadas proporcionan métodos para consumir los servicios web que usan el patrón de diseño modelo de programación asincrónica (APM). En este patrón, se implementa una operación asincrónica como dos métodos denominados BeginOperationName y EndOperationName, que comienzan y finalizan la operación asincrónica.

El método BeginOperationName comienza la operación asincrónica y devuelve un objeto que implementa la interfaz . Después de llamar a BeginOperationName, una aplicación puede seguir ejecutando instrucciones en el subproceso que realiza la llamada, mientras que la operación asincrónica tiene lugar en un subproceso del grupo de subprocesos.

Para cada llamada a BeginOperationName, la aplicación también debe llamar a EndOperationName para obtener los resultados de la operación. El valor devuelto de EndOperationName es el mismo tipo devuelto por el método de servicio web sincrónico. Por ejemplo, el EndGetTodoItems método devuelve una colección de instancias de TodoItem . El método EndOperationName también incluye un parámetro que se debe establecer en la instancia devuelta por la llamada correspondiente al método BeginOperationName.

La biblioteca TPL (Task Parallel Library) puede simplificar el proceso de consumo de un par de métodos de inicio y finalización de APM encapsulando las operaciones asincrónicas en el mismo Task objeto. Esta encapsulación se proporciona mediante varias sobrecargas del TaskFactory.FromAsync método .

Para obtener más información sobre APM, vea Modelo de programación asincrónica y TPL y Programación .NET Framework programación asincrónica en MSDN.

Creación del objeto TodoServiceClient

La clase de proxy generada proporciona TodoServiceClient la clase , que se usa para comunicarse con el servicio WCF a través de HTTP. Proporciona funcionalidad para invocar métodos de servicio web como operaciones asincrónicas desde una instancia de servicio identificada por uri. Para obtener más información sobre las operaciones asincrónicas, vea Async Support Overview.

La instancia se declara en el nivel de clase de modo que el objeto reside mientras la aplicación necesite consumir el servicio WCF, como se muestra en el TodoServiceClient ejemplo de código siguiente:

public class SoapService : ISoapService
{
  ITodoService todoService;
  ...

  public SoapService ()
  {
    todoService = new TodoServiceClient (
      new BasicHttpBinding (),
      new EndpointAddress (Constants.SoapUrl));
  }
  ...
}

La TodoServiceClient instancia se configura con información de enlace y una dirección de punto de conexión. Un enlace se usa para especificar los detalles de transporte, codificación y protocolo necesarios para que las aplicaciones y servicios se comuniquen entre sí. especifica que los mensajes SOAP codificados por texto BasicHttpBinding se enviarán a través del protocolo de transporte HTTP. La especificación de una dirección de punto de conexión permite a la aplicación conectarse a diferentes instancias del servicio WCF, siempre que haya varias instancias publicadas.

Para obtener más información sobre cómo configurar la referencia de servicio, vea Configuring the Service Reference.

Creación de objetos de transferencia de datos

La aplicación de ejemplo usa la TodoItem clase para modelar los datos. Para almacenar un elemento en el servicio web, primero debe convertirse TodoItem al tipo generado por TodoItem proxy. Esto se logra mediante el ToWCFServiceTodoItem método , como se muestra en el ejemplo de código siguiente:

TodoWCFService.TodoItem ToWCFServiceTodoItem (TodoItem item)
{
  return new TodoWCFService.TodoItem
  {
    ID = item.ID,
    Name = item.Name,
    Notes = item.Notes,
    Done = item.Done
  };
}

Este método simplemente crea una nueva instancia de y TodoWCFService.TodoItem establece cada propiedad en la propiedad idéntica de la instancia de TodoItem .

De forma similar, cuando se recuperan datos del servicio web, se deben convertir del tipo generado por proxy TodoItem a una instancia de TodoItem . Esto se logra con el FromWCFServiceTodoItem método , como se muestra en el ejemplo de código siguiente:

static TodoItem FromWCFServiceTodoItem (TodoWCFService.TodoItem item)
{
  return new TodoItem
  {
    ID = item.ID,
    Name = item.Name,
    Notes = item.Notes,
    Done = item.Done
  };
}

Este método simplemente recupera los datos del tipo generado por proxy TodoItem y los establece en la instancia recién TodoItem creada.

Recuperación de datos

Los TodoServiceClient.BeginGetTodoItemsTodoServiceClient.EndGetTodoItems métodos y se usan para llamar a GetTodoItems la operación proporcionada por el servicio web. Estos métodos asincrónicos se encapsulan en un Task objeto , como se muestra en el ejemplo de código siguiente:

public async Task<List<TodoItem>> RefreshDataAsync ()
{
  ...
  var todoItems = await Task.Factory.FromAsync <ObservableCollection<TodoWCFService.TodoItem>> (
    todoService.BeginGetTodoItems,
    todoService.EndGetTodoItems,
    null,
    TaskCreationOptions.None);

  foreach (var item in todoItems)
  {
    Items.Add (FromWCFServiceTodoItem (item));
  }
  ...
}

El método crea un objeto que ejecuta el método una vez completado el método, con el parámetro que indica que no se pasa ningún dato Task.Factory.FromAsyncTask al TodoServiceClient.EndGetTodoItemsTodoServiceClient.BeginGetTodoItemsnullBeginGetTodoItems delegado. Por último, el valor de la enumeración especifica que se debe usar el comportamiento predeterminado para la creación y TaskCreationOptions ejecución de tareas.

El método devuelve un de instancias de , que luego se TodoServiceClient.EndGetTodoItems convierte en un de instancias para su ObservableCollectionTodoWCFService.TodoItemListTodoItem presentación.

Creación de datos

Los TodoServiceClient.BeginCreateTodoItemTodoServiceClient.EndCreateTodoItem métodos y se usan para llamar a CreateTodoItem la operación proporcionada por el servicio web. Estos métodos asincrónicos se encapsulan en un Task objeto , como se muestra en el ejemplo de código siguiente:

public async Task SaveTodoItemAsync (TodoItem item, bool isNewItem = false)
{
  ...
  var todoItem = ToWCFServiceTodoItem (item);
  ...
  await Task.Factory.FromAsync (
    todoService.BeginCreateTodoItem,
    todoService.EndCreateTodoItem,
    todoItem,
    TaskCreationOptions.None);
  ...
}

El método crea un objeto que ejecuta el método una vez completado el método, siendo el parámetro los datos que se pasan al delegado para especificar el que va a crear el Task.Factory.FromAsyncTask servicio TodoServiceClient.EndCreateTodoItemTodoServiceClient.BeginCreateTodoItemtodoItemBeginCreateTodoItemTodoItem web. Por último, el valor de la enumeración especifica que se debe usar el comportamiento predeterminado para la creación y TaskCreationOptions ejecución de tareas.

El servicio web produce una FaultException excepción si no se puede crear TodoItem , que controla la aplicación.

Actualización de datos

Los TodoServiceClient.BeginEditTodoItemTodoServiceClient.EndEditTodoItem métodos y se usan para llamar a EditTodoItem la operación proporcionada por el servicio web. Estos métodos asincrónicos se encapsulan en un Task objeto , como se muestra en el ejemplo de código siguiente:

public async Task SaveTodoItemAsync (TodoItem item, bool isNewItem = false)
{
  ...
  var todoItem = ToWCFServiceTodoItem (item);
  ...
  await Task.Factory.FromAsync (
    todoService.BeginEditTodoItem,
    todoService.EndEditTodoItem,
    todoItem,
    TaskCreationOptions.None);
  ...
}

El método crea un objeto que ejecuta el método una vez completado el método, siendo el parámetro los datos que se pasan al delegado para especificar que el servicio web va a Task.Factory.FromAsyncTaskTodoServiceClient.EndEditTodoItemTodoServiceClient.BeginCreateTodoItemtodoItemBeginEditTodoItemTodoItem actualizar. Por último, el valor de la enumeración especifica que se debe usar el comportamiento predeterminado para la creación y TaskCreationOptions ejecución de tareas.

El servicio web produce una excepción si no encuentra o actualiza FaultException , que controla la TodoItem aplicación.

Eliminación de datos

Los TodoServiceClient.BeginDeleteTodoItemTodoServiceClient.EndDeleteTodoItem métodos y se usan para llamar a DeleteTodoItem la operación proporcionada por el servicio web. Estos métodos asincrónicos se encapsulan en un Task objeto , como se muestra en el ejemplo de código siguiente:

public async Task DeleteTodoItemAsync (string id)
{
  ...
  await Task.Factory.FromAsync (
    todoService.BeginDeleteTodoItem,
    todoService.EndDeleteTodoItem,
    id,
    TaskCreationOptions.None);
  ...
}

El método crea un objeto que ejecuta el método una vez completado el método, siendo el parámetro los datos que se pasan al delegado para especificar que el servicio web va Task.Factory.FromAsyncTask a TodoServiceClient.EndDeleteTodoItemTodoServiceClient.BeginDeleteTodoItemidBeginDeleteTodoItemTodoItem eliminar. Por último, el valor de la enumeración especifica que se debe usar el comportamiento predeterminado para la creación y TaskCreationOptions ejecución de tareas.

El servicio web produce una excepción si no encuentra o elimina FaultException , que controla la TodoItem aplicación.

Configuración del acceso remoto a IIS Express

En Visual Studio 2017 o Visual Studio 2019, debería poder probar la aplicación para UWP en un equipo sin configuración adicional. La prueba de clientes iOS y Android puede requerir los pasos adicionales de esta sección. Consulte Conectar a servicios web locales desde simuladores de iOS y emuladores de Android para obtener más información.

De forma predeterminada, IIS Express responderá solo a las solicitudes a localhost . Los dispositivos remotos (como un dispositivo Android, un iPhone o incluso un simulador) no tendrán acceso al servicio WCF local. Deberá conocer la dirección IP de la estación Windows 10 en la red local. Para este ejemplo, suponga que la estación de trabajo tiene la dirección IP 192.168.1.143 . En los pasos siguientes se explica cómo configurar Windows 10 y IIS Express para aceptar conexiones remotas y conectarse al servicio desde un dispositivo físico o virtual:

  1. Agregue una excepción a Windows Firewall. Debe abrir un puerto a través de Windows Firewall que las aplicaciones de la subred pueden usar para comunicarse con el servicio WCF. Cree una regla de entrada que abra el puerto 49393 en el firewall. Desde un símbolo del sistema administrativo, ejecute este comando:

    netsh advfirewall firewall add rule name="TodoWCFService" dir=in protocol=tcp localport=49393 profile=private remoteip=localsubnet action=allow
    
  2. Configure IIS Express para aceptar conexiones remotas. Puede configurar los IIS Express editando el archivo de configuración para IIS Express en [directorio de la solución].vs\config\applicationhost.config. Busque el elemento con el nombre TodoWCFService . Debe tener un aspecto similar al siguiente XML:

    <site name="TodoWCFService" id="2">
        <application path="/" applicationPool="Clr4IntegratedAppPool">
            <virtualDirectory path="/" physicalPath="C:\Users\tom\TodoWCF\TodoWCFService\TodoWCFService" />
        </application>
        <bindings>
            <binding protocol="http" bindingInformation="*:49393:localhost" />
        </bindings>
    </site>
    

    Deberá agregar dos elementos para abrir el puerto binding 49393 al tráfico externo y al emulador de Android. El enlace usa un [IP address]:[port]:[hostname] formato que especifica cómo IIS Express responderá a las solicitudes. Las solicitudes externas tendrán nombres de host que deben especificarse como binding . Agregue el siguiente xml al bindings elemento , reemplazando la dirección IP por su propia dirección IP:

    <binding protocol="http" bindingInformation="*:49393:192.168.1.143" />
    <binding protocol="http" bindingInformation="*:49393:127.0.0.1" />
    

    Después de los bindings cambios, el elemento debe tener un aspecto parecido al siguiente:

    <site name="TodoWCFService" id="2">
        <application path="/" applicationPool="Clr4IntegratedAppPool">
            <virtualDirectory path="/" physicalPath="C:\Users\tom\TodoWCF\TodoWCFService\TodoWCFService" />
        </application>
        <bindings>
            <binding protocol="http" bindingInformation="*:49393:localhost" />
            <binding protocol="http" bindingInformation="*:49393:192.168.1.143" />
            <binding protocol="http" bindingInformation="*:49393:127.0.0.1" />
        </bindings>
    </site>
    

    Importante

    De forma predeterminada, IIS Express no aceptará conexiones de orígenes externos por motivos de seguridad. Para habilitar las conexiones desde dispositivos remotos, debe ejecutar IIS Express con permisos administrativos. La manera más fácil de hacerlo es ejecutar Visual Studio 2017 con permisos administrativos. Esto iniciará IIS Express permisos administrativos al ejecutar TodoWCFService.

    Una vez completados estos pasos, debería poder ejecutar TodoWCFService y conectarse desde otros dispositivos de la subred. Para probar esto, ejecute la aplicación y visite http://localhost:49393/TodoService.svc . Si recibe un error de solicitud incorrecta al visitar esa dirección URL, puede ser incorrecto en la configuración de IIS Express (la solicitud está llegando a IIS Express pero se está rechazando). Si recibe un error diferente, puede que la aplicación no se esté ejecutando o que el firewall esté configurado incorrectamente.

    Para permitir IIS Express seguir ejecutando y atendiendo el servicio, desactive la opción Editar y continuar en los depuradores web Project Properties.

  3. Personalice los dispositivos de punto de conexión que usan para acceder al servicio. Este paso implica configurar la aplicación cliente, que se ejecuta en un dispositivo físico o emulado, para acceder al servicio WCF.

    Android Emulator usa un proxy interno que impide que el emulador acceda directamente a la dirección del equipo localhost host. En su lugar, 10.0.2.2 la dirección del emulador se enruta a en el equipo host a través de un proxy localhost interno. Estas solicitudes con proxy tendrán como nombre de host en el encabezado de solicitud, por lo que creó el enlace IIS Express para este nombre de host en 127.0.0.1 los pasos anteriores.

    El simulador de iOS se ejecuta en un host de compilación de Mac, incluso si usa el simulador remoto de iOS para Windows. Las solicitudes de red del simulador tendrán la dirección IP de la estación de trabajo en la red local como nombre de host (en este ejemplo es , pero es probable que la dirección IP real 192.168.1.143 sea diferente). Este es el motivo por el que creó IIS Express enlace para este nombre de host en los pasos anteriores.

    Asegúrese de que la propiedad SoapUrlSoapUrl del proyecto TodoWCF (Portable) tiene valores correctos para la red:

    public static string SoapUrl
    {
        get
        {
            var defaultUrl = "http://localhost:49393/TodoService.svc";
    
            if (Device.RuntimePlatform == Device.Android)
            {
                defaultUrl = "http://10.0.2.2:49393/TodoService.svc";
            }
            else if (Device.RuntimePlatform == Device.iOS)
            {
                defaultUrl = "http://192.168.1.143:49393/TodoService.svc";
            }
    
            return defaultUrl;
        }
    }
    

    Una vez configurado Constants.cs con los puntos de conexión adecuados, debería poder conectarse a todoWCFService que se ejecuta en la estación de trabajo de Windows 10 desde dispositivos físicos o virtuales.