Hoy veremos cómo es la estructura básica de archivos de una Azure Function, cómo podemos editar esos archivos y cómo agregamos las librerías que tenemos como dependencias en nuestro código.
Código de la función
Las funciones son el componente principal del servicio de Azure Functions. Escribimos el código de nuestra función en el lenguaje de nuestra preferencia y guardamos el archivo de código junto con la configuración en la misma carpeta.
Archivo de la función en C#
Las funciones en C# se crean en un archivo llamado run.csx. Los archivos .csx, llamados C# Script, nos permiten abstraernos de todo el código repetitivo como los namespaces, las clases y demás, y enfocarnos en el código de nuestra función. Si necesitamos agregar alguna clase que sea usada en nuestro código, podemos agregarla en el mismo archivo.
En el caso de Azure Functions el método que usamos para ejecutar la función es Run:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
public static void Run(TimerInfo myTimer, TraceWriter log) | |
{ | |
log.Info($"Función con trigger por timer en C# ejecutada el {DateTime.Now}"); | |
} |
Archivo de la función en Node.js
Al usar Node.js sólo es necesario declarar una sola función via modules.export
, para que el entorno de ejecución la encuentre y pueda ejecutarla. Esta función siempre debe recibir un objeto context
.
El resto de los parámetros son opcionales:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Se debe incluir el context, pero los otros argumentos son opcionales | |
module.exports = function(context) { | |
// Las variables de entrada adicionales pueden accederse en la propiedad arguments | |
if(arguments.length === 2) { | |
context.log('La función recibió 2 argumentos de entrada'); | |
} | |
}; |
Pero pueden declararse como variables de entrada:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// O se pueden incluir parámetros adicionales como variables de entrada | |
module.exports = function(context, miDisparador, miEntrada, miOtraEntrada) { | |
// la lógica de la función va aquí | |
}; |
Archivo de configuración
La configuración se realiza en formato JSON, en un archivo llamado function.json
.
En el archivo function.json se guarda la información específica de una función, incluyendo sus bindings. El entorno de ejecución lee este archivo para saber con qué eventos dispararla, qué parámetros se incluyen en el llamado a la función, y a dónde enviar los datos de salida de la misma.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"disabled":false, | |
"bindings":[ | |
// aquí van los bindings | |
{ | |
"type": "bindingType", | |
"direction": "in", | |
"name": "myParamName", | |
// … más, dependiendo del binding … | |
} | |
] | |
} |
Es posible deshabilitar la ejecución de una función seteando el parámetro disabled
en true
.
Dentro del listado de bindings
es que se configuran los triggers y los bindings. Todos los bindings comparten algunas de las propiedades, y otras son específicas de cada tipo de binding. Las que son obligatorias para todos los tipos son:
Propiedad | Valores/Tipos | Comentarios |
---|---|---|
type |
string | Tipo de binding. Por ejemplo: queueTrigger . |
direction |
‘in’, ‘out’ | Indica si el binding es para recibir datos en la función (in) o para enviar datos desde la función (out). |
name |
string | El nombre que se usará para los datos enlazados a la función. En C# este será el nombre del argumento; en JavaScript será la key en una lista de key/value. |
Estructura de carpetas
El código de todas las funciones se encuentra en la carpeta raíz que contiene el archivo con la configuración del host y una o más subcarpetas, cada una de las cuales contiene el código de una función individual:
wwwroot | - host.json | - mifuncionnode | | - function.json | | - index.js | | - node_modules | | | - ... packages ... | | - package.json | - mifuncioncsharp | | - function.json | | - run.csx
El archivo host.json
contiene configuración específica del entorno de ejecución y se encuentra en la raíz de la aplicación.
Cada función tiene una carpeta, con uno o más archivos de código, el archivo de configuración function.json
y otras dependencias.
Cuando preparamos nuestro proyecto para hacer un deploy de nuestras funciones en el servicio de Azure Functions, podemos usar esta jerarquía de carpetas como la estructura de nuestro sitio. Y podemos usar las herramientas de integración continua o despliegue que estamos acostumbrados con los otros servicios de Azure App Service.
¿Cómo actualizamos los archivos?
La opción más simple, aunque obviamente también más limitada, es la de editar el código directamente desde el editor de código disponible en el Portal de Azure, aunque esto sólo nos permite editar el código de la Function y el archivo de configuración function.json
.
Si necesitamos, por ejemplo, agregar una dependencia, y por lo tanto, un archivo project.json
para nuestro código C# o package.json
para Node.js, podemos subirlo usando la interfaz de Kudu, o editar nuestro código de manera local, con nuestro editor preferido, y luego subirlos de la misma forma que subimos una Web App: con WebDeploy, FTP o configurando la integración continua desde nuestro repositorio de código.
Un detalle a tener en cuenta es que una vez que habilitamos la integración continua de nuestro código no podremos volver a editarlo desde el portal, ya que entrará en modo de sólo lectura.
Agregando dependencias
Para código C#
Para hacer referencia a una librería simplemente usamos una cláusula using
, como en cualquier código en C#.
using System;
Hay algunas librerías que ya vienen incorporadas al servicio, y pueden usarse en forma directa, simplemente agregando el using
:
mscorlib
System
System.Core
System.Xml
System.Net.Http
Microsoft.Azure.WebJobs
Microsoft.Azure.WebJobs.Host
Microsoft.Azure.WebJobs.Extensions
System.Web.Http
System.Net.Http.Formatting
Otras ya están instaladas, pero deben referenciarse primero usando #r "NombreDelAssembly"
(Ej.: #r "Microsoft.WindowsAzure.Storage"
):
Newtonsoft.Json
Microsoft.WindowsAzure.Storage
Microsoft.ServiceBus
Microsoft.AspNet.WebHooks.Receivers
Microsoft.AspNet.WebHooks.Common
También podemos instalar paquetes desde NuGet usando un archivo project.json
.
El archivo project.json
tiene el siguiente formato:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"frameworks": { | |
"net46":{ | |
"dependencies": { | |
"Microsoft.Azure.Search": "2.0.4-preview" | |
} | |
} | |
} | |
} |
Es importante notar que la única versión soportada del .Net Framework es la 4.6, así que no hay que olvidarse de especificar net46
. También hay que saber que al agregar los paquetes a través de NuGet no es necesario instanciarlo con #r "NombreDeAssembly"
, simplemente agregamos el using
.
O, finalmente, también podemos instalar una librería propia, copiándola en una carpeta bin
, dentro de la carpeta de la función, y llamándola usando #r "MiAssembly.dll"
.
Para código Node.js
La versión actual de Node.js sobre la que corren nuestras funciones es la 6.4.0.
Se pueden instalar paquetes usando un archivo package.json
dentro de la carpeta de la función. También podemos ejecutar npm install
desde la interfaz de comandos de Kudu, y luego los importamos usando require
:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Importamos la librería underscore.js | |
var _ = require('underscore'); | |
module.exports = function(context) { | |
// Usamos la librería underscore.js que importamos | |
var matched_names = _ | |
.where(context.bindings.myInput.names, {first: 'Juan'}); | |
// El resto del código de nuestra función | |
} |
Próximos pasos:
Aprende más sobre Azure Functions con el Curso de Introducción a Azure Functions con C# creado por JuanK Ruiz (@JuanKRuiz) en {NetUniversity}.