Consumo de un servicio web ASP.NET (ASMX)
ASMX proporciona la capacidad de compilar servicios web que envían mensajes mediante el Protocolo simple de acceso a objetos (SOAP). SOAP es un protocolo independiente de la plataforma e independiente del lenguaje para compilar y acceder a los servicios web. Los consumidores de un servicio ASMX no necesitan saber nada sobre la plataforma, el modelo de objetos o el lenguaje de programación que se usa para implementar el servicio. Solo necesitan saber cómo enviar y recibir mensajes SOAP. En este artículo se muestra cómo consumir un servicio SOAP ASMX desde una Xamarin.Forms aplicación.
Un mensaje SOAP es un documento XML que contiene los siguientes elementos:
- Elemento raíz denominado Envelope que identifica el documento XML como un mensaje SOAP.
- Elemento Header opcional que contiene información específica de la aplicación, como los datos de autenticación. Si el elemento Header está presente, debe ser el primer elemento secundario del elemento Envelope.
- Elemento Body necesario que contiene el mensaje SOAP destinado al destinatario.
- Elemento Fault opcional que se usa para indicar mensajes de error. Si el elemento Fault está presente, debe ser un elemento secundario del elemento Body.
SOAP puede funcionar a través de muchos protocolos de transporte, incluidos HTTP, SMTP, TCP y UDP. Sin embargo, un servicio ASMX solo puede funcionar a través de HTTP. La plataforma Xamarin admite implementaciones estándar de SOAP 1.1 a través de HTTP, lo que incluye compatibilidad con muchas de las configuraciones de servicio ASMX estándar.
Este ejemplo incluye las aplicaciones móviles que se ejecutan en dispositivos físicos o emulados, y un servicio ASMX que proporciona métodos para obtener, agregar, editar y eliminar datos. Cuando se ejecutan las aplicaciones móviles, se conectan al servicio ASMX hospedado localmente, como se muestra en la captura de pantalla siguiente:

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.
ATS se puede rechazar 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 Seguridad de transporte de aplicaciones.
Consumo del servicio web
El servicio ASMX 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.
Creación del proxy TodoService
Una clase de proxy, denominada , extiende y proporciona métodos para comunicarse con TodoServiceSoapHttpClientProtocol el servicio ASMX a través de HTTP. El proxy se genera agregando una referencia web a cada proyecto específico de la plataforma en Visual Studio 2019 o Visual Studio 2017. La referencia web genera métodos y eventos para cada acción definida en el documento WSDL (Lenguaje de descripción de servicios Web) del servicio.
Por ejemplo, la GetTodoItems acción de servicio da como resultado un método y un evento en el GetTodoItemsAsyncGetTodoItemsCompleted proxy. El método generado tiene un tipo de valor devuelto void e invoca GetTodoItems la acción en la clase SoapHttpClientProtocol primaria. Cuando el método invocado recibe una respuesta del servicio, se desan el evento y se proporcionan los datos de respuesta dentro de GetTodoItemsCompleted la propiedad del Result evento.
Creación de la implementación de ISoapService
Para permitir que el proyecto multiplataforma compartido funcione con el servicio, el ejemplo define la interfaz , que sigue el modelo de programación asincrónica tarea ISoapServiceISoapService Cada plataforma implementa para ISoapService exponer el proxy específico de la plataforma. En el ejemplo se TaskCompletionSource usan objetos para exponer el proxy como una interfaz asincrónica de tarea. Los detalles sobre TaskCompletionSource el uso se encuentran en las implementaciones de cada tipo de acción en las secciones siguientes.
El ejemplo SoapService :
- Crea instancias de como
TodoServiceuna instancia de nivel de clase. - Crea una colección llamada para
ItemsalmacenarTodoItemobjetos - Especifica un punto de conexión personalizado para la propiedad
Urlopcional en elTodoService
public class SoapService : ISoapService
{
ASMXService.TodoService todoService;
public List<TodoItem> Items { get; private set; } = new List<TodoItem>();
public SoapService ()
{
todoService = new ASMXService.TodoService ();
todoService.Url = Constants.SoapUrl;
...
}
}
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 ToASMXServiceTodoItem método , como se muestra en el ejemplo de código siguiente:
ASMXService.TodoItem ToASMXServiceTodoItem (TodoItem item)
{
return new ASMXService.TodoItem {
ID = item.ID,
Name = item.Name,
Notes = item.Notes,
Done = item.Done
};
}
Este método crea una nueva ASMService.TodoItem instancia de y 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 FromASMXServiceTodoItem método , como se muestra en el ejemplo de código siguiente:
static TodoItem FromASMXServiceTodoItem (ASMXService.TodoItem item)
{
return new TodoItem {
ID = item.ID,
Name = item.Name,
Notes = item.Notes,
Done = item.Done
};
}
Este método recupera los datos del tipo generado por el proxy TodoItem y los establece en la instancia recién TodoItem creada.
Recuperación de datos
La ISoapService interfaz espera que el método devuelva un con la colección de RefreshDataAsyncTask elementos. Sin embargo, TodoService.GetTodoItemsAsync el método devuelve void. Para satisfacer el patrón de interfaz, debe llamar a , esperar a que se desancie el evento GetTodoItemsAsync y rellenar la GetTodoItemsCompleted colección. Esto le permite devolver una colección válida a la interfaz de usuario.
En el ejemplo siguiente se crea un nuevo , se inicia la llamada asincrónica en el método y se TaskCompletionSource espera el proporcionado por RefreshDataAsyncTaskTaskCompletionSource . Cuando se TodoService_GetTodoItemsCompleted invoca el controlador de eventos, rellena la colección y actualiza ItemsTaskCompletionSource :
public class SoapService : ISoapService
{
TaskCompletionSource<bool> getRequestComplete = null;
...
public SoapService()
{
...
todoService.GetTodoItemsCompleted += TodoService_GetTodoItemsCompleted;
}
public async Task<List<TodoItem>> RefreshDataAsync()
{
getRequestComplete = new TaskCompletionSource<bool>();
todoService.GetTodoItemsAsync();
await getRequestComplete.Task;
return Items;
}
private void TodoService_GetTodoItemsCompleted(object sender, ASMXService.GetTodoItemsCompletedEventArgs e)
{
try
{
getRequestComplete = getRequestComplete ?? new TaskCompletionSource<bool>();
Items = new List<TodoItem>();
foreach (var item in e.Result)
{
Items.Add(FromASMXServiceTodoItem(item));
}
getRequestComplete?.TrySetResult(true);
}
catch (Exception ex)
{
Debug.WriteLine(@"\t\tERROR {0}", ex.Message);
}
}
...
}
Para obtener más información, vea Modelo de programación asincrónica y TPL y Tradicional .NET Framework programación asincrónica.
Creación o edición de datos
Al crear o editar datos, debe implementar el ISoapService.SaveTodoItemAsync método . Este método detecta si es un elemento nuevo o TodoItem actualizado y llama al método adecuado en el objeto todoService . Los controladores de eventos y también deben implementarse para que sepa cuándo ha recibido una respuesta del servicio ASMX (estos se pueden combinar en un único controlador porque realizan la CreateTodoItemCompletedEditTodoItemCompleted misma todoService operación). En el ejemplo siguiente se muestran las implementaciones de interfaz y controlador de eventos, así como el TaskCompletionSource objeto utilizado para funcionar de forma asincrónica:
public class SoapService : ISoapService
{
TaskCompletionSource<bool> saveRequestComplete = null;
...
public SoapService()
{
...
todoService.CreateTodoItemCompleted += TodoService_SaveTodoItemCompleted;
todoService.EditTodoItemCompleted += TodoService_SaveTodoItemCompleted;
}
public async Task SaveTodoItemAsync (TodoItem item, bool isNewItem = false)
{
try
{
var todoItem = ToASMXServiceTodoItem(item);
saveRequestComplete = new TaskCompletionSource<bool>();
if (isNewItem)
{
todoService.CreateTodoItemAsync(todoItem);
}
else
{
todoService.EditTodoItemAsync(todoItem);
}
await saveRequestComplete.Task;
}
catch (SoapException se)
{
Debug.WriteLine("\t\t{0}", se.Message);
}
catch (Exception ex)
{
Debug.WriteLine("\t\tERROR {0}", ex.Message);
}
}
private void TodoService_SaveTodoItemCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
saveRequestComplete?.TrySetResult(true);
}
...
}
Eliminación de datos
La eliminación de datos requiere una implementación similar. Defina , TaskCompletionSource implemente un controlador de eventos y el ISoapService.DeleteTodoItemAsync método :
public class SoapService : ISoapService
{
TaskCompletionSource<bool> deleteRequestComplete = null;
...
public SoapService()
{
...
todoService.DeleteTodoItemCompleted += TodoService_DeleteTodoItemCompleted;
}
public async Task DeleteTodoItemAsync (string id)
{
try
{
deleteRequestComplete = new TaskCompletionSource<bool>();
todoService.DeleteTodoItemAsync(id);
await deleteRequestComplete.Task;
}
catch (SoapException se)
{
Debug.WriteLine("\t\t{0}", se.Message);
}
catch (Exception ex)
{
Debug.WriteLine("\t\tERROR {0}", ex.Message);
}
}
private void TodoService_DeleteTodoItemCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
deleteRequestComplete?.TrySetResult(true);
}
...
}
Prueba del servicio web
La prueba de dispositivos físicos o emulados con un servicio hospedado localmente requiere la configuración personalizada de IIS, las direcciones de punto de conexión y las reglas de firewall. Para obtener más información sobre cómo configurar el entorno para pruebas, consulte Configuración del acceso remoto a IIS Express. La única diferencia entre probar WCF y ASMX es el número de puerto de TodoService.
Descarga del ejemplo