Desarrollo de Azure Functions con Visual Studio

Visual Studio le permite desarrollar, probar e implementar funciones de la biblioteca de clases C# en Azure. Si esta es la primera experiencia con Azure Functions, vea Introducción a Azure Functions.

Antes de empezar, le recomendamos que complete la guía de inicio rápido de Functions para Visual Studio.

En este artículo se dan detalles sobre cómo usar Visual Studio para desarrollar funciones de biblioteca de clases C# y publicarlas en Azure. Hay dos modelos para desarrollar funciones de la biblioteca de clases de C#: el modelo de trabajo aislado y el modelo en proceso.

En este artículo se trata sobre el modelo de trabajo aislado. Puede elegir su modelo preferido en la parte superior del artículo.

En este artículo se trata sobre el modelo de trabajo aislado. Puede elegir su modelo preferido en la parte superior del artículo.

A menos que se indique lo contrario, los procedimientos y los ejemplos que se muestran son para Visual Studio 2022. Para obtener más información sobre las versiones de Visual Studio 2022, consulte las notas de la versión o las notas de la versión preliminar.

Requisitos previos

  • Visual Studio 2022, con la carga de trabajo Desarrollo de Azure.

  • Los demás recursos que necesita, como una cuenta de Azure Storage, se crean en la suscripción durante el proceso de publicación.

  • Si no tiene una suscripción a Azure, cree una cuenta gratuita de Azure antes de empezar.

Creación de un proyecto de Azure Functions

La plantilla del proyecto de Azure Functions de Visual Studio crea un proyecto de biblioteca de clases de C# que puede publicar en una aplicación de funciones en Azure. Una aplicación de funciones permite agrupar funciones como una unidad lógica para facilitar la administración, la implementación, el escalado y el uso compartido de recursos.

  1. En el menú de Visual Studio, seleccione Archivo>Nuevo>Proyecto.

  2. En Crear un proyecto, escriba functions en el cuadro de búsqueda, elija la plantilla Azure Functions y seleccione Siguiente.

  3. En Configurar el nuevo proyecto, escriba un nombre de proyecto para el proyecto y, a continuación, seleccione Crear. El nombre de la aplicación de función debe ser válido como espacio de nombres de C#, por lo que no debe usar guiones bajos, guiones u otros caracteres no alfanuméricos.

  4. En la configuración de Crear aplicación de Azure Functions, use los valores de la tabla siguiente:

    Configuración valor Descripción
    Versión de .NET .NET 6 aislado Este valor crea un proyecto de función que se ejecuta en un proceso de trabajo aislado. El proceso de trabajo aislado admite otras versiones que no sean LTS de .NET y también .NET Framework. Para más información, consulte Selección de un destino para versiones de runtime de Azure Functions.
    Plantilla de función desencadenador HTTP Este valor crea una función desencadenada por una solicitud HTTP.
    Cuenta de almacenamiento (AzureWebJobsStorage) Emulador de Storage Dado que una aplicación de funciones de Azure necesita una cuenta de almacenamiento, se asigna o se crea una cuando publica su proyecto en Azure. Un desencadenador HTTP no utiliza una cadena de conexión de cuenta de Azure Storage; todos los demás tipos de desencadenador requieren una cadena de conexión de cuenta de Azure Storage válida.
    Nivel de autorización Anónimo Cualquier cliente puede desencadenar una función creada sin tener que proporcionar una clave. Esta configuración de autorización facilita probar la función nueva. Para más información sobre las claves y la autorización, consulte Claves de autorización e Introducción a los enlaces y desencadenadores HTTP de Azure Functions.

    Screenshot of Azure Functions project settings

    Configuración valor Descripción
    Versión de .NET .NET 6 Este valor crea un proyecto de función que se ejecuta dentro de proceso con la versión 4.x del entorno de ejecución de Azure Functions. Para más información, consulte Selección de un destino para versiones de runtime de Azure Functions.
    Plantilla de función desencadenador HTTP Este valor crea una función desencadenada por una solicitud HTTP.
    Cuenta de almacenamiento (AzureWebJobsStorage) Emulador de Storage Dado que una aplicación de funciones de Azure necesita una cuenta de almacenamiento, se asigna o se crea una cuando publica su proyecto en Azure. Un desencadenador HTTP no utiliza una cadena de conexión de cuenta de Azure Storage; todos los demás tipos de desencadenador requieren una cadena de conexión de cuenta de Azure Storage válida.
    Nivel de autorización Anónimo Cualquier cliente puede desencadenar una función creada sin tener que proporcionar una clave. Esta configuración de autorización facilita probar la función nueva. Para más información sobre las claves y la autorización, consulte Claves de autorización e Introducción a los enlaces y desencadenadores HTTP de Azure Functions.

    Screenshot of Azure Functions project settings

    Asegúrese de establecer el Nivel de autorización en Anónimo. Al elegir el nivel predeterminado de Función, tiene que presentar la tecla de función en las solicitudes para acceder al punto de conexión de la función.

  5. Seleccione Crear para crear el proyecto de función y la función con desencadenador HTTP.

