Conexión de Azure Functions a Azure Storage mediante herramientas de línea de comandos
En este artículo, integrará una cola de Azure Storage con la función y la cuenta de almacenamiento que creó en el artículo de inicio rápido anterior. Para lograr esta integración se usa un enlace de salida que escribe los datos de una solicitud HTTP en un mensaje de la cola. Completar este artículo no supone ningún costo adicional sobre el pequeño importe del inicio rápido anterior. Para más información acerca de los enlaces, consulte Conceptos básicos sobre los enlaces y desencadenadores de Azure Functions.
Configuración del entorno local
Antes de empezar, debe completar el artículo Inicio rápido: Creación de un proyecto de Azure Functions desde la línea de comandos. Si ya ha limpiado los recursos al final de ese artículo, vuelva a recorrer los pasos para crear de nuevo la aplicación de función y los recursos relacionados en Azure.
Antes de empezar, debe completar el artículo Inicio rápido: Creación de un proyecto de Azure Functions desde la línea de comandos. Si ya ha limpiado los recursos al final de ese artículo, vuelva a recorrer los pasos para crear de nuevo la aplicación de función y los recursos relacionados en Azure.
Antes de empezar, debe completar el artículo Inicio rápido: Creación de un proyecto de Azure Functions desde la línea de comandos. Si ya ha limpiado los recursos al final de ese artículo, vuelva a recorrer los pasos para crear de nuevo la aplicación de función y los recursos relacionados en Azure.
Antes de empezar, debe completar el artículo Inicio rápido: Creación de un proyecto de Azure Functions desde la línea de comandos. Si ya ha limpiado los recursos al final de ese artículo, vuelva a recorrer los pasos para crear de nuevo la aplicación de función y los recursos relacionados en Azure.
Antes de empezar, debe completar el artículo Inicio rápido: Creación de un proyecto de Azure Functions desde la línea de comandos. Si ya ha limpiado los recursos al final de ese artículo, vuelva a recorrer los pasos para crear de nuevo la aplicación de función y los recursos relacionados en Azure.
Antes de empezar, debe completar el artículo Inicio rápido: Creación de un proyecto de Azure Functions desde la línea de comandos. Si ya ha limpiado los recursos al final de ese artículo, vuelva a recorrer los pasos para crear de nuevo la aplicación de función y los recursos relacionados en Azure.
Recuperación de la cadena de conexión de Azure Storage
Anteriormente, creó una cuenta de Azure Storage para que la aplicación de funciones la utilizara. La cadena de conexión de esta cuenta se almacena de forma segura en la configuración de la aplicación en Azure. Mediante la descarga de la configuración en el archivo local.settings.json, puede usar esa conexión para escribir en una cola de Storage de la misma cuenta cuando ejecute la función de forma local.
En la raíz del proyecto, ejecute el comando siguiente, reemplazando
<APP_NAME>por el nombre de la aplicación de funciones del inicio rápido anterior. Este comando sobrescribirá los valores existentes en el archivo.func azure functionapp fetch-app-settings <APP_NAME>Abra local.settings.json y busque el valor denominado
AzureWebJobsStorage, que es la cadena de conexión de la cuenta de almacenamiento. Usará el nombreAzureWebJobsStoragey la cadena de conexión en otras secciones de este artículo.
Importante
Como local.settings.json contiene secretos descargados de Azure, excluya siempre este archivo del control de código fuente. El archivo .gitignore que se creó con un proyecto de Functions local excluye el archivo de forma predeterminada.
Registro de extensiones de enlace
A excepción de los desencadenadores HTTP y el temporizador, los enlaces se implementan como paquetes de extensión. Ejecute el siguiente comando dotnet add package en la ventana Terminal para agregar el paquete de extensión de Storage al proyecto.
dotnet add package Microsoft.Azure.WebJobs.Extensions.Storage
Ahora podrá agregar el enlace de salida de almacenamiento al proyecto.
Incorporación de una definición de enlace de salida a la función
Aunque ninguna de las funciones puede tener más de un desencadenador, puede tener varios enlaces de entrada y salida que le permiten conectarse a otros servicios y recursos de Azure sin escribir código de integración personalizado.
Estos enlaces se declaran en el archivo function.json en la carpeta de la función. En el inicio rápido anterior, el archivo function.json de la carpeta HttpExample contiene dos enlaces en la colección bindings:
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "res"
}
]
"scriptFile": "__init__.py",
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "$return"
}
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "Request",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "Response"
}
]
Cada enlace tiene al menos un tipo, una dirección y un nombre. En el ejemplo anterior, el primer enlace es del tipo httpTrigger con la dirección in. En el caso de la dirección in, name especifica el nombre de un parámetro de entrada que se envía a la función cuando la invoca el desencadenador.
El segundo enlace de la colección se denomina res. Este enlace http es un enlace de salida (out) que se usa para escribir la respuesta HTTP.
Para escribir en una cola de Azure Storage desde esta función, agregue un enlace out del tipo queue con el nombre msg, como se muestra en el código siguiente:
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "res"
},
{
"type": "queue",
"direction": "out",
"name": "msg",
"queueName": "outqueue",
"connection": "AzureWebJobsStorage"
}
]
}
El segundo enlace de la colección es de tipo http con la dirección out, en cuyo caso la variable name especial de $return indica que este enlace usa el valor devuelto de la función, en lugar de proporcionar un parámetro de entrada.
Para escribir en una cola de Azure Storage desde esta función, agregue un enlace out del tipo queue con el nombre msg, como se muestra en el código siguiente:
"bindings": [
{
"authLevel": "anonymous",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "$return"
},
{
"type": "queue",
"direction": "out",
"name": "msg",
"queueName": "outqueue",
"connection": "AzureWebJobsStorage"
}
]
El segundo enlace de la colección se denomina res. Este enlace http es un enlace de salida (out) que se usa para escribir la respuesta HTTP.
Para escribir en una cola de Azure Storage desde esta función, agregue un enlace out del tipo queue con el nombre msg, como se muestra en el código siguiente:
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "Request",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "Response"
},
{
"type": "queue",
"direction": "out",
"name": "msg",
"queueName": "outqueue",
"connection": "AzureWebJobsStorage"
}
]
}
En este caso, msg se asigna a la función como argumento de salida. En el caso de un tipo queue, también debe especificar el nombre de la cola en queueName y proporcionar el nombre de la conexión Azure Storage (desde local.settings.json) en connection.
En un proyecto de C#, los enlaces se definen como atributos de enlace en el método de función. Las definiciones específicas dependen de si la aplicación se ejecuta dentro de proceso (biblioteca de clases de C#) o en un proceso aislado.
Abra el archivo de proyecto HttpExample.cs y agregue el parámetro siguiente a la definición del método Run:
[Queue("outqueue"),StorageAccount("AzureWebJobsStorage")] ICollector<string> msg,
El parámetro msg es de tipo ICollector<T>, que representa una colección de mensajes escritos en un enlace de salida cuando se completa la función. En este caso, la salida es una cola de almacenamiento denominada outqueue. La cadena de conexión de la cuenta de Storage la establece StorageAccountAttribute. Este atributo indica la configuración que contiene la cadena de conexión de la cuenta de Storage y se puede aplicar en el nivel de clase, método o parámetro. En este caso, puede omitir StorageAccountAttribute, puesto que ya está usando la cuenta de almacenamiento predeterminada.
La definición del método Run debe ahora parecerse a la siguiente:
[FunctionName("HttpExample")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
[Queue("outqueue"),StorageAccount("AzureWebJobsStorage")] ICollector<string> msg,
ILogger log)
En un proyecto de Java, los enlaces se definen como anotaciones de enlace en el método de función. Entonces, el archivo function.json se genera automáticamente en función de estas anotaciones.
Vaya a la ubicación del código de función en src/main/java, abra el archivo de proyecto Function.java y agregue el parámetro siguiente a la definición del método run:
@QueueOutput(name = "msg", queueName = "outqueue", connection = "AzureWebJobsStorage") OutputBinding<String> msg
El parámetro msg es de tipo OutputBinding<T>, que representa una colección de cadenas escritas como mensajes en un enlace de salida cuando se completa la función. En este caso, la salida es una cola de almacenamiento denominada outqueue. La cadena de conexión de la cuenta de Storage la establece el método connection. En lugar de la propia cadena de conexión, el usuario se encarga de pasar la configuración de la aplicación que contiene la cadena de conexión de la cuenta de Storage.
La definición del método run debe ahora parecerse a la del siguiente ejemplo:
@FunctionName("HttpTrigger-Java")
public HttpResponseMessage run(
@HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.FUNCTION)
HttpRequestMessage<Optional<String>> request,
@QueueOutput(name = "msg", queueName = "outqueue", connection = "AzureWebJobsStorage")
OutputBinding<String> msg, final ExecutionContext context) {
...
}
Para más información sobre los enlaces, consulte Conceptos básicos sobre los enlaces y desencadenadores de Azure Functions y configuración de la cola de salida.
Adición de código para usar el enlace de salida
Con el enlace de cola definido, ahora puede actualizar la función para que reciba el parámetro de salida msg y escribir mensajes en la cola.
Actualice HttpExample\__init__.py para que se ajuste al siguiente código y agregue el parámetro msg a la definición de la función y msg.set(name) en la instrucción if name:.
import logging
import azure.functions as func
def main(req: func.HttpRequest, msg: func.Out[func.QueueMessage]) -> str:
name = req.params.get('name')
if not name:
try:
req_body = req.get_json()
except ValueError:
pass
else:
name = req_body.get('name')
if name:
msg.set(name)
return func.HttpResponse(f"Hello {name}!")
else:
return func.HttpResponse(
"Please pass a name on the query string or in the request body",
status_code=400
)
El parámetro msg es una instancia de azure.functions.Out class. Su método set escribe un mensaje de cadena en la cola; en este caso, el nombre que se pasa a la función en la cadena de consulta de la dirección URL.
Agregue código que utilice el objeto de enlace de salida msg en context.bindings para crear un mensaje de la cola. Agregue este código antes de la instrucción context.res.
// Add a message to the Storage queue,
// which is the name passed to the function.
context.bindings.msg = (req.query.name || req.body.name);
En este momento, la función debe tener el aspecto siguiente:
module.exports = async function (context, req) {
context.log('JavaScript HTTP trigger function processed a request.');
if (req.query.name || (req.body && req.body.name)) {
// Add a message to the Storage queue,
// which is the name passed to the function.
context.bindings.msg = (req.query.name || req.body.name);
context.res = {
// status: 200, /* Defaults to 200 */
body: "Hello " + (req.query.name || req.body.name)
};
}
else {
context.res = {
status: 400,
body: "Please pass a name on the query string or in the request body"
};
}
};
Agregue código que utilice el objeto de enlace de salida msg en context.bindings para crear un mensaje de la cola. Agregue este código antes de la instrucción context.res.
context.bindings.msg = name;
En este momento, la función debe tener el aspecto siguiente:
import { AzureFunction, Context, HttpRequest } from "@azure/functions"
const httpTrigger: AzureFunction = async function (context: Context, req: HttpRequest): Promise<void> {
context.log('HTTP trigger function processed a request.');
const name = (req.query.name || (req.body && req.body.name));
if (name) {
// Add a message to the storage queue,
// which is the name passed to the function.
context.bindings.msg = name;
// Send a "hello" response.
context.res = {
// status: 200, /* Defaults to 200 */
body: "Hello " + (req.query.name || req.body.name)
};
}
else {
context.res = {
status: 400,
body: "Please pass a name on the query string or in the request body"
};
}
};
export default httpTrigger;
Agregue código que use el cmdlet Push-OutputBinding para escribir texto en la cola mediante el enlace de salida msg. Agregue este código antes de establecer el estado correcto en la instrucción if.
$outputMsg = $name
Push-OutputBinding -name msg -Value $outputMsg
En este momento, la función debe tener el aspecto siguiente:
using namespace System.Net
# Input bindings are passed in via param block.
param($Request, $TriggerMetadata)
# Write to the Azure Functions log stream.
Write-Host "PowerShell HTTP trigger function processed a request."
# Interact with query parameters or the body of the request.
$name = $Request.Query.Name
if (-not $name) {
$name = $Request.Body.Name
}
if ($name) {
# Write the $name value to the queue,
# which is the name passed to the function.
$outputMsg = $name
Push-OutputBinding -name msg -Value $outputMsg
$status = [HttpStatusCode]::OK
$body = "Hello $name"
}
else {
$status = [HttpStatusCode]::BadRequest
$body = "Please pass a name on the query string or in the request body."
}
# Associate values to output bindings by calling 'Push-OutputBinding'.
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
StatusCode = $status
Body = $body
})
Agregue código que utilice el objeto de enlace de salida msg para crear un mensaje de la cola. Agregue este código antes de la devolución del método.
if (!string.IsNullOrEmpty(name))
{
// Add a message to the output collection.
msg.Add(string.Format("Name passed to the function: {0}", name));
}
En este momento, la función debe tener el aspecto siguiente:
[FunctionName("HttpExample")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
[Queue("outqueue"),StorageAccount("AzureWebJobsStorage")] ICollector<string> msg,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
string name = req.Query["name"];
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
name = name ?? data?.name;
if (!string.IsNullOrEmpty(name))
{
// Add a message to the output collection.
msg.Add(string.Format("Name passed to the function: {0}", name));
}
return name != null
? (ActionResult)new OkObjectResult($"Hello, {name}")
: new BadRequestObjectResult("Please pass a name on the query string or in the request body");
}
Ahora, puede usar el nuevo parámetro msg para escribir en el enlace de salida desde el código de la función. Agregue la siguiente línea de código antes de la respuesta de operación correcta para agregar el valor de name al enlace de salida msg.
msg.setValue(name);
Al usar un enlace de salida, no tiene que usar el código del SDK de Azure Storage para autenticarse, obtener una referencia de cola o escribir datos. El sistema en tiempo de ejecución de Functions y el enlace de salida de cola realizan esas tareas automáticamente.
El método run debe ahora parecerse al del siguiente ejemplo:
public HttpResponseMessage run(
@HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS)
HttpRequestMessage<Optional<String>> request,
@QueueOutput(name = "msg", queueName = "outqueue",
connection = "AzureWebJobsStorage") OutputBinding<String> msg,
final ExecutionContext context) {
context.getLogger().info("Java HTTP trigger processed a request.");
// Parse query parameter
String query = request.getQueryParameters().get("name");
String name = request.getBody().orElse(query);
if (name == null) {
return request.createResponseBuilder(HttpStatus.BAD_REQUEST)
.body("Please pass a name on the query string or in the request body").build();
} else {
// Write the name to the message queue.
msg.setValue(name);
return request.createResponseBuilder(HttpStatus.OK).body("Hello, " + name).build();
}
}
Actualización de las pruebas
Dado que el arquetipo también crea un conjunto de pruebas, debe actualizar estas pruebas para controlar el nuevo parámetro msg en la signatura del método run.
Vaya a la ubicación del código de prueba en src/test/java, abra el archivo de proyecto Function.Java y reemplace la línea de código debajo de //Invoke por el código siguiente.
@SuppressWarnings("unchecked")
final OutputBinding<String> msg = (OutputBinding<String>)mock(OutputBinding.class);
final HttpResponseMessage ret = new Function().run(req, msg, context);
Observe que no necesita escribir código para la autenticación, para obtener una referencia de la cola ni para escribir datos. Todas estas tareas de integración se administran de manera adecuada en el entorno de ejecución de Azure Functions y en el enlace de salida de la cola.
Ejecución local de la función
Para ejecutar una función, inicie el host en tiempo de ejecución local de Azure Functions desde la carpeta LocalFunctionProj:
func startHacia el final de la salida, deberían aparecer las líneas siguientes:
... Now listening on: http://0.0.0.0:7071 Application started. Press Ctrl+C to shut down. Http Functions: HttpExample: [GET,POST] http://localhost:7071/api/HttpExample ...Nota
Si HttpExample no aparece como se ha mostrado arriba, es probable que haya iniciado el host desde fuera de la carpeta raíz del proyecto. En ese caso, use Ctrl+C para detener el host, vaya a la carpeta raíz del proyecto y vuelva a ejecutar el comando anterior.
Copie la dirección URL de la función
HttpExamplede esta salida en un explorador y anexe la cadena de consulta?name=<YOUR_NAME>, lo que hará que la dirección URL completa seahttp://localhost:7071/api/HttpExample?name=Functions. El explorador debe mostrar un mensaje de respuesta que devuelve el valor de la cadena de consulta. El terminal en el que inició el proyecto también muestra la salida del registro cuando realiza solicitudes.Cuando termine, presione Ctrl+C y seleccione
ypara detener el host de Functions.
Sugerencia
Durante el inicio, el host descarga e instala la extensión de enlace de Storage y otras extensiones de enlace de Microsoft. Esta instalación se produce porque las extensiones de enlace se habilitan de forma predeterminada en el archivo host.json con las siguientes propiedades:
{
"version": "2.0",
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[1.*, 2.0.0)"
}
}
Si encuentra algún error relacionado con las extensiones de enlace, compruebe que las propiedades anteriores están presentes en host.json.
Visualización del mensaje en la cola de Azure Storage
La cola se puede ver en Azure Portal o en el Explorador de Microsoft Azure Storage. También puede ver la cola en la CLI de Azure, como se describe en los pasos siguientes:
Abra el archivo local.setting.json del proyecto de Functions y copie el valor de la cadena de conexión. En una ventana de terminal o de comandos, ejecute el siguiente comando para crear una variable de entorno denominada
AZURE_STORAGE_CONNECTION_STRINGy pegue la cadena de conexión concreta en lugar de<MY_CONNECTION_STRING>. (Esta variable de entorno significa que no es necesario proporcionar la cadena de conexión a cada comando posterior mediante el argumento--connection-string).export AZURE_STORAGE_CONNECTION_STRING="<MY_CONNECTION_STRING>"(Opcional) Puede usar el comando
az storage queue listpara ver las colas de Storage de la cuenta. La salida de este comando debe incluir una cola denominadaoutqueue, la cual se creó cuando la función escribió su primer mensaje en esa cola.az storage queue list --output tsvUse el comando
az storage message getpara leer el mensaje de esta cola, que será el primer nombre que usó al probar la función anteriormente. El comando lee y quita el primer mensaje de la cola.echo `echo $(az storage message get --queue-name outqueue -o tsv --query '[].{Message:content}') | base64 --decode`Dado que el cuerpo del mensaje se almacena codificado en Base64, el mensaje se debe descodificar antes de visualizarse. Después de ejecutar
az storage message get, el mensaje se quita de la cola. Si solo había un mensaje enoutqueue, no se recuperará al ejecutar este comando una segunda vez y, en su lugar, recibirá un error.
Nueva implementación del proyecto en Azure
Ahora que ha comprobado localmente que la función escribió un mensaje en la cola de Azure Storage, puede volver a implementar el proyecto para actualizar el punto de conexión que se ejecuta en Azure.
En la carpeta LocalFunctionsProj, use el comando func azure functionapp publish para volver a implementar el proyecto y reemplace<APP_NAME> el nombre de la aplicación.
func azure functionapp publish <APP_NAME>
En la carpeta de proyecto local, use el siguiente comando de Maven para volver a publicar el proyecto:
mvn azure-functions:deploy
Comprobación en Azure
Como en el inicio rápido anterior, use un explorador o CURL para probar la función que ha vuelto a implementar.
Vuelva a examinar la cola de Storage, como se describe en la sección anterior, para comprobar que contiene el nuevo mensaje escrito en la cola.
Limpieza de recursos
Cuando haya terminado, use el siguiente comando para eliminar el grupo de recursos y todos los recursos que contiene para evitar incurrir en costos adicionales.
az group delete --name AzureFunctionsQuickstart-rg
Pasos siguientes
Ha actualizado la función desencadenada por HTTP para escribir datos en una cola de almacenamiento. Ahora puede aprender más sobre el desarrollo de Functions desde la línea de comandos mediante Core Tools y la CLI de Azure:

