Guía para ejecutar Azure Functions en C# en el modelo de trabajo aislado
Este artículo es una introducción al trabajo con Azure Functions en .NET mediante el modelo de trabajo aislado. Este modelo permite que el proyecto tenga como destino versiones de .NET independientemente de otros componentes en tiempo de ejecución. Para obtener información sobre las versiones específicas de .NET admitidas, consulte versión compatible.
Use los vínculos siguientes para empezar a compilar de inmediato funciones de modelo de trabajo aislado de .NET.
Introducción | Conceptos | Ejemplos |
---|---|---|
Para obtener información sobre cómo implementar un proyecto de modelo de trabajo aislado en Azure, consulte Implementación en Azure Functions.
Ventajas del modelo de trabajo aislado
Existen dos modos en los que puede ejecutar las funciones de su biblioteca de clases .NET: o bien en el mismo proceso que el runtime del host de funciones (in-process) o en un proceso de trabajo aislado. Cuando las funciones de .NET se ejecutan en un proceso de trabajo aislado, puede aprovechar las ventajas siguientes:
- Menos conflictos: dado que las funciones se ejecutan en un proceso independiente, los ensamblados usados en la aplicación no entrarán en conflicto con la versión diferente de los mismos ensamblados que usa el proceso de host.
- Control total del proceso: usted controla la puesta en marcha de la aplicación, lo que significa que puede administrar las configuraciones usadas y el middleware iniciado.
- Inserción de dependencias estándar: dado que tiene control total del proceso, puede usar los comportamientos actuales de .NET para la inserción de dependencias e incorporar middleware a la aplicación de funciones.
- Flexibilidad de versión de .NET: la ejecución fuera del proceso de host significa que las funciones se pueden ejecutar en versiones de .NET no compatibles de forma nativa con el entorno de ejecución de Functions, incluido .NET Framework.
Si tiene una aplicación de funciones de C# existente que se ejecuta en proceso, debe migrar la aplicación para aprovechar estas ventajas. Para más información, consulte Migración de aplicaciones .NET desde el modelo en proceso al modelo de trabajo aislado.
Para ver una comparación exhaustiva entre los dos modelos, consulte Diferencias entre el proceso en proceso y el proceso de trabajo aislado .NET Azure Functions.
Versiones compatibles
Las versiones del tiempo de ejecución de Functions son compatibles con versiones específicas de .NET. Para obtener más información sobre las versiones de Functions, consulte Introducción a las versiones de tiempo de ejecución de Azure Functions. La compatibilidad con versiones depende de si las funciones se ejecutan en proceso o como proceso de trabajo aislado.
Nota
Para aprender a cambiar la versión del runtime de Functions que usa la aplicación de funciones, consulte la sesión Visualización y actualización de la versión actual del entorno de ejecución.
En la tabla siguiente, se muestra el nivel más alto de .NET o .NET Framework que se puede usar con una versión específica de Functions.
Versiones del entorno en tiempo de ejecución de Functions | Modelo de trabajo aislado | Modelo In-Process4 |
---|---|---|
Functions 4.x1 | .NET 9.0 .NET 8.0 .NET Framework 4.82 |
.NET 8.0 |
Funciones 1.x3 | N/D | .NET Framework 4.8 |
1 .NET 6 se admitía anteriormente en ambos modelos, pero alcanzó el fin del soporte técnico oficial el 12 de noviembre de 2024. .NET 7 se admitía anteriormente en el modelo de trabajo aislado, pero llegó al final del soporte técnico oficial el 14 de mayo de 2024.
2 El proceso de compilación también requiere el SDK de .NET .
3 El soporte técnico finaliza para la versión 1.x del entorno de ejecución de Azure Functions el 14 de septiembre de 2026. Para más información, consulte este anuncio de soporte. Para seguir teniendo soporte completo, debería migrar sus aplicaciones a la versión 4.x.
4 El soporte técnico finaliza para el modelo In-Process el 10 de noviembre de 2026. Para más información, consulte este anuncio de soporte. Para seguir teniendo soporte técnico completo, debería migrar sus aplicaciones al modelo de trabajo aislado.
Para obtener las últimas noticias sobre las versiones de Azure Functions, incluida la eliminación de versiones secundarias específicas anteriores, revise los anuncios de Azure App Service.
Estructura de proyecto
Un proyecto de .NET para Azure Functions en el que se usa el modelo de trabajo aislado es básicamente un proyecto de aplicación de consola de .NET que tiene como destino un runtime .NET compatible. A continuación, se muestran los archivos básicos necesarios en cualquier proyecto aislado de .NET:
- Archivo del proyecto de C# (. csproj) que define el proyecto y las dependencias.
- Archivo program.cs que es el punto de entrada de la aplicación.
- Cualquier archivo de código que defina las funciones.
- Archivo host.json que define la configuración compartida por las funciones de su proyecto.
- Archivo local.settings.json que define las variables de entorno usadas por su proyecto cuando se ejecuta localmente en su máquina.
Para obtener ejemplos completos, vea el proyecto de ejemplo de .NET 8 y el proyecto de ejemplo de .NET Framework 4.8.
Referencias de paquete
Un proyecto de .NET para Azure Functions en el que se usa el modelo de trabajo aislado utiliza un conjunto único de paquetes, tanto para la funcionalidad principal como para las extensiones de enlace.
Paquetes base
Los siguientes paquetes son necesarios para ejecutar las funciones de .NET en un proceso de trabajo aislado:
Versión 2.x
Las versiones 2.x de los paquetes principales cambian los marcos admitidos y proporcionan compatibilidad con las nuevas API de .NET de estas versiones posteriores. Cuando el destino es .NET 9 o posterior, la aplicación debe hacer referencia a la versión 2.0.0 o posterior de ambos paquetes.
Al actualizar a las versiones 2.x, tenga en cuenta los siguientes cambios:
- A partir de la versión 2.0.0 de Microsoft.Azure.Functions.Worker.Sdk:
- El SDK incluye configuraciones predeterminadas para compilaciones de contenedor delSDK.
- El SDK incluye compatibilidad con
dotnet run
cuando se instala la Azure Functions Core Tools.
- A partir de la versión 2.0.0 de Microsoft.Azure.Functions.Worker:
- Esta versión agrega compatibilidad con
IHostApplicationBuilder
. Algunos ejemplos de esta guía incluyen pestañas para mostrar alternativas medianteIHostApplicationBuilder
. Estos ejemplos requieren las versiones 2.x. - La validación del ámbito del proveedor de servicios se incluye de forma predeterminada si se ejecuta en un entorno de desarrollo. Este comportamiento coincide con ASP.NET Core.
- La opción
EnableUserCodeException
está habilitada de forma predeterminada. La propiedad ahora está marcada como obsoleta. - La opción
IncludeEmptyEntriesInMessagePayload
está habilitada de forma predeterminada. Con esta opción habilitada, las cargas de desencadenador que representan colecciones siempre incluyen entradas vacías. Por ejemplo, si se envía un mensaje sin cuerpo, seguiría habiendo una entrada vacía enstring[]
para los datos del desencadenador. La inclusión de entradas vacías facilita la referencia cruzada con matrices de metadatos a las que también puede hacer referencia la función. Puede deshabilitar este comportamiento estableciendoIncludeEmptyEntriesInMessagePayload
enfalse
en la configuración del servicio deWorkerOptions
. - La clase
ILoggerExtensions
cambia su nombre aFunctionsLoggerExtensions
. El cambio de nombre impide un error de llamada ambiguo al usarLogMetric()
en una instancia deILogger
. - En el caso de las aplicaciones que usan
HttpResponseData
, el métodoWriteAsJsonAsync()
ya no establecerá el código de estado en200 OK
. En 1.x, esto invalida otros códigos de error que se habían establecido.
- Esta versión agrega compatibilidad con
- Las versiones 2.x quitan el soporte con TFM de .NET 5.
Paquetes de extensión
Dado que las funciones de proceso de trabajo aislado de .NET usan tipos de enlace diferentes, requieren un conjunto único de paquetes de extensión de enlace.
Encontrará estos paquetes de extensión en Microsoft.Azure.Functions.Worker.Extensions.
Inicio y configuración
Al usar el modelo de trabajo aislado, tiene acceso al inicio de la aplicación de funciones, que normalmente se encuentra en Program.cs
. El usuario es responsable de crear e iniciar su propia instancia de host. Como tal, también tiene acceso directo a la canalización de configuración de la aplicación. Con el proceso de trabajo aislado de .NET Functions, puede agregar configuraciones mucho más fácilmente, insertar dependencias y ejecutar su propio middleware.
El código siguiente muestra un ejemplo de una canalización de HostBuilder:
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults()
.ConfigureServices(s =>
{
s.AddApplicationInsightsTelemetryWorkerService();
s.ConfigureFunctionsApplicationInsights();
s.AddSingleton<IHttpResponderService, DefaultHttpResponderService>();
s.Configure<LoggerFilterOptions>(options =>
{
// The Application Insights SDK adds a default logging filter that instructs ILogger to capture only Warning and more severe logs. Application Insights requires an explicit override.
// Log levels can also be configured using appsettings.json. For more information, see https://learn.microsoft.com/en-us/azure/azure-monitor/app/worker-service#ilogger-logs
LoggerFilterRule? toRemove = options.Rules.FirstOrDefault(rule => rule.ProviderName
== "Microsoft.Extensions.Logging.ApplicationInsights.ApplicationInsightsLoggerProvider");
if (toRemove is not null)
{
options.Rules.Remove(toRemove);
}
});
})
.Build();
Este código requiere using Microsoft.Extensions.DependencyInjection;
.
Antes de llamar a Build()
en IHostBuilder
, debe:
- Llame a
ConfigureFunctionsWebApplication()
si usa la integración de ASP.NET Core oConfigureFunctionsWorkerDefaults()
en caso contrario. Consulte Desencadenador HTTP para obtener más información sobre estas opciones.
Si va a escribir la aplicación con F#, algunas extensiones de desencadenador y enlace requieren una configuración adicional. Consulte la documentación de configuración de la extensión de blobs, la extensión Tables y la extensión Cosmos DB cuando piense usar estas extensiones en una aplicación F#. - Configure los servicios o la configuración de la aplicación que requiera el proyecto. Consulte Configuración para más detalles.
Si planea usar Application Insights, debe llamar aAddApplicationInsightsTelemetryWorkerService()
yConfigureFunctionsApplicationInsights()
en el delegadoConfigureServices()
. Consulte Application Insights para obtener más información.
Si el proyecto tiene como destino .NET Framework 4.8, también debe agregar FunctionsDebugger.Enable();
antes de crear HostBuilder. Debe ser la primera línea del método Main()
. Consulte Depuración al utilizar .NET Framework como destino para más información.
El HostBuilder se utiliza para compilar y devolver una instancia de IHost
completamente inicializada, que se ejecuta de forma asincrónica para iniciar la aplicación de funciones.
await host.RunAsync();
Configuración
El tipo de generador que usa determina cómo puede configurar la aplicación.
El método ConfigureFunctionsWorkerDefaults se usa para agregar la configuración necesaria para que se ejecute la aplicación de funciones. El método incluye las funciones siguientes:
- Conjunto predeterminado de convertidores.
- Establezca el valor predeterminado de JsonSerializerOptions para omitir mayúsculas y minúsculas en los nombres de propiedad.
- Integre con el registro de Azure Functions.
- Middleware y características de enlace de salida.
- Middleware de ejecución de función.
- Soporte de gRPC predeterminado.
.ConfigureFunctionsWorkerDefaults()
El acceso a la canalización del generador de host significa que también puede establecer cualquier configuración específica de la aplicación durante la inicialización. Puede llamar al método ConfigureAppConfiguration en HostBuilder una o varias veces para agregar cualquier origen de configuración requerido por el código. Para más información sobre la configuración de la aplicación, consulte Configuración en ASP.NET Core.
Estas configuraciones solo se aplican al código de trabajo del que es creador y no influyen directamente en la configuración del host de Functions ni en los desencadenadores y enlaces. Para realizar cambios en el host de funciones o en la configuración del enlace y el desencadenador, todavía necesitará usar el archivo host.json.
Nota:
Los orígenes de configuración personalizados no se pueden usar para la configuración de desencadenadores y enlaces. La configuración de desencadenador y enlace debe estar disponible para la plataforma de Functions y no solo para el código de la aplicación. Puede proporcionar esta configuración a través de la configuración de la aplicación, las referencias de Key Vault o las funciones de referencias de App Configuration.
Inserción de dependencia
El modelo de trabajo aislado usa mecanismos estándar de .NET para insertar servicios.
Cuando se usa un HostBuilder
, llame a ConfigureServices en el generador de hosts y use los métodos de extensión en IServiceCollection para insertar servicios específicos. En el ejemplo siguiente se inserta una dependencia del servicio singleton:
.ConfigureServices(services =>
{
services.AddSingleton<IHttpResponderService, DefaultHttpResponderService>();
})
Este código requiere using Microsoft.Extensions.DependencyInjection;
. Para obtener más información, consulte Inserción de dependencias en ASP.NET Core.
Registro de clientes de Azure
La inserción de dependencias se puede usar para interactuar con otros servicios de Azure. Puede insertar clientes desde el SDK de Azure para .NET mediante el paquete Microsoft.Extensions.Azure. Después de instalar el paquete, registre los clientes llamando a AddAzureClients()
en la colección de servicios de Program.cs
. En el ejemplo siguiente se configura un cliente con nombre para Azure Blobs:
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Azure;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults()
.ConfigureServices((hostContext, services) =>
{
services.AddAzureClients(clientBuilder =>
{
clientBuilder.AddBlobServiceClient(hostContext.Configuration.GetSection("MyStorageConnection"))
.WithName("copierOutputBlob");
});
})
.Build();
host.Run();
En el ejemplo siguiente se muestra cómo se puede usar este registro y los tipos de SDK para copiar el contenido del blob como una secuencia de un contenedor a otro mediante un cliente insertado:
using Microsoft.Extensions.Azure;
using Microsoft.Extensions.Logging;
namespace MyFunctionApp
{
public class BlobCopier
{
private readonly ILogger<BlobCopier> _logger;
private readonly BlobContainerClient _copyContainerClient;
public BlobCopier(ILogger<BlobCopier> logger, IAzureClientFactory<BlobServiceClient> blobClientFactory)
{
_logger = logger;
_copyContainerClient = blobClientFactory.CreateClient("copierOutputBlob").GetBlobContainerClient("samples-workitems-copy");
_copyContainerClient.CreateIfNotExists();
}
[Function("BlobCopier")]
public async Task Run([BlobTrigger("samples-workitems/{name}", Connection = "MyStorageConnection")] Stream myBlob, string name)
{
await _copyContainerClient.UploadBlobAsync(name, myBlob);
_logger.LogInformation($"Blob {name} copied!");
}
}
}
El ILogger<T>
de este ejemplo también se obtuvo mediante inyección de dependencias, por lo que se registra automáticamente. Para más información sobre las opciones de configuración para el registro, consulte Registro.
Sugerencia
En el ejemplo se usa una cadena literal para el nombre del cliente tanto en Program.cs
como en la función. Considere la posibilidad de usar en su lugar una cadena de constantes compartida definida en la clase de función. Por ejemplo, puede agregar public const string CopyStorageClientName = nameof(_copyContainerClient);
y, después, hacer referencia a BlobCopier.CopyStorageClientName
en ambas ubicaciones. De forma similar, puede definir el nombre de la sección de configuración con la función en lugar de en Program.cs
.
Software intermedio
El modelo de trabajo aislado también admite el registro de middleware, de nuevo mediante un modelo similar al que existe en ASP.NET. Este modelo proporciona la capacidad de insertar lógica en la canalización de invocación, y antes y después de que se ejecuten las funciones.
El método de extensión ConfigureFunctionsWorkerDefaults tiene una sobrecarga que le permite registrar su propio middleware, como puede ver en el ejemplo siguiente.
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults(workerApplication =>
{
// Register our custom middlewares with the worker
workerApplication.UseMiddleware<ExceptionHandlingMiddleware>();
workerApplication.UseMiddleware<MyCustomMiddleware>();
workerApplication.UseWhen<StampHttpHeaderMiddleware>((context) =>
{
// We want to use this middleware only for http trigger invocations.
return context.FunctionDefinition.InputBindings.Values
.First(a => a.Type.EndsWith("Trigger")).Type == "httpTrigger";
});
})
.Build();
El método de extensión UseWhen
se puede usar para registrar un middleware que se ejecuta condicionalmente. Debe pasar a este método un predicado que devuelve un valor booleano y el middleware participa en la canalización de procesamiento de invocación cuando el valor devuelto del predicado es true
.
Los métodos de extensión siguientes en FunctionContext facilitan el trabajo con el middleware en el modelo aislado.
Método | Descripción |
---|---|
GetHttpRequestDataAsync |
Obtiene la instancia HttpRequestData cuando la llamada la realiza un desencadenador HTTP. Este método devuelve una instancia de ValueTask<HttpRequestData?> , que es útil cuando desea leer datos de mensajes, como encabezados de solicitud y cookies. |
GetHttpResponseData |
Obtiene la instancia HttpResponseData cuando la llamada la realiza un desencadenador HTTP. |
GetInvocationResult |
Obtiene una instancia de InvocationResult , que representa el resultado de la ejecución de la función actual. Utilice la propiedad Value para obtener o establecer el valor según sea necesario. |
GetOutputBindings |
Obtiene las entradas de enlace de salida para la ejecución de la función actual. Cada entrada del resultado de este método es de tipo OutputBindingData . Puede utilizar la propiedad Value para obtener o establecer el valor según sea necesario. |
BindInputAsync |
Enlaza un elemento de enlace de entrada para la instancia BindingMetadata solicitada. Por ejemplo, puede usar este método cuando tenga una función con un enlace de entrada de BlobInput que necesite usar su middleware. |
Este es un ejemplo de implementación de un middleware que lee la instancia HttpRequestData
y actualiza la instancia HttpResponseData
durante la ejecución de las funciones:
internal sealed class StampHttpHeaderMiddleware : IFunctionsWorkerMiddleware
{
public async Task Invoke(FunctionContext context, FunctionExecutionDelegate next)
{
var requestData = await context.GetHttpRequestDataAsync();
string correlationId;
if (requestData!.Headers.TryGetValues("x-correlationId", out var values))
{
correlationId = values.First();
}
else
{
correlationId = Guid.NewGuid().ToString();
}
await next(context);
context.GetHttpResponseData()?.Headers.Add("x-correlationId", correlationId);
}
}
Este middleware comprueba la presencia de un encabezado de solicitud específico (x-correlationId) y, cuando está presente, usa el valor de encabezado para poner un sello en un encabezado de respuesta. De lo contrario, genera un nuevo valor GUID y lo usa para poner un sello en el encabezado de respuesta. Para obtener un ejemplo más completo del uso de middleware personalizado en la aplicación de funciones, consulte el ejemplo de referencia de middleware personalizado.
Personalización de la serialización JSON
El modelo de trabajo aislado usa System.Text.Json
de forma predeterminada. Puede personalizar el comportamiento del serializador configurando los servicios como parte del archivo Program.cs
. En esta sección se describe la serialización de uso general y no influirá en la serialización JSON del desencadenador HTTP con la integración de ASP.NET Core, que se debe configurar por separado.
En el ejemplo siguiente, se muestra esto mediante ConfigureFunctionsWebApplication
, pero también funcionará para ConfigureFunctionsWorkerDefaults
:
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
var host = new HostBuilder()
.ConfigureFunctionsWebApplication((IFunctionsWorkerApplicationBuilder builder) =>
{
builder.Services.Configure<JsonSerializerOptions>(jsonSerializerOptions =>
{
jsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
jsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
jsonSerializerOptions.ReferenceHandler = ReferenceHandler.Preserve;
// override the default value
jsonSerializerOptions.PropertyNameCaseInsensitive = false;
});
})
.Build();
host.Run();
En su lugar, puede usar JSON.NET (Newtonsoft.Json
) para la serialización. Para ello, deberá instalar el paquete Microsoft.Azure.Core.NewtonsoftJson
. A continuación, en el registro del servicio, deberá reasignar la propiedad Serializer
en la configuración de WorkerOptions
. En el ejemplo siguiente, se muestra esto mediante ConfigureFunctionsWebApplication
, pero también funcionará para ConfigureFunctionsWorkerDefaults
:
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
var host = new HostBuilder()
.ConfigureFunctionsWebApplication((IFunctionsWorkerApplicationBuilder builder) =>
{
builder.Services.Configure<WorkerOptions>(workerOptions =>
{
var settings = NewtonsoftJsonObjectSerializer.CreateJsonSerializerSettings();
settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
settings.NullValueHandling = NullValueHandling.Ignore;
workerOptions.Serializer = new NewtonsoftJsonObjectSerializer(settings);
});
})
.Build();
host.Run();
Métodos reconocidos como funciones
Un método de función es un método público de una clase pública con un atributo Function
aplicado al método y un atributo desencadenador aplicado a un parámetro de entrada, como en el ejemplo siguiente:
[Function(nameof(QueueFunction))]
[QueueOutput("output-queue")]
public string[] Run([QueueTrigger("input-queue")] Album myQueueItem, FunctionContext context)
El atributo desencadenador especifica el tipo de desencadenador y enlaza los datos de entrada a un parámetro del método. La función de ejemplo anterior se desencadena mediante un mensaje de cola, y este último se pasa al método en el parámetro myQueueItem
.
El atributo Function
marca el método como punto de entrada de una función. El nombre debe ser único dentro de un proyecto, debe empezar por una letra y solo puede incluir letras, números, _
y -
, y hasta 127 caracteres. Las plantillas de proyecto suelen crear un método denominado Run
, pero el nombre de método puede ser cualquier nombre de método de C# válido. Este método debe ser un miembro público de una clase pública. Por lo general, debe ser un método de instancia para que los servicios se puedan pasar a través de la inserción de dependencias.
Parámetros de función
Estos son algunos de los parámetros que puede incluir como parte de una firma de método de función:
- Enlaces, que se marcan como tales mediante la decoración de los parámetros como atributos. La función debe contener exactamente un parámetro de desencadenador.
- Un objeto de contexto de ejecución, que proporciona información sobre la invocación actual.
- Un token de cancelación, usado para el apagado suave.
Contexto de ejecución
.NET aislado pasa un objeto FunctionContext en los métodos de función. Este objeto permite obtener una instancia de ILoggerILogger
para escribir en los registros llamando al método GetLogger y proporcionando una cadena ILogger
. Puede usar este contexto para obtener un ILogger
sin tener que usar la inserción de dependencias. Para más información, consulte Registro.
Tokens de cancelación
Una función puede aceptar un parámetro CancellationToken que permite que el sistema operativo notifique al código cuando la función esté a punto de finalizar. Puede utilizar esta notificación para asegurarse de que la función no se termina inesperadamente en una forma que deje los datos en un estado incoherente.
Los tokens de cancelación se admiten en funciones de .NET cuando se ejecutan en un proceso de trabajo aislado. En el ejemplo siguiente se genera una excepción cuando se ha recibido una solicitud de cancelación:
[Function(nameof(ThrowOnCancellation))]
public async Task ThrowOnCancellation(
[EventHubTrigger("sample-workitem-1", Connection = "EventHubConnection")] string[] messages,
FunctionContext context,
CancellationToken cancellationToken)
{
_logger.LogInformation("C# EventHub {functionName} trigger function processing a request.", nameof(ThrowOnCancellation));
foreach (var message in messages)
{
cancellationToken.ThrowIfCancellationRequested();
await Task.Delay(6000); // task delay to simulate message processing
_logger.LogInformation("Message '{msg}' was processed.", message);
}
}
El siguiente ejemplo realiza acciones de limpieza cuando se recibe una solicitud de cancelación:
[Function(nameof(HandleCancellationCleanup))]
public async Task HandleCancellationCleanup(
[EventHubTrigger("sample-workitem-2", Connection = "EventHubConnection")] string[] messages,
FunctionContext context,
CancellationToken cancellationToken)
{
_logger.LogInformation("C# EventHub {functionName} trigger function processing a request.", nameof(HandleCancellationCleanup));
foreach (var message in messages)
{
if (cancellationToken.IsCancellationRequested)
{
_logger.LogInformation("A cancellation token was received, taking precautionary actions.");
// Take precautions like noting how far along you are with processing the batch
_logger.LogInformation("Precautionary activities complete.");
break;
}
await Task.Delay(6000); // task delay to simulate message processing
_logger.LogInformation("Message '{msg}' was processed.", message);
}
}
Enlaces
Los enlaces se definen mediante atributos en métodos, parámetros y tipos de valor devuelto. En su lugar, los enlaces se basan en cadenas, matrices y tipos serializables, como los objetos de clase anterior sin formato (POCO). Para algunas extensiones de enlace, también puede enlazar a tipos específicos de servicio definidos en los SDK de servicio.
Para los desencadenadores HTTP, consulte la sección Desencadenador HTTP.
Para obtener un conjunto completo de ejemplos de referencia para usar desencadenadores y enlaces con funciones de proceso de trabajo aislado, consulte el ejemplo de referencia de extensiones de enlace.
Enlaces de entrada
Una función puede tener cero o más enlaces de entrada que pueden pasar datos a una función. Al igual que los desencadenadores, los enlaces de entrada se definen mediante la aplicación de un atributo de enlace a un parámetro de entrada. Cuando se ejecuta la función, el entorno de ejecución intenta obtener los datos especificados en el enlace. Los datos que se solicitan suelen depender de la información proporcionada por el desencadenador mediante parámetros de enlace.
Enlaces de salida
Para escribir en un enlace de salida, debe aplicar un atributo de enlace de salida al método de función, que define cómo escribir en el servicio enlazado. El valor devuelto por el método se escribe en el enlace de salida. Por ejemplo, en el ejemplo siguiente se escribe un valor de cadena en una cola de mensajes denominada output-queue
mediante un enlace de salida:
[Function(nameof(QueueFunction))]
[QueueOutput("output-queue")]
public string[] Run([QueueTrigger("input-queue")] Album myQueueItem, FunctionContext context)
{
// Use a string array to return more than one message.
string[] messages = {
$"Album name = {myQueueItem.Name}",
$"Album songs = {myQueueItem.Songs}"};
_logger.LogInformation("{msg1},{msg2}", messages[0], messages[1]);
// Queue Output messages
return messages;
}
Varios enlaces de salida
Los datos que se escriben en un enlace de salida siempre son el valor devuelto de la función. Si tiene que escribir en más de un enlace de salida, debe crear un tipo de valor devuelto personalizado. Este tipo de valor devuelto debe tener el atributo de enlace de salida aplicado a una o más propiedades de la clase. El ejemplo siguiente es una función desencadenada por HTTP mediante integración de ASP.NET Core que escribe en la respuesta HTTP y en un enlace de salida de cola:
public class MultipleOutputBindings
{
private readonly ILogger<MultipleOutputBindings> _logger;
public MultipleOutputBindings(ILogger<MultipleOutputBindings> logger)
{
_logger = logger;
}
[Function("MultipleOutputBindings")]
public MyOutputType Run([HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequest req)
{
_logger.LogInformation("C# HTTP trigger function processed a request.");
var myObject = new MyOutputType
{
Result = new OkObjectResult("C# HTTP trigger function processed a request."),
MessageText = "some output"
};
return myObject;
}
public class MyOutputType
{
[HttpResult]
public IActionResult Result { get; set; }
[QueueOutput("myQueue")]
public string MessageText { get; set; }
}
}
Al usar tipos de valor devuelto personalizados para varios enlaces de salida con la integración de ASP.NET Core, debe agregar el atributo [HttpResult]
a la propiedad que proporciona el resultado. El atributo HttpResult
está disponible cuando se usa SDK 1.17.3-preview2 o posterior, junto con versión 3.2.0 o posterior de la extensión HTTP y versión 1.3.0 o posterior de la extensión de ASP.NET Core.
Tipos de SDK
Para algunos tipos de enlace específicos del servicio, se pueden proporcionar datos de enlace mediante tipos de SDK de servicio y marcos de trabajo. Estas proporcionan funcionalidad adicional más allá de lo que puede ofrecer una cadena serializada o un objeto CLR sin formato (POCO). Para usar los tipos más recientes, el proyecto debe actualizarse para usar versiones más recientes de las dependencias principales.
Dependencia | Requisito de versión |
---|---|
Microsoft.Azure.Functions.Worker | 1.18.0 o posterior |
Microsoft.Azure.Functions.Worker.Sdk | 1.13.0 o posterior |
Al probar los tipos de SDK localmente en la máquina, también deberá usar Azure Functions Core Tools versión 4.0.5000 o posterior. Puede comprobar la versión actual mediante el comando func version
.
Cada extensión de desencadenador y enlace también tiene su propio requisito de versión mínimo, que se describe en los artículos de referencia de extensión. Los siguientes enlaces específicos de servicio proporcionan tipos SDK:
Service | Desencadenador | Enlace de entrada | Enlace de salida |
---|---|---|---|
Azure Blobs | Disponibilidad general | Disponibilidad general | Tipos de SDK no recomendados.1 |
Colas de Azure | Disponibilidad general | El enlace de entrada no existe | Tipos de SDK no recomendados.1 |
Azure Service Bus | Disponibilidad general | El enlace de entrada no existe | Tipos de SDK no recomendados.1 |
Azure Event Hubs | Disponibilidad general | El enlace de entrada no existe | Tipos de SDK no recomendados.1 |
Azure Cosmos DB | Tipos de SDK no usados2 | Disponibilidad general | Tipos de SDK no recomendados.1 |
Tablas de Azure | El desencadenador no existe | Disponibilidad general | Tipos de SDK no recomendados.1 |
Azure Event Grid | Disponibilidad general | El enlace de entrada no existe | Tipos de SDK no recomendados.1 |
1 Para escenarios de salida en los que usaría un tipo de SDK, debe crear y trabajar con clientes del SDK directamente en lugar de usar un enlace de salida. Consulte Registro de clientes de Azure para ver un ejemplo de inserción de dependencias.
2 El desencadenador de Cosmos DB usa la fuente de cambios de Azure Cosmos DB y expone elementos de fuente de cambios como tipos serializables JSON. La ausencia de tipos de SDK es por diseño para este escenario.
Nota:
Al usar expresiones de enlace que se basan en los datos del desencadenador, no pueden usarse los tipos de SDK para el propio desencadenador.
Desencadenador HTTP
Los desencadenadores HTTP permiten invocar una función mediante una solicitud HTTP. Hay dos enfoques diferentes que se pueden usar:
- Un modelo de integración de ASP.NET Core que usa conceptos que los desarrolladores de ASP.NET Core conocen
- Un modelo integrado, que no requiere dependencias adicionales y usa tipos personalizados para solicitudes y respuestas HTTP. Este enfoque se mantiene por motivos de compatibilidad con versiones anteriores de aplicaciones de trabajo aisladas de .NET.
Integración de ASP.NET Core
En esta sección se muestra cómo trabajar con los objetos de solicitud y respuesta HTTP subyacentes mediante tipos de ASP.NET Core incluidos HttpRequest, HttpResponse e IActionResult. Este modelo no está disponible para las aplicaciones destinadas a .NET Framework, que en su lugar deben usar el modelo integrado.
Nota:
Este modelo no expone todas las características de ASP.NET Core. En concreto, la ASP.NET Core canalización de middleware y las funcionalidades de enrutamiento no están disponibles. La integración del ASP.NET Core requiere que use paquetes actualizados.
Para habilitar la integración de ASP.NET Core para HTTP:
Agregue una referencia en su proyecto al paquete Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore, versión 1.0.0 o posterior.
Actualice su proyecto para usar estas versiones específicas de paquetes:
- Microsoft.Azure.Functions.Worker.Sdk, versión 1.11.0. o posterior
- Microsoft.Azure.Functions.Worker, versión 1.16.0 o posterior.
En el archivo
Program.cs
, actualice la configuración del generador de hosts para que llame aConfigureFunctionsWebApplication()
. Esto reemplaza aConfigureFunctionsWorkerDefaults()
si usara ese método en caso contrario. En el ejemplo siguiente se muestra una configuración mínima sin otras personalizaciones:using Microsoft.Azure.Functions.Worker; using Microsoft.Extensions.Hosting; var host = new HostBuilder() .ConfigureFunctionsWebApplication() .Build(); host.Run();
Actualice las funciones existentes desencadenadas por HTTP para usar los tipos de ASP.NET Core. Este ejemplo muestra el
HttpRequest
estándar y unIActionResult
usado para una función sencilla de "hola, mundo":[Function("HttpFunction")] public IActionResult Run( [HttpTrigger(AuthorizationLevel.Anonymous, "get")] HttpRequest req) { return new OkObjectResult($"Welcome to Azure Functions, {req.Query["name"]}!"); }
Serialización JSON con integración de ASP.NET Core
ASP.NET Core tiene su propia capa de serialización y no se ve afectada al personalizar la configuración de serialización general. Para personalizar el comportamiento de serialización usado para los desencadenadores HTTP, debe incluir una .AddMvc()
llamada como parte del registro del servicio. El devuelto IMvcBuilder
se puede usar para modificar la configuración de serialización JSON de ASP.NET Core. En el ejemplo siguiente se muestra cómo configurar JSON.NET (Newtonsoft.Json
) para la serialización mediante este enfoque:
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
var host = new HostBuilder()
.ConfigureFunctionsWebApplication()
.ConfigureServices(services =>
{
services.AddApplicationInsightsTelemetryWorkerService();
services.ConfigureFunctionsApplicationInsights();
services.AddMvc().AddNewtonsoftJson();
})
.Build();
host.Run();
Modelos HTTP integrados
En el modelo integrado, el sistema traduce el mensaje de solicitud HTTP entrante en un objeto HttpRequestData que se pasa a la función. Este objeto proporciona datos de la solicitud, incluidos Headers
, Cookies
, Identities
, URL
y un mensaje opcional Body
. Este objeto es una representación de la solicitud HTTP, pero no está conectado directamente al agente de escucha HTTP subyacente o al mensaje recibido.
Del mismo modo, la función devuelve un objeto HttpReponseData, que proporciona los datos usados para crear la respuesta HTTP, incluido el StatusCode
del mensaje, Headers
y, opcionalmente, un Body
de mensaje.
El siguiente ejemplo muestra el uso de HttpRequestData
y HttpResponseData
:
[Function(nameof(HttpFunction))]
public static HttpResponseData Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequestData req,
FunctionContext executionContext)
{
var logger = executionContext.GetLogger(nameof(HttpFunction));
logger.LogInformation("message logged");
var response = req.CreateResponse(HttpStatusCode.OK);
response.Headers.Add("Content-Type", "text/plain; charset=utf-8");
response.WriteString("Welcome to .NET isolated worker !!");
return response;
}
Registro
Puede escribir en los registros mediante una instancia ILogger<T>
o ILogger
. El registrador se puede obtener mediante la inserción de dependencias de ILogger<T>
o de un [ILoggerFactory]:
public class MyFunction {
private readonly ILogger<MyFunction> _logger;
public MyFunction(ILogger<MyFunction> logger) {
_logger = logger;
}
[Function(nameof(MyFunction))]
public void Run([BlobTrigger("samples-workitems/{name}", Connection = "")] string myBlob, string name)
{
_logger.LogInformation($"C# Blob trigger function Processed blob\n Name: {name} \n Data: {myBlob}");
}
}
El registrador también se puede obtener de un objeto FunctionContext pasado a su función. Llame al método GetLogger<T> o GetLogger, pasando un valor de cadena que es el nombre de la categoría en la que se escriben los registros. La categoría suele ser el nombre de la función específica desde la que se escriben los registros. Para obtener más información sobre las categorías, consulte el artículo sobre supervisión.
Use los métodos de ILogger<T>
y ILogger
para escribir varios niveles de registro, como LogWarning
o LogError
. Para obtener más información sobre los niveles de registro, consulte el artículo sobre supervisión. Puede personalizar los niveles de registro de los componentes agregados al código registrando filtros:
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults()
.ConfigureServices(services =>
{
// Registers IHttpClientFactory.
// By default this sends a lot of Information-level logs.
services.AddHttpClient();
})
.ConfigureLogging(logging =>
{
// Disable IHttpClientFactory Informational logs.
// Note -- you can also remove the handler that does the logging: https://github.com/aspnet/HttpClientFactory/issues/196#issuecomment-432755765
logging.AddFilter("System.Net.Http.HttpClient", LogLevel.Warning);
})
.Build();
Como parte de la configuración de la aplicación en Program.cs
, también puede definir el comportamiento de cómo se muestran los errores en los registros. El comportamiento predeterminado depende del tipo de generador que esté usando.
Cuando usa un HostBuilder
, de forma predeterminada, las excepciones generadas por el código pueden terminar encapsuladas en una RpcException
. Para quitar esta capa adicional, establezca la propiedad EnableUserCodeException
en "true" como parte de la configuración del generador:
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Hosting;
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults(builder => {}, options =>
{
options.EnableUserCodeException = true;
})
.Build();
host.Run();
Application Insights
Puede configurar la aplicación de proceso aislada para emitir registros directamente en Application Insights. Este comportamiento reemplaza el comportamiento predeterminado de los registros de retransmisión a través del host. A menos que use .NET Aspire, se recomienda configurar la integración directa de Application Insights porque proporciona control sobre cómo se emiten esos registros.
La integración de Application Insights no está habilitada de manera predeterminada en todas las experiencias de configuración. Algunas plantillas crearán proyectos de Functions con los paquetes necesarios y el código de inicio comentados. Si desea utilizar la integración de Application Insights, puede eliminar el comentario de estas líneas en el archivo Program.cs
del proyecto.csproj
. Las instrucciones del resto de esta sección también describen cómo habilitar la integración.
Si el proyecto forma parte de una orquestación .NET Aspire, en su lugar se utiliza OpenTelemetry para la monitorización. No debe habilitar la integración directa de Application Insights en proyectos de .NET Aspire. En su lugar, configure el exportador OpenTelemetry de Azure Monitor como parte del proyecto predeterminado del servicio. Si su proyecto Functions utiliza la integración de Application Insights en un contexto .NET Aspire, la aplicación dará error al iniciarse.
Instalar paquetes
Para escribir registros directamente en Application Insights desde su código, agregue referencias a estos paquetes en su proyecto:
- Microsoft.Azure.Functions.Worker.ApplicationInsights, versión 1.0.0 o posterior.
- Microsoft.ApplicationInsights.WorkerService.
Puede ejecutar los siguientes comandos para agregar estas referencias al proyecto:
dotnet add package Microsoft.ApplicationInsights.WorkerService
dotnet add package Microsoft.Azure.Functions.Worker.ApplicationInsights
Configuración del inicio
Con los paquetes instalados, debe llamar a AddApplicationInsightsTelemetryWorkerService()
y ConfigureFunctionsApplicationInsights()
durante la configuración del servicio en el archivo Program.cs
, como en este ejemplo:
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults()
.ConfigureServices(services => {
services.AddApplicationInsightsTelemetryWorkerService();
services.ConfigureFunctionsApplicationInsights();
})
.Build();
host.Run();
La llamada a ConfigureFunctionsApplicationInsights()
agrega un ITelemetryModule
, que escucha un ActivitySource
definido por Functions. Esto crea la telemetría de dependencia necesaria para admitir el seguimiento distribuido. Para más información sobre AddApplicationInsightsTelemetryWorkerService()
y cómo usarlo, consulte Application Insights para aplicaciones de Worker Service.
Administración de niveles de registro
Importante
El host de Functions y el rol de trabajo de proceso aislado tienen una configuración independiente para los niveles de registro, etc. Ninguna configuración de Application Insights en host.json afectará al registro del trabajo y, de forma similar, la configuración realizada en el código de trabajo no afectará al registro desde el host. Debe aplicar cambios en ambos lugares si el escenario necesita personalización en ambas capas.
El resto de la aplicación sigue funcionando con ILogger
y ILogger<T>
. Sin embargo, de forma predeterminada, el SDK de Application Insights agrega un filtro de registro que indica al registrador capturar solo advertencias y registros más graves. Si desea deshabilitar este comportamiento, quite la regla de filtro como parte de la configuración del servicio:
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults()
.ConfigureServices(services => {
services.AddApplicationInsightsTelemetryWorkerService();
services.ConfigureFunctionsApplicationInsights();
})
.ConfigureLogging(logging =>
{
logging.Services.Configure<LoggerFilterOptions>(options =>
{
LoggerFilterRule defaultRule = options.Rules.FirstOrDefault(rule => rule.ProviderName
== "Microsoft.Extensions.Logging.ApplicationInsights.ApplicationInsightsLoggerProvider");
if (defaultRule is not null)
{
options.Rules.Remove(defaultRule);
}
});
})
.Build();
host.Run();
Optimizaciones de rendimiento
En esta sección se describen las opciones que puede habilitar para mejorar el rendimiento en torno al arranque de acceso esporádico.
En general, la aplicación debe usar las versiones más recientes de sus dependencias principales. Como mínimo, debe actualizar el proyecto de la siguiente manera:
- Actualice Microsoft.Azure.Functions.Worker a la versión 1.19.0 o posterior.
- Actualice Microsoft.Azure.Functions.Worker.Sdk a la versión 1.16.4 o posterior.
- Agregue una referencia de marco a
Microsoft.AspNetCore.App
, a menos que la aplicación tenga como destino .NET Framework.
En el fragmento siguiente se muestra esta configuración en el contexto de un archivo del proyecto:
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.21.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.16.4" />
</ItemGroup>
Marcadores de posición
Los marcadores de posición son una funcionalidad de plataforma que mejora el arranque de acceso esporádico para aplicaciones destinadas a .NET 6 o una versión posterior. Para usar esta optimización, debe habilitar explícitamente los marcadores de posición mediante estos pasos:
Actualice la configuración del proyecto para usar las versiones de dependencia más recientes, como se detalla en la sección anterior.
Establezca la configuración de la aplicación de
WEBSITE_USE_PLACEHOLDER_DOTNETISOLATED
en1
, lo que puede hacer usando este comando az functionapp config appsettings set:az functionapp config appsettings set -g <groupName> -n <appName> --settings 'WEBSITE_USE_PLACEHOLDER_DOTNETISOLATED=1'
En este ejemplo, sustituya
<groupName>
por el nombre del grupo de recursos y reemplace<appName>
por el nombre de su aplicación de funciones.Asegúrese de que la propiedad
netFrameworkVersion
de la aplicación de funciones coincide con la plataforma de destino del proyecto, que debe ser .NET 6 o posterior. Puede hacerlo usando este comando az functionapp config set:az functionapp config set -g <groupName> -n <appName> --net-framework-version <framework>
En este ejemplo, sustituya también
<framework>
por la cadena de versión adecuada, comov8.0
, según la versión .NET de destino.Asegúrese de que su aplicación de funciones está configurada para usar un proceso de 64 bits, lo que puede hacer mediante este comando az functionapp config set:
az functionapp config set -g <groupName> -n <appName> --use-32bit-worker-process false
Importante
Al establecer el WEBSITE_USE_PLACEHOLDER_DOTNETISOLATED
en 1
, todas las demás configuraciones de la aplicación de funciones deben establecerse correctamente. De lo contrario, es posible que la aplicación de funciones no se inicie.
Ejecutor optimizado
El ejecutor de la función es un componente de la plataforma que hace que se ejecuten invocaciones. Una versión optimizada de este componente está habilitada de forma predeterminada a partir de la versión 1.16.2 del SDK. No es necesario efectuar ninguna otra configuración.
ReadyToRun
La aplicación de funciones se puede compilar como archivos binarios de ReadyToRun. ReadyToRun es una forma de compilación Ahead Of Time que puede mejorar el rendimiento de inicio para ayudar a reducir el impacto del inicio en frío cuando se ejecuta en un plan de consumo. ReadyToRun está disponible en .NET 6 (y versiones posteriores) y requiere la versión 4.0 o posterior del runtime de Azure Functions.
ReadyToRun requiere que compile el proyecto en la arquitectura en tiempo de ejecución de la aplicación de hospedaje. Si no están alineados, la aplicación encontrará un error al iniciarse. Seleccione su identificador de tiempo de ejecución en esta tabla:
Sistema operativo | La aplicación es de 32 bits1 | Identificador en tiempo de ejecución |
---|---|---|
Windows | True | win-x86 |
Windows | False | win-x64 |
Linux | True | N/D (no compatible). |
Linux | False | linux-x64 |
1 Solo las aplicaciones de 64 bits son aptas para otras optimizaciones de rendimiento.
Para comprobar si la aplicación de Windows es de 32 o 64 bits, puede ejecutar el siguiente comando de la CLI, sustituyendo <group_name>
por el nombre del grupo de recursos y <app_name>
por el nombre de la aplicación. Una salida de "true" indica que la aplicación es de 32 bits y "false" indica 64 bits.
az functionapp config show -g <group_name> -n <app_name> --query "use32BitWorkerProcess"
Puede cambiar la aplicación a 64 bits con el siguiente comando, con las mismas sustituciones:
az functionapp config set -g <group_name> -n <app_name> --use-32bit-worker-process false`
Para compilar un proyecto como ReadyToRun, actualice el archivo del proyecto agregando los elementos <PublishReadyToRun>
y <RuntimeIdentifier>
. El ejemplo siguiente muestra una configuración para publicar en una aplicación de funciones de Windows de 64 bits.
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<AzureFunctionsVersion>v4</AzureFunctionsVersion>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<PublishReadyToRun>true</PublishReadyToRun>
</PropertyGroup>
Si no desea establecer <RuntimeIdentifier>
como parte del archivo de proyecto, también puede configurarlo como parte del propio gesto de publicación. Por ejemplo, con una aplicación de funciones de Windows de 64 bits, el comando de la CLI de .NET sería:
dotnet publish --runtime win-x64
En Visual Studio, la opción Tiempo de ejecución de destino del perfil de publicación debe establecerse en el identificador de tiempo de ejecución correcto. Cuando se establece en el valor predeterminado de Portable, no se usa ReadyToRun.
Implementación en Azure Functions
Al implementar el proyecto de código de función en Azure, debe ejecutarse en una aplicación de funciones o en un contenedor de Linux. La aplicación de funciones y otros recursos de Azure necesarios deben existir antes de implementar el código.
También puede implementar la aplicación de funciones en un contenedor de Linux. Para obtener más información, consulte Trabajar con contenedores y Azure Functions.
Creación de recursos de Azure
Puede crear la aplicación de funciones y otros recursos necesarios en Azure mediante uno de estos métodos:
- Visual Studio: Visual Studio puede crear recursos automáticamente durante el proceso de publicación de código.
- Visual Studio Code: Visual Studio Code puede conectarse a la suscripción, crear los recursos necesarios para la aplicación y, a continuación, publicar el código.
- CLI de Azure: puede usar la CLI de Azure para crear los recursos necesarios en Azure.
- Azure PowerShell: puede usar Azure PowerShell para crear los recursos necesarios en Azure.
- Plantillas de implementación: puede usar plantillas ARM y archivos Bicep para automatizar la implementación de los recursos necesarios en Azure. Asegúrese de que su plantilla incluye cualquier configuración necesaria.
- Azure Portal: puede crear los recursos necesarios en Azure Portal.
Publicación de la aplicación
Después de crear la aplicación de funciones y otros recursos necesarios en Azure, puede implementar el proyecto de código en Azure mediante uno de estos métodos:
- Visual Studio: implementación manual sencilla durante el desarrollo.
- Visual Studio Code: implementación manual sencilla durante el desarrollo.
- Azure Functions Core Tools: implemente el archivo de proyecto desde la línea de comandos.
- Implementación continua: útil para el mantenimiento continuo, con frecuencia en un espacio de ensayo.
- Plantillas de implementación: Puede usar plantillas ARM o archivos Bicep para automatizar la implementación de paquetes.
Para más información, vea Tecnologías de implementación en Azure Functions.
Carga de implementación
Muchos de los métodos de implementación usan un archivo ZIP. Si usted mismo va a crear el archivo ZIP, debe seguir la estructura que se describe en esta sección. Si no es así, la aplicación puede experimentar errores al iniciarse.
La carga de implementación debe coincidir con la salida de un comando dotnet publish
, aunque sin la carpeta principal envolvente. El archivo ZIP debe realizarse a partir de los siguientes archivos:
.azurefunctions/
extensions.json
functions.metadata
host.json
worker.config.json
- Ejecutable del proyecto (una aplicación de consola)
- Otros archivos auxiliares y directorios del mismo nivel a ese ejecutable
Estos archivos se generan mediante el proceso de compilación y no están diseñados para editarse directamente.
Al preparar un archivo ZIP para la implementación, solo debe comprimir el contenido del directorio de salida, no el propio directorio envolvente. Cuando el archivo se extrae en el directorio de trabajo actual, los archivos enumerados anteriormente deben estar visibles inmediatamente.
Requisitos de implementación
Hay algunos requisitos para ejecutar funciones de .NET en el modelo de trabajo aislado de Azure, en función del sistema operativo:
- FUNCTIONS_WORKER_RUNTIME debe establecerse en un valor de
dotnet-isolated
. - netFrameworkVersion debe establecerse en la versión deseada.
Al crear la aplicación de funciones en Azure mediante los métodos de la sección anterior, esta configuración necesaria se agrega automáticamente. Cuando cree estos recursos utilizando plantillas ARM o archivos Bicep para la automatización, debe asegurarse de establecerlos en la plantilla.
.NET Aspire (versión preliminar)
.NET Aspire es una pila con opiniones que simplifica el desarrollo de aplicaciones distribuidas en la nube. Puede inscribir proyectos de modelo de trabajo aislados de .NET 8 y .NET 9 en orquestaciones de Aspire 9.0 mediante la compatibilidad con la versión preliminar. En la sección se describen los requisitos básicos para la inscripción.
Esta integración requiere una configuración específica:
- Use Aspire 9.0 o posterior y el SDK de .NET 9. Aspire 9.0 admite los marcos .NET 8 y .NET 9.
- Si usa Visual Studio, actualice a la versión 17.12 o posterior. También debe disponer de la última versión de las herramientas de funciones para Visual Studio. Para comprobar si hay actualizaciones, vaya a Herramientas>Opciones, elija Azure Functions en Proyectos y soluciones. Seleccione Buscar actualizaciones e instale las actualizaciones según se le solicite.
- En el proyecto host de la aplicación Aspire:
- Debe hacer referencia a Aspire.Hosting.Azure.Functions.
- Debe tener una referencia de proyecto al proyecto de Functions.
- En el host de
Program.cs
la aplicación, también debe incluir el proyecto llamando aAddAzureFunctionsProject<TProject>()
enIDistributedApplicationBuilder
. Este método se usa en lugar delAddProject<TProject>()
que se usa para otros tipos de proyecto. Si solo usaAddProject<TProject>()
, el proyecto de Functions no se iniciará correctamente.
- En el proyecto de Functions:
- Debe hacer referencia a las versiones 2.x de Microsoft.Azure.Functions.Worker y Microsoft.Azure.Functions.Worker.Sdk. También debe actualizar las referencias que tenga
Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore
a la versión 2.x. Program.cs
Debe utilizar laIHostApplicationBuilder
versión de inicio de instancia de host.- Si desea usar los valores predeterminados del servicio Aspire, debe incluir una referencia de proyecto al proyecto predeterminado del servicio. Antes de compilar
IHostApplicationBuilder
enProgram.cs
, también debe incluir una llamada abuilder.AddServiceDefaults()
. - No debe mantener la configuración en
local.settings.json
, aparte de laFUNCTIONS_WORKER_RUNTIME
configuración, que debe permanecer "dotnet-isolated". Otra configuración debe establecerse a través del proyecto host de la aplicación. - Debe quitar las integraciones directas de Application Insights. La monitorización en Aspire se realiza a través de su soporte OpenTelemetry.
- Debe hacer referencia a las versiones 2.x de Microsoft.Azure.Functions.Worker y Microsoft.Azure.Functions.Worker.Sdk. También debe actualizar las referencias que tenga
En el ejemplo siguiente se muestra un mínimo Program.cs
para un proyecto host de aplicación:
var builder = DistributedApplication.CreateBuilder(args);
builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject");
builder.Build().Run();
En el ejemplo siguiente se muestra un mínimo Program.cs
para un proyecto de Functions usado en Aspire:
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
var builder = FunctionsApplication.CreateBuilder(args);
builder.AddServiceDefaults();
builder.ConfigureFunctionsWebApplication();
builder.Build().Run();
Esto no incluye la configuración predeterminada de Application Insights que verá en muchos de los otros Program.cs
ejemplos de este artículo. En su lugar, la integración de OpenTelemetry de Aspire se configura a través de la builder.AddServiceDefaults()
llamada.
Consideraciones y procedimientos recomendados para la integración de .NET Aspire
Tenga en cuenta los siguientes puntos al evaluar .NET Aspire con Azure Functions:
- La compatibilidad con Azure Functions con .NET Aspire está actualmente en versión preliminar. Durante el período de versión preliminar, al publicar la solución Aspire en Azure, los proyectos de Functions se implementan como recursos de Azure Container Apps sin escalado controlado por eventos. La compatibilidad con Azure Functions no está disponible para las aplicaciones implementadas en este modo.
- La configuración de desencadenador y enlace a través de Aspire se limita actualmente a integraciones específicas. Consulte Configuración de conexión con Aspire para obtener más información.
Program.cs
Debe utilizar laIHostApplicationBuilder
versión de inicio de instancia de host. Esto le permite llamar abuilder.AddServiceDefaults()
para agregar valores predeterminados del servicio Aspire de .NET al proyecto de Functions.- Aspire usa OpenTelemetry para la supervisión. Puede configurar Aspire para exportar datos de telemetría a Azure Monitor a través del proyecto predeterminado del servicio. En muchos otros contextos de Azure Functions, puede incluir la integración directa con Application Insights mediante el registro del servicio de trabajo de telemetría. Esto no se recomienda en Aspire y puede provocar errores de ejecución con la versión 2.22.0 de
Microsoft.ApplicationInsights.WorkerService
. Debe quitar las integraciones directas de Application Insights del proyecto de Functions al usar Aspire. - En el caso de los proyectos de funciones incluidos en una orquestación de Aspire, la mayor parte de la configuración de la aplicación debe proceder del proyecto host de aplicaciones de Aspire. Normalmente, debe evitar establecer elementos en
local.settings.json
, aparte de laFUNCTIONS_WORKER_RUNTIME
configuración. Si la misma variable de entorno está establecida porlocal.settings.json
y Aspire, el sistema utiliza la versión Aspire. - No configure el emulador de Storage para ninguna conexión de
local.settings.json
. Muchas plantillas de inicio de Functions incluyen el emulador como valor predeterminado paraAzureWebJobsStorage
. Sin embargo, la configuración del emulador puede pedir a algunos IDE que inicien una versión del emulador que pueda entrar en conflicto con la versión que usa Aspire.
Configuración de conexión con Aspire
Azure Functions requiere una conexión de almacenamiento de host (AzureWebJobsStorage
) para varios de sus comportamientos principales. Al llamar al AddAzureFunctionsProject<TProject>()
proyecto host de la aplicación, se crea una conexión predeterminada AzureWebJobsStorage
y se proporciona al proyecto de Functions. Esta conexión predeterminada utiliza el emulador de almacenamiento para las ejecuciones de desarrollo local y aprovisiona automáticamente una cuenta de almacenamiento cuando se implementa. Para un control adicional, puede reemplazar esta conexión llamando .WithHostStorage()
al recurso del proyecto de Functions.
En el ejemplo siguiente se muestra un mínimo Program.cs
para un proyecto host de aplicación que reemplaza el almacenamiento de host:
var builder = DistributedApplication.CreateBuilder(args);
var myHostStorage = builder.AddAzureStorage("myHostStorage");
builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject")
.WithHostStorage(myHostStorage);
builder.Build().Run();
Nota:
Cuando Aspire aprovisiona el almacenamiento de host en modo de publicación, el valor predeterminado es crear asignaciones de roles para los roles Colaborador de la cuenta de almacenamiento,Colaborador de datos de almacenamiento Blob,Colaborador de datos de cola de Storage , yTabla de almacenamiento Funciones de colaborador de datos.
Los desencadenadores y enlaces hacen referencia a las conexiones por nombre. Algunas integraciones de Aspire están habilitadas para proporcionarlas a través de una llamada a WithReference()
en el recurso del proyecto:
Integración de Aspire | Notas |
---|---|
Azure Blobs | Cuando Aspire aprovisiona el recurso, el valor predeterminado es crear asignaciones de roles para el Colaborador de datos de almacenamiento Blob,Colaborador de datos de cola de Storage y Colaborador de datos de tabla de Storage. |
Colas de Azure | Cuando Aspire aprovisiona el recurso, el valor predeterminado es crear asignaciones de roles para el Colaborador de datos de almacenamiento Blob,Colaborador de datos de cola de Storage y Colaborador de datos de tabla de Storage. |
Azure Event Hubs | Cuando Aspire aprovisiona el recurso, el valor predeterminado es crear una asignación de roles mediante el rol Propietario de datos de Azure Event Hubs. |
Azure Service Bus | Cuando Aspire aprovisiona el recurso, el valor predeterminado es crear una asignación de roles mediante el rol Propietario de datos de Azure Service Bus. |
En el ejemplo siguiente se muestra un mínimo Program.cs
para un proyecto host de aplicación que configura un desencadenador de cola. En este ejemplo, el desencadenador de cola correspondiente tiene su Connection
propiedad establecida en "MyQueueTriggerConnection".
var builder = DistributedApplication.CreateBuilder(args);
var myAppStorage = builder.AddAzureStorage("myAppStorage").RunAsEmulator();
var queues = myAppStorage.AddQueues("queues");
builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject")
.WithReference(queues, "MyQueueTriggerConnection");
builder.Build().Run();
Para otras integraciones, llama a para WithReference
establecer la configuración de una manera diferente, lo que hace que esté disponible para integraciones de cliente Aspire, pero no para desencadenadores y enlaces. Para estas integraciones, debe llamar a WithEnvironment()
para pasar la información de conexión para que el desencadenador o el enlace se resuelvan. En el ejemplo siguiente se muestra cómo establecer la variable de entorno "MyBindingConnection" para un recurso que expone una expresión de cadena de conexión:
builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject")
.WithEnvironment("MyBindingConnection", otherIntegration.Resource.ConnectionStringExpression);
Puede configurar WithReference()
y WithEnvironment()
si desea que las integraciones de cliente de Aspire usen una conexión y el sistema de desencadenadores y enlaces.
Para algunos recursos, la estructura de una conexión puede ser diferente entre la ejecución local y la publicación en Azure. En el ejemplo anterior, otherIntegration
podría ser un recurso que se ejecuta como un emulador, por lo que ConnectionStringExpression
devolvería una cadena de conexión del emulador. Sin embargo, cuando se publique el recurso, Aspire podría establecer una conexión basada en la identidad y ConnectionStringExpression
devolvería el URI del servicio. En este caso, para configurar conexiones basadas en identidades para Azure Functions, es posible que tenga que proporcionar un nombre de variable de entorno diferente. En el ejemplo siguiente se usa builder.ExecutionContext.IsPublishMode
para agregar condicionalmente el sufijo necesario:
builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject")
.WithEnvironment("MyBindingConnection" + (builder.ExecutionContext.IsPublishMode ? "__serviceUri" : ""), otherIntegration.Resource.ConnectionStringExpression);
Dependiendo de su escenario, puede que también necesite ajustar los permisos que se asignarán para una conexión basada en identidad. Puede usar el ConfigureConstruct<T>()
método para personalizar cómo Aspire configura la infraestructura cuando publica el proyecto.
Consulte las páginas de referencia de cada enlace para obtener más información sobre los formatos de conexión que admite y los permisos que requieren esos formatos.
Depuración
Cuando se ejecuta localmente mediante Visual Studio o Visual Studio Code, puede depurar el proyecto de trabajo aislado de .NET de la manera normal. Sin embargo, hay dos escenarios de depuración que no funcionan según lo previsto.
Depuración remota con Visual Studio
Dado que la aplicación de proceso de trabajo aislado se ejecuta fuera del entorno de ejecución de Functions, debe asociar el depurador remoto a un proceso independiente. Para obtener más información sobre la depuración mediante Visual Studio, consulte Depuración remota.
Depuración al utilizar .NET Framework como destino
Si el proyecto aislado tiene como destino .NET Framework 4.8, debe realizar pasos manuales para habilitar la depuración. Estos pasos no son necesarios si se usa otra plataforma de destino.
La aplicación debe empezar con una llamada a FunctionsDebugger.Enable();
como primera operación. Esto ocurre en el método Main()
antes de inicializar un HostBuilder. El archivo Program.cs
debe tener un aspecto similar al siguiente:
using System;
using System.Diagnostics;
using Microsoft.Extensions.Hosting;
using Microsoft.Azure.Functions.Worker;
using NetFxWorker;
namespace MyDotnetFrameworkProject
{
internal class Program
{
static void Main(string[] args)
{
FunctionsDebugger.Enable();
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults()
.Build();
host.Run();
}
}
}
A continuación, debe asociarse manualmente al proceso mediante un depurador de .NET Framework. Visual Studio no hace esto automáticamente para aplicaciones de .NET Framework de proceso de trabajo aislado y se debe evitar la operación "Iniciar depuración".
En el directorio del proyecto (o su directorio de salida de compilación), ejecute:
func host start --dotnet-isolated-debug
Esto inicia el trabajo y el proceso se detiene con el siguiente mensaje:
Azure Functions .NET Worker (PID: <process id>) initialized in debug mode. Waiting for debugger to attach...
Donde <process id>
es el id. del proceso de trabajo. Ahora puede usar Visual Studio para asociarse manualmente al proceso. Para instrucciones sobre esta operación, consulte Asociación con un proceso en ejecución.
Una vez asociado el depurador, la ejecución del proceso se reanuda y podrá depurar.
Versiones preliminares de .NET
Antes de una versión disponible con carácter general, es posible que una versión de .NET se publique en el estado Versión preliminar o Publicación. Consulte la directiva de soporte técnico oficial de .NET para obtener más información sobre estos estados.
Aunque puede tener como destino una versión determinada de un proyecto local de Functions, es posible que las aplicaciones de función hospedadas en Azure no tengan esa versión disponible. Azure Functions solo se puede usar con las versiones Versión preliminar o Publicación que se indican en esta sección.
Azure Functions no funciona actualmente con ninguna versión "Versión preliminar" o "Publicación" de .NET. Consulte Versiones admitidas para obtener una lista de versiones disponibles con carácter general que puede usar.
Uso de una versión preliminar del SDK de .NET
Para usar Azure Functions con una versión preliminar de .NET, debe actualizar el proyecto mediante:
- Instalación de la versión pertinente del SDK de .NET en el desarrollo
- Cambiando la configuración
TargetFramework
en el archivo.csproj
Al implementar en una aplicación de funciones en Azure, también debe asegurarse de que el marco está disponible para la aplicación. Durante el período de versión preliminar, es posible que algunas herramientas y experiencias no muestren la nueva versión preliminar como opción. Si no ve la versión preliminar incluida en Azure Portal, por ejemplo, puede usar la API de REST, las plantillas de Bicep o la CLI de Azure para configurar la versión manualmente.
En el caso de las aplicaciones hospedadas en Windows, use el siguiente comando de la CLI de Azure. Reemplace <groupName>
por el nombre del grupo de recursos, y <appName>
por el nombre de la aplicación de funciones. Reemplace <framework>
por la cadena de versión adecuada, como v8.0
.
az functionapp config set -g <groupName> -n <appName> --net-framework-version <framework>
Consideraciones sobre el uso de versiones preliminares de .NET
Tenga en cuenta estas consideraciones al usar Functions con versiones preliminares de .NET:
Al crear las funciones en Visual Studio, debe usar Visual Studio Preview, que admite la creación de proyectos de Azure Functions con SDK de versión preliminar de .NET.
Asegúrese de que tiene las últimas herramientas y plantillas de Functions. Para actualizar las herramientas:
- Vaya a Herramientas>Opciones, seleccione Azure Functions en Proyectos y soluciones.
- Seleccione Buscar actualizaciones e instale las actualizaciones según se le solicite.
Durante el período de versión preliminar, el entorno de desarrollo podría tener una versión más reciente de la versión preliminar de .NET que el servicio hospedado. Esto puede hacer que se produzca un error en la aplicación de funciones cuando se implementa. Para solucionar esto, puede especificar la versión del SDK que se va a usar en
global.json
.- Ejecute el comando
dotnet --list-sdks
y anote la versión preliminar que está usando actualmente durante el desarrollo local. - Ejecute el comando
dotnet new globaljson --sdk-version <SDK_VERSION> --force
, donde<SDK_VERSION>
es la versión que usa localmente. Por ejemplo,dotnet new globaljson --sdk-version dotnet-sdk-8.0.100-preview.7.23376.3 --force
hace que el sistema use el SDK de .NET 8 Preview 7 al compilar el proyecto.
- Ejecute el comando
Nota:
Debido a la carga Just-In-Time de marcos de versión preliminar, las aplicaciones de funciones que se ejecutan en Windows pueden experimentar tiempos de inicio de acceso esporádico aumentados en comparación con las versiones anteriores de disponibilidad general.