Después de crear un proyecto de Azure Functions, la plantilla de proyecto crea un proyecto de C#, instala los paquetes NuGet Microsoft.Azure.Functions.Worker y Microsoft.Azure.Functions.Worker.Sdk, y establece la plataforma de destino.

Después de crear un proyecto de Azure Functions, la plantilla de proyecto crea un proyecto de C#, instala el paquete NuGet Microsoft.NET.Sdk.Functions y establece la plataforma de destino.

El proyecto nuevo contiene los archivos siguientes:

  • host.json: permite configurar el host de Functions. Esta configuración se aplica tanto cuando se ejecuta localmente como en Azure. Para más información, consulte la referencia sobre host.json.

  • local.settings.json: mantiene la configuración que se usa cuando se ejecutan localmente las funciones. Esta configuración no se usa cuando se ejecuta en Azure. Para más información, consulte Archivo de configuración local.

    Importante

    Como el archivo local.settings.json puede contener secretos, debe excluirlo del control de código fuente del proyecto. Asegúrese de que el valor Copiar en el directorio de salida para este archivo esté establecido en Copiar si es posterior.

Para más información, consulte Estructura del proyecto en la guía de trabajo aislado.

Para más información, consulte Proyecto de biblioteca de clases de Functions.

Trabajar con la configuración de la aplicación localmente

Cuando se ejecuta en una aplicación de funciones de Azure, la configuración requerida por las funciones se almacena de forma segura en la configuración de la aplicación. Durante el desarrollo local, esta configuración se agrega en su lugar a la colección Values del archivo local.settings.json. El archivo local.settings.json almacena también la configuración que usan las herramientas locales de desarrollo.

Los elementos de la colección Values del archivo local.settings.json del proyecto están diseñados para reflejar elementos en la configuración de la aplicación de la aplicación de funciones en Azure.

Visual Studio no carga de forma automática la configuración de local.settings.json al publicar el proyecto. Para asegurarse de que esta configuración también existe en la aplicación de funciones de Azure, debe cargarla después de publicar el proyecto. Para obtener más información, vea Configuración de aplicación de funciones. Los valores de una colección ConnectionStrings nunca se publican.

El código también puede leer los valores de configuración de la aplicación de funciones como variables de entorno. Para más información, consulte Variables de entorno.

Configuración del proyecto para el desarrollo local

El entorno de tiempo de ejecución de Functions usa internamente una cuenta de Azure Storage. Para todos los tipos de desencadenadores distintos de HTTP y webhooks, establezca la clave Values.AzureWebJobsStorage en una cadena de conexión de cuenta de Azure Storage válida. La aplicación de funciones también puede usar el emulador de Azurite para la configuración de conexión AzureWebJobsStorage que necesita el proyecto. Para usar el emulador, establezca el valor de AzureWebJobsStorage en UseDevelopmentStorage=true. Cambie esta configuración a una cadena de conexión de la cuenta de almacenamiento real antes de la implementación. Para más información, consulte Emulador de almacenamiento local.

Para establecer la cadena de conexión de cuenta de almacenamiento:

  1. En Azure Portal, vaya a la cuenta de almacenamiento.

  2. En la pestaña Claves de acceso, debajo de Seguridad y redes, copie la cadena de conexión de key1.

  3. En el proyecto, abra el archivo local.settings.json y establezca el valor de la clave AzureWebJobsStorage en la cadena de conexión que ha copiado.

  4. Repita el paso anterior para agregar claves únicas a la matriz Values de cualquier otra conexión necesaria para las funciones.

Incorporación de una función al proyecto

En las funciones de biblioteca de clases C#, los enlaces que la función usa se definen mediante la aplicación de atributos en el código. Al crear los desencadenadores de funciones a partir de las plantillas proporcionadas, los atributos del desencadenador se aplican automáticamente.

  1. En el Explorador de soluciones, haga clic con el botón derecho en el nodo del proyecto y seleccione Agregar>Nueva función de Azure Functions.

  2. Escriba un nombre para la clase y seleccione Agregar.

  3. Elija el desencadenador, establezca las propiedades de enlace necesarias y, después, seleccione Agregar. En el ejemplo siguiente se muestra los valores para crear una función de desencadenador de Queue Storage.

    Create a Queue storage trigger function

    Para un desencadenador de servicio de Azure Storage, active la casilla Configurar conexión y se le pedirá que elija entre usar un emulador de almacenamiento de Azurite o hacer referencia a una cuenta de almacenamiento de Azure aprovisionada. Seleccione Siguiente y, si elige una cuenta de almacenamiento, Visual Studio intentará conectarse a su cuenta de Azure y obtener la cadena de conexión. Seleccione Guardar el valor de cadena de conexión en el archivo de secretos del usuario local y, a continuación, Finalizar para crear la clase del desencadenador.

    En este ejemplo de desencadenador se usa una configuración de aplicación para la conexión de almacenamiento con una clave denominada QueueStorage. Esta clave, que está almacenada en el archivo local.settings.json, hace referencia al emulador de Azurite o a una cuenta de almacenamiento de Azure.

  4. Examine la clase recién agregada. Por ejemplo, la clase de C# siguiente representa una función de desencadenador de Queue Storage básica:

    Puede ver un método Run() estático con el atributo Function. Este atributo indica que el método es el punto de entrada de la función.

    using System;
    using Azure.Storage.Queues.Models;
    using Microsoft.Azure.Functions.Worker;
    using Microsoft.Extensions.Logging;
    
    namespace Company.Function
    {
        public class QueueTriggerCSharp
        {
            private readonly ILogger<QueueTriggerCSharp> _logger;
    
            public QueueTriggerCSharp(ILogger<QueueTriggerCSharp> logger)
            {
                _logger = logger;
            }
    
            [Function(nameof(QueueTriggerCSharp))]
            public void Run([QueueTrigger("PathValue", Connection = "ConnectionValue")] QueueMessage message)
            {
                _logger.LogInformation($"C# Queue trigger function processed: {message.MessageText}");
            }
        }
    }
    

    Puede ver un método Run() estático con el atributo FunctionName. Este atributo indica que el método es el punto de entrada de la función.

    using System;
    using Microsoft.Azure.WebJobs;
    using Microsoft.Azure.WebJobs.Host;
    using Microsoft.Extensions.Logging;
    
    namespace Company.Function
    {
        public class QueueTriggerCSharp
        {
            [FunctionName("QueueTriggerCSharp")]
            public void Run([QueueTrigger("PathValue", Connection = "ConnectionValue")]string myQueueItem, ILogger log)
            {
                log.LogInformation($"C# Queue trigger function processed: {myQueueItem}");
            }
        }
    }
    

Se aplica un atributo específico de enlace a cada parámetro de enlace que se suministra al método de punto de entrada. El atributo toma la información de enlace como parámetros. En el ejemplo anterior, el primer parámetro tiene aplicado un atributo QueueTrigger, que indica una función de desencadenador de Queue Storage. El nombre de la cola y el valor de la cadena de conexión se pasan como parámetros en el atributo QueueTrigger. Para más información, consulte Enlaces de Azure Queue Storage para Azure Functions.

Use el procedimiento anterior para agregar más funciones al proyecto de aplicación de funciones. Cada función del proyecto puede tener un desencadenador diferente, pero una función no puede tener más de un desencadenador. Para más información, consulte Conceptos básicos sobre los enlaces y desencadenadores de Azure Functions.

Adición de enlaces

Al igual que sucede con los desencadenadores, los enlaces de entrada y salida se agregan a la función como atributos de enlace. Agregue los enlaces a una función como se indica a continuación:

  1. Asegúrese de que configura el proyecto para desarrollo local.

  2. Agregue el paquete de extensión NuGet adecuado para el enlace específico mediante la búsqueda de los requisitos de paquete de NuGet específicos del enlace en el artículo de referencia para el enlace. Por ejemplo, buscar los requisitos del paquete para el desencadenador de Event Hubs en el artículo de referencia Enlaces de Azure Event Hubs.

  3. Use el siguiente comando en la consola de Administrador de paquetes para instalar un paquete específico:

    Install-Package Microsoft.Azure.Functions.Worker.Extensions.<BINDING_TYPE> -Version <TARGET_VERSION>
    
    Install-Package Microsoft.Azure.WebJobs.Extensions.<BINDING_TYPE> -Version <TARGET_VERSION>
    

    En este ejemplo, reemplace <BINDING_TYPE> por el nombre específico de la extensión de enlace y <TARGET_VERSION> por una versión específica del paquete, como 4.0.0. Las versiones válidas se enumeran en las páginas individuales del paquete en NuGet.org.

  4. Si hay valores de la aplicación que el enlace necesita, agréguelos a la colección Values del archivo de configuración local.

    La función usa estos valores cuando se ejecuta localmente. Cuando la función se ejecuta en la aplicación de funciones en Azure, usa los valores de la aplicación de funciones. Visual Studio facilita publicar la configuración local en Azure.

  5. Agregue el atributo de enlace apropiado para la firma del método. En el ejemplo siguiente, un mensaje de la cola desencadena la función y el enlace de salida, se crea un nuevo mensaje de la cola con el mismo texto en otra cola.

     public class QueueTrigger
    {
        private readonly ILogger _logger;
    
        public QueueTrigger(ILoggerFactory loggerFactory)
        {
            _logger = loggerFactory.CreateLogger<QueueTrigger>();
        }
    
        [Function("CopyQueueMessage")]
        [QueueOutput("myqueue-items-destination", Connection = "QueueStorage")]
        public string Run([QueueTrigger("myqueue-items-source", Connection = "QueueStorage")] string myQueueItem)
        {
            _logger.LogInformation($"C# Queue trigger function processed: {myQueueItem}");
            return myQueueItem;
        }
    }
    

    El atributo QueueOutput define el enlace en el método. En el caso de varios enlaces de salida, coloque este atributo en una propiedad de cadena del objeto devuelto. Para más información, consulte Varios enlaces de salida.

    public static class SimpleExampleWithOutput
    {
        [FunctionName("CopyQueueMessage")]
        public static void Run(
            [QueueTrigger("myqueue-items-source", Connection = "QueueStorage")] string myQueueItem, 
            [Queue("myqueue-items-destination", Connection = "QueueStorage")] out string myQueueItemCopy,
            ILogger log)
        {
            log.LogInformation($"CopyQueueMessage function processed: {myQueueItem}");
            myQueueItemCopy = myQueueItem;
        }
    }
    

    El atributo Queue del parámetro out define el enlace de salida.

    La conexión con el almacenamiento en la cola se obtiene del valor QueueStorage. Para más información, consulte el artículo de referencia del enlace concreto.

Para obtener una lista completa de los enlaces admitidos por Functions, consulte Enlaces admitidos.

Ejecución local de funciones

Azure Functions Core Tools le permite ejecutar un proyecto de Azure Functions en el equipo de desarrollo local. Al presionar F5 para depurar un proyecto de Functions, el host de Functions local (func.exe) comienza a escuchar en un puerto local (normalmente 7071). Los puntos de conexión de función a los que se puede llamar se escriben en la salida y puede usarlos para probar las funciones. Para más información, consulte Uso de Azure Functions Core Tools. La primera vez que inicie una función desde Visual Studio Code se le solicitará que instale estas herramientas.

Para iniciar la función en Visual Studio en modo de depuración, haga lo siguiente:

  1. Presione F5. Si se le solicita, acepte la solicitud de Visual Studio para descargar e instalar las herramientas de Azure Functions Core (CLI). También es preciso que habilite una excepción de firewall para que las herramientas para controlen las solicitudes de HTTP.

  2. Con el proyecto en ejecución, pruebe el código como probaría una función implementada.

    Cuando Visual Studio se ejecuta en modo de depuración, los puntos de interrupción se alcanzan de la forma esperada.

Para obtener un escenario de prueba más detallado mediante Visual Studio, consulte Funciones de prueba.

Publicación en Azure

Al publicar el proyecto de Functions en Azure, Visual Studio usa la implementación con archivos .zip para implementar los archivos del proyecto. Cuando sea posible, también debe seleccionar Ejecutar desde el paquete para que el proyecto se ejecute en el paquete de implementación (.zip). Para más información, consulte Ejecución de las funciones desde un archivo de paquete en Azure.

No implemente en Azure Functions con Web Deploy (msdeploy).

Siga estos pasos para publicar el proyecto en una aplicación de funciones de Azure.

  1. En el Explorador de soluciones, haga clic con el botón derecho en el proyecto y seleccione Publicar. En Destino, seleccione Azure y, luego, Siguiente.

    Screenshot of publish window.

  2. Seleccione la opción Aplicación de funciones de Azure (Windows) en la pestaña Destino específico. Esta opción creará una aplicación de funciones que se ejecutará en Windows. Después, seleccione el botón Siguiente.

    Screenshot of publish window with specific target.

  3. En Instancia de la función, seleccione Crear una aplicación de Azure Functions...

    Screenshot of create a new function app instance.

  4. Crear una nueva instancia con los valores especificados en la tabla siguiente:

    Configuración valor Descripción
    Nombre Nombre único globalmente Nombre que identifica de forma única la nueva aplicación de función. Acepte este nombre o escriba uno nuevo. Los caracteres válidos son a-z, 0-9 y -.
    Suscripción Su suscripción La suscripción de Azure que se va a usar. Acepte esta suscripción o seleccione una nueva en la lista desplegable.
    Grupo de recursos Nombre del grupo de recursos Nombre del grupo de recursos en el que quiere crear la aplicación de funciones. Seleccione Nuevo para crear un nuevo grupo de recursos. También puede elegir un grupo de recursos existente en la lista desplegable.
    Tipo de plan Consumo Cuando publique el proyecto en una aplicación de funciones que se ejecute en un plan Consumo, solo pagará por las ejecuciones de la aplicación. Otros planes de hospedaje suponen costos más elevados.
    Ubicación Ubicación de la instancia de App Service Elija una ubicación en una región próxima a usted o a otros servicios a los que las funciones accedan.
    Azure Storage Cuenta de almacenamiento de uso general El runtime de Functions necesita una cuenta de almacenamiento de Azure. Seleccione Nueva para configurar una cuenta de almacenamiento de uso general. También puede elegir una cuenta existente que cumpla los requisitos de la cuenta de almacenamiento.
    Application Insights Instancia de Application Insights Debe habilitar la integración de Application Insights para la aplicación de funciones. Seleccione Nuevo para crear una nueva instancia, ya sea en un área de trabajo de Log Analytics nueva o en una existente. También puede elegir una cuenta existente.

    Screenshot of Create App Service dialog.

  5. Seleccione Crear para crear una aplicación de funciones y sus recursos relacionados en Azure. El estado de la creación del recurso se muestra en la parte inferior izquierda de la ventana.

  6. En la instancia de Functions, asegúrese de que Ejecutar desde el archivo de paquete esté activado. La aplicación de funciones se implementa con la implementación de un archivo zip y con el modo de ejecución desde el paquete habilitado. La implementación de archivo ZIP es el método de implementación recomendado para el proyecto de Functions, ya que se obtiene un mejor rendimiento.

    Screenshot of Finish profile creation.

  7. Seleccione Finalizary, en la página Publicar, seleccione Publicar para implementar el paquete que contiene los archivos de proyecto en la nueva aplicación de funciones en Azure.

    Una vez finalizada la implementación, en la pestaña Publicar aparecerá la dirección URL raíz de la aplicación de funciones de Azure.

  8. En la pestaña Publicar, en la sección Hospedaje, elija Abrir en Azure Portal. Esto abre el recurso de Azure de aplicación de funciones nuevo en Azure Portal.

    Screenshot of Publish success message.

Configuración de Function App

Visual Studio no carga automáticamente esta configuración cuando publica el proyecto. Todos los valores que agregue a local.settings.json también se deben agregar a la aplicación de funciones en Azure.

La manera más sencilla de cargar la configuración necesaria en la aplicación de funciones en Azure consiste en expandir los tres puntos situados junto a la sección Hospedaje y seleccionar el vínculo Administrar la configuración de Azure App Service que aparece después de publicar correctamente el proyecto.

Settings in Publish window

Al seleccionar este vínculo se muestra el cuadro de diálogo Configuración de la aplicación para la aplicación de funciones, donde puede agregar una configuración de la aplicación nueva o modificar las existentes.

Application settings

Local muestra un valor de configuración en el archivo local.settings.json y Remoto un valor actual de la aplicación de funciones de Azure. Elija Agregar configuración para crear una nueva configuración de aplicación. Use el vínculo Insertar un valor desde Local para copiar un valor de configuración para el campo Remoto. Los cambios pendientes se escriben en el archivo de configuración local y la aplicación de función cuando se selecciona Aceptar.

Nota

De forma predeterminada, el archivo local.settings.json no se ha insertado en el control de código fuente. Esto significa que si clona un proyecto de Functions local desde el control de código fuente, el proyecto no tiene el archivo local.settings.json. En este caso, debe crear manualmente el archivo local.settings.json en la raíz del proyecto para que el cuadro de diálogo Configuración de la aplicación funcione según lo previsto.

También puede administrar la configuración de la aplicación en una de estas otras maneras:

Depuración remota

Para depurar la aplicación de funciones de forma remota, es preciso publicar una configuración de depuración del proyecto. También debe habilitar la depuración remota en la aplicación de funciones en Azure.

En esta sección se supone que ya ha publicado en la aplicación de funciones mediante una configuración de versión.

Consideraciones sobre la depuración remota

  • No se recomienda la depuración remota en servicios de producción.
  • Si la depuración de Solo mi código está habilitada, deshabilítela.
  • Evite detenciones prolongadas en los puntos de interrupción durante la depuración remota. Azure considera un proceso detenido durante más de unos minutos como un proceso sin respuesta y lo apaga.
  • Mientras realiza la depuración, el servidor envía datos a Visual Studio, lo que podría afectar a los cargos de ancho de banda. Para obtener información acerca de las tarifas de ancho de banda, consulte Precios de Azure.
  • La depuración remota se deshabilita automáticamente en la aplicación de funciones después de las 48 horas. A las 48 horas, habrá que volver a habilitarla.

Asociar el depurador

La forma en que se conecta el depurador depende del modo de ejecución. Si se depura una aplicación de proceso de trabajo aislado, actualmente es preciso asociar el depurador remoto a un proceso de .NET independiente y se requieren otros pasos de configuración.

Al terminar, es preciso deshabilitar la depuración remota.

Para conectar un depurador remoto a una aplicación de funciones que se ejecuta en un proceso independiente del host de Functions:

  1. En la pestaña Publicar, seleccione los puntos suspensivos (...) en la sección Hosting y, después, elija Descargar perfil de publicación. Esta acción descarga una copia del perfil de publicación y abre la ubicación de descarga. Necesita este archivo, que contiene las credenciales usadas para conectarse al proceso de trabajo aislado que se ejecuta en Azure.

    Precaución

    El archivo .publishsettings contiene las credenciales (sin codificar) que se usan para administrar una aplicación de funciones. El procedimiento recomendado para este archivo consiste en almacenarlo temporalmente fuera de los directorios de origen (por ejemplo en la carpeta Bibliotecas\Documentos) y, después, eliminarlo cuando deje de ser necesario. Un usuario malintencionado que obtuviera acceso al archivo .publishsettings podría modificar, crear y eliminar su aplicación de funciones.

  2. Una vez más, en la pestaña Publicar, seleccione los puntos suspensivos (...) en la sección Hosting y, después, elija Adjuntar depurador.

    Screenshot of attaching the debugger from Visual Studio.

    Visual Studio se conecta a la aplicación de funciones y habilita la depuración remota, en caso de que aún no esté habilitada.

    Nota:

    Dado que el depurador remoto no se puede conectar al proceso de host, podría ver un error. En cualquier caso, la depuración predeterminada no se dividirá en el código.

  3. De nuevo en Visual Studio, copie la dirección URL de Sitio en Hosting en la página Publicar.

  4. En el menú Depurar, seleccione Asociar al proceso y, en la ventana Asociar al proceso, pegue la dirección URL en Destino de la conexión, quite https:// y anexe el puerto :4024.

    Compruebe que el destino se parece a este <FUNCTION_APP>.azurewebsites.net:4024 y presione Entrar.

    Visual Studio attach to process dialog

  5. Si se le solicita, permita que Visual Studio acceda a través de un firewall local.

  6. Cuando se le pidan credenciales, en lugar de las credenciales de usuario local, elija otra cuenta (Más opciones en Windows). Especifique los valores de userName y userPWD del perfil publicado en Dirección de correo electrónico y Contraseña en el cuadro de diálogo de autenticación en Windows. Una vez establecida una conexión segura con el servidor de implementación, se muestran los procesos disponibles.

    Visual Studio enter credential

  7. Active Mostrar proceso de todos los usuarios y, después, elija dotnet.exe y seleccione Adjuntar. Cuando se completa la operación, se adjunta al código de la biblioteca de clases de C# que se ejecuta en un proceso de trabajo aislado. En este momento, puede depurar la aplicación de funciones de forma normal.

Para conectar un depurador remoto a una aplicación de funciones que se ejecuta en proceso con el host de Functions:

  • En la pestaña Publicar, seleccione los puntos suspensivos (...) en la sección Hosting y, después, elija Adjuntar depurador.

    Screenshot of attaching the debugger from Visual Studio.

Visual Studio se conecta a la aplicación de funciones y habilita la depuración remota, en caso de que aún no esté habilitada. También localiza y conecta el depurador al proceso de host de la aplicación. En este momento, puede depurar la aplicación de funciones de forma normal.

Deshabilitar la depuración remota

Cuando haya terminado de depurar el código de forma remota, debe deshabilitar la depuración remota en Azure Portal. La depuración remota se deshabilita automáticamente a las de 48 horas, por si se le olvida hacerlo.

  1. En la pestaña Publicar del proyecto, seleccione los puntos suspensivos (...) en la sección Hosting y elija Abrir en Azure Portal. Esta acción abre la aplicación de funciones en la instancia de Azure Portal en que se implementa el proyecto.

  2. En la aplicación de funciones, seleccione Configuración en Configuración, elija Configuración general, establezca Depuración remota en Desactivado y, después, seleccione Guardar y Continuar.

Una vez que se reinicie la aplicación de funciones, no podrá conectarse de forma remota a los procesos remotos. Puede usar esta misma pestaña en Azure Portal para habilitar la depuración remota fuera de Visual Studio.

Supervisión de funciones

La forma recomendada de supervisar la ejecución de las funciones es mediante la aplicación de función con Azure Application Insights. Debe habilitar esta integración al crear la aplicación de funciones durante la publicación de Visual Studio.

Si por algún motivo la integración no se realizó durante la publicación, debe habilitar la integración de Application Insights para la aplicación de funciones en Azure.

Para obtener más información sobre la supervisión mediante Application Insights, consulte Supervisión de Azure Functions.

Funciones de prueba

En esta sección se describe cómo crear un proyecto de modelo en proceso para C# que puede probar con xUnit.

Testing Azure Functions with C# in Visual Studio

1. Instalación

Siga estos pasos para configurar el entorno, incluido el proyecto de aplicación y las funciones, necesarios para admitir las pruebas:

  1. Cree una nueva aplicación de Functions y asígnele el nombre Functions.
  2. Cree una función HTTP a partir de la plantilla y asígnele el nombre MyHttpTrigger.
  3. Cree una función de temporizador a partir de la plantilla y asígnele el nombre MyTimerTrigger.
  4. Cree una aplicación de prueba en xUnit en la solución y asígnele el nombre Functions.Test. Quite los archivos de prueba predeterminados.
  5. Use NuGet para agregar referencias desde la aplicación de prueba a Microsoft.AspNetCore.Mvc
  6. Haga referencia a la aplicación Functions desde la aplicación Functions.Tests.

Ahora que se han creado los proyectos, puede crear las clases usadas para ejecutar las pruebas automatizadas.

2. Crear clases de prueba

Cada función toma una instancia de ILogger para controlar el registro de mensajes. Algunas pruebas no registran los mensajes o no tiene que preocuparse por cómo se implementa el registro. Otras pruebas deben evaluar los mensajes registrados para determinar si están pasando una prueba.

  1. Cree una clase denominada ListLogger que contenga una lista interna de los mensajes que se evaluarán durante las pruebas. Para implementar la interfaz de ILogger necesaria, la clase necesita un ámbito. La siguiente clase simula un ámbito para los casos de prueba que se van a pasar a la clase ListLogger.

  2. Cree una nueva clase en el proyecto Functions.Tests denominada NullScope.cs y agregue este código:

    using System;
    
    namespace Functions.Tests
    {
        public class NullScope : IDisposable
        {
            public static NullScope Instance { get; } = new NullScope();
    
            private NullScope() { }
    
            public void Dispose() { }
        }
    }
    
  3. Cree una clase en el proyecto Functions.Tests denominada ListLogger.cs y agregue este código:

    using Microsoft.Extensions.Logging;
    using System;
    using System.Collections.Generic;
    using System.Text;
    
    namespace Functions.Tests
    {
        public class ListLogger : ILogger
        {
            public IList<string> Logs;
    
            public IDisposable BeginScope<TState>(TState state) => NullScope.Instance;
    
            public bool IsEnabled(LogLevel logLevel) => false;
    
            public ListLogger()
            {
                this.Logs = new List<string>();
            }
    
            public void Log<TState>(LogLevel logLevel,
                                    EventId eventId,
                                    TState state,
                                    Exception exception,
                                    Func<TState, Exception, string> formatter)
            {
                string message = formatter(state, exception);
                this.Logs.Add(message);
            }
        }
    }
    

    La clase ListLogger implementa los siguientes miembros según los contrata la interfaz ILogger:

    • BeginScope: Los ámbitos agregan contexto al registro. En este caso, la prueba simplemente apunta a la instancia estática en la clase NullScope para permitir la prueba de la función.

    • IsEnabled: Se proporciona un valor predeterminado de false.

    • Log: Este método usa la función formatter proporcionada para dar formato al mensaje y, a continuación, agrega el texto resultante a la colección Logs.

    La colección Logs es una instancia de List<string> y se inicializa en el constructor.

  4. Cree un archivo de código en el proyecto Functions.Tests denominado LoggerTypes.cs y agregue este código:

    namespace Functions.Tests
    {
        public enum LoggerTypes
        {
            Null,
            List
        }
    }
    

    Esta enumeración especifica el tipo de registrador utilizado por las pruebas.

  5. Cree una clase en el proyecto Functions.Tests denominada TestFactory.cs y agregue este código:

    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Http.Internal;
    using Microsoft.Extensions.Logging;
    using Microsoft.Extensions.Logging.Abstractions;
    using Microsoft.Extensions.Primitives;
    using System.Collections.Generic;
    
    namespace Functions.Tests
    {
        public class TestFactory
        {
            public static IEnumerable<object[]> Data()
            {
                return new List<object[]>
                {
                    new object[] { "name", "Bill" },
                    new object[] { "name", "Paul" },
                    new object[] { "name", "Steve" }
    
                };
            }
    
            private static Dictionary<string, StringValues> CreateDictionary(string key, string value)
            {
                var qs = new Dictionary<string, StringValues>
                {
                    { key, value }
                };
                return qs;
            }
    
            public static HttpRequest CreateHttpRequest(string queryStringKey, string queryStringValue)
            {
                var context = new DefaultHttpContext();
                var request = context.Request;
                request.Query = new QueryCollection(CreateDictionary(queryStringKey, queryStringValue));
                return request;
            }
    
            public static ILogger CreateLogger(LoggerTypes type = LoggerTypes.Null)
            {
                ILogger logger;
    
                if (type == LoggerTypes.List)
                {
                    logger = new ListLogger();
                }
                else
                {
                    logger = NullLoggerFactory.Instance.CreateLogger("Null Logger");
                }
    
                return logger;
            }
        }
    }
    

    La clase TestFactory implementa los siguientes miembros:

    • Data: Esta propiedad devuelve una colección IEnumerable de datos de ejemplo. Los pares clave-valor representan los valores que se pasan en una cadena de consulta.

    • CreateDictionary: Este método acepta un par clave-valor como argumento y devuelve un Dictionary nuevo usado para crear QueryCollection para representar los valores de cadena de consulta.

    • CreateHttpRequest: Este método crea una solicitud HTTP que se inicializa con los parámetros de cadena de consulta indicados.

    • CreateLogger: Según el tipo de registrador, este método devuelve una clase de registrador que se usa para las pruebas. ListLogger realiza un seguimiento de los mensajes registrados disponibles para su evaluación en las pruebas.

  6. Cree una clase en el proyecto Functions.Tests denominada FunctionsTests.cs y agregue este código:

    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Logging;
    using Xunit;
    
    namespace Functions.Tests
    {
        public class FunctionsTests
        {
            private readonly ILogger logger = TestFactory.CreateLogger();
    
            [Fact]
            public async void Http_trigger_should_return_known_string()
            {
                var request = TestFactory.CreateHttpRequest("name", "Bill");
                var response = (OkObjectResult)await MyHttpTrigger.Run(request, logger);
                Assert.Equal("Hello, Bill. This HTTP triggered function executed successfully.", response.Value);
            }
    
            [Theory]
            [MemberData(nameof(TestFactory.Data), MemberType = typeof(TestFactory))]
            public async void Http_trigger_should_return_known_string_from_member_data(string queryStringKey, string queryStringValue)
            {
                var request = TestFactory.CreateHttpRequest(queryStringKey, queryStringValue);
                var response = (OkObjectResult)await MyHttpTrigger.Run(request, logger);
                Assert.Equal($"Hello, {queryStringValue}. This HTTP triggered function executed successfully.", response.Value);
            }
    
            [Fact]
            public void Timer_should_log_message()
            {
                var logger = (ListLogger)TestFactory.CreateLogger(LoggerTypes.List);
                new MyTimerTrigger().Run(null, logger);
                var msg = logger.Logs[0];
                Assert.Contains("C# Timer trigger function executed at", msg);
            }
        }
    }
    

    Los miembros implementados en esta clase son:

    • Http_trigger_should_return_known_string: Esta prueba crea una solicitud con los valores de la cadena de consulta de name=Bill en una función HTTP y comprueba que se devuelve la respuesta esperada.

    • Http_trigger_should_return_string_from_member_data: Esta prueba usa atributos de xUnit para proporcionar datos de ejemplo a la función HTTP.

    • Timer_should_log_message: esta prueba crea una instancia de ListLogger y la pasa a una función de temporizador. Una vez que se ejecuta la función, se comprueba el registro para garantizar que el mensaje esperado está presente.

  7. Para acceder a la configuración de la aplicación en las pruebas, puede insertar una instancia de IConfiguration con valores de variables de entorno simuladas en la función.

3. Ejecución de las pruebas

Para ejecutar las pruebas, vaya al Explorador de pruebas y seleccione Ejecutar todas las pruebas en la vista.

Testing Azure Functions with C# in Visual Studio

4. Depuración de pruebas

Para depurar las pruebas, establezca un punto de interrupción en una prueba, vaya al Explorador de pruebas y seleccione Ejecutar > Última ejecución de depuración.

Pasos siguientes

Para obtener más información sobre Azure Functions Core Tools,vea Uso de Azure Functions Core Tools.