Compartir a través de


Usar la inserción de dependencias en Azure Functions con .NET

Azure Functions admite el patrón de diseño de software de inserción de dependencias (DI), que es una técnica para lograr la inversión de control (IoC) entre las clases y sus dependencias.

  • La inserción de dependencias en Azure Functions se basa en las características de inserción de dependencias de .NET Core. Se recomienda estar familiarizado con la inserción de dependencias de .NET Core . Hay diferencias en el modo en que se invalidan las dependencias y cómo se leen los valores de configuración con Azure Functions en el plan de consumo.

  • La compatibilidad con la inserción de dependencias comienza con Azure Functions 2.x.

  • Los patrones de inserción de dependencias difieren en función de si las funciones de C# se ejecutan en proceso o fuera de proceso.

Importante

Las instrucciones de este artículo solo se aplican a las funciones de biblioteca de clases de C#, que se ejecutan en proceso con el runtime. Este modelo de inserción de dependencias personalizado no se aplica a las funciones aisladas de .NET, lo que le permite ejecutar funciones de .NET fuera de proceso. El modelo de proceso de trabajo aislado de .NET se basa en patrones normales de inserción de dependencias de ASP.NET Core. Para más información, consulte Inserción de dependencias en la guía del proceso de trabajo aislado de .NET.

Prerrequisitos

Para poder usar la inserción de dependencias, debe instalar los siguientes paquetes NuGet:

Registrar servicios

Para registrar servicios, cree un método para configurar y agregar componentes a una IFunctionsHostBuilder instancia. El host de Azure Functions crea una instancia de IFunctionsHostBuilder y la pasa directamente al método .

Advertencia

En el caso de las aplicaciones de funciones que se ejecutan en los planes de consumo o Premium, las modificaciones de los valores de configuración usados en desencadenadores pueden provocar errores de escalado. Los cambios realizados en estas propiedades por la FunctionsStartup clase producen un error de inicio de la aplicación de funciones.

La inyección de IConfiguration puede provocar un comportamiento inesperado. Para más información sobre cómo agregar orígenes de configuración, consulte Personalización de orígenes de configuración.

Para registrar el método, agregue el FunctionsStartup atributo de ensamblado que especifica el nombre de tipo usado durante el inicio.

using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;

[assembly: FunctionsStartup(typeof(MyNamespace.Startup))]

namespace MyNamespace;

public class Startup : FunctionsStartup
{
    public override void Configure(IFunctionsHostBuilder builder)
    {
        builder.Services.AddHttpClient();

        builder.Services.AddSingleton<IMyService>((s) => {
            return new MyService();
        });

        builder.Services.AddSingleton<ILoggerProvider, MyLoggerProvider>();
    }
}

En este ejemplo se usa el paquete Microsoft.Extensions.Http necesario para registrar una HttpClient en el inicio.

Advertencias

Una serie de pasos de registro se ejecutan antes y después de que el entorno de ejecución procesa la clase de inicio. Por lo tanto, tenga en cuenta los siguientes elementos:

  • La clase de inicio está pensada solo para la configuración y el registro. Evite utilizar servicios registrados al inicio durante el proceso de arranque. Por ejemplo, no intente registrar un mensaje en un registrador que se está registrando durante el inicio. Este punto del proceso de registro es demasiado temprano para que los servicios estén disponibles para su uso. Una vez ejecutado el Configure método , el entorno de ejecución de Functions continúa registrando otras dependencias, lo que puede afectar a cómo funcionan los servicios.

  • El contenedor de inserción de dependencias solo contiene tipos registrados explícitamente. Los únicos servicios disponibles como tipos inyectables son los que se configuran en el Configure método . Como resultado, los tipos específicos de Functions como BindingContext y ExecutionContext no están disponibles durante la instalación o como tipos inyectables.

  • No se admite configurar la autenticación de ASP.NET. El host de Functions configura los servicios de autenticación de ASP.NET para exponer adecuadamente las API para las operaciones centrales del ciclo de vida. Otras configuraciones de una clase personalizada Startup pueden invalidar esta configuración, lo que provoca consecuencias imprevistas. Por ejemplo, la llamada builder.Services.AddAuthentication() puede interrumpir la autenticación entre el portal y el host, lo que provoca que los mensajes como el entorno de ejecución de Azure Functions no sean accesibles.

Uso de dependencias insertadas

La inserción de constructores se usa para que las dependencias estén disponibles en una función. El uso de la inserción de constructores requiere que no use clases estáticas para los servicios insertados o para las clases de función.

En el ejemplo siguiente se muestra cómo se insertan las IMyService dependencias y HttpClient en una función desencadenada por HTTP.

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Extensions.Logging;
using System.Net.Http;
using System.Threading.Tasks;

namespace MyNamespace;

public class MyHttpTrigger
{
    private readonly HttpClient _client;
    private readonly IMyService _service;

    public MyHttpTrigger(IHttpClientFactory httpClientFactory, IMyService service)
    {
        this._client = httpClientFactory.CreateClient();
        this._service = service;
    }

    [FunctionName("MyHttpTrigger")]
    public async Task<IActionResult> Run(
        [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
        ILogger log)
    {
        var response = await _client.GetAsync("https://microsoft.com");
        var message = _service.GetMessage();

        return new OkObjectResult("Response from function with injected dependencies.");
    }
}

En este ejemplo se usa el paquete Microsoft.Extensions.Http necesario para registrar una HttpClient en el inicio.

Duración del servicio

Las aplicaciones de Azure Functions proporcionan la misma vigencia de servicio que la inserción de dependencias de ASP.NET. Para una aplicación de Functions, las distintas duraciones de servicio se comportan de la siguiente manera:

  • Transitorio: los servicios transitorios se crean en cada resolución del servicio.
  • Alcance: la duración del servicio con ámbito coincide con una duración de ejecución de función. Los servicios con ámbito se crean una vez por ejecución de función. Las solicitudes posteriores de ese servicio durante la ejecución reutilizan la instancia de servicio existente.
  • Singleton: la duración del servicio singleton coincide con la duración del host y se reutiliza en las ejecuciones de función de esa instancia. Los servicios de vigencia singleton se recomiendan para conexiones y clientes, por ejemplo, para instancias DocumentClient o HttpClient.

Vea o descargue un ejemplo de diferentes duraciones de servicio en GitHub.

Registro de servicios

Si necesita su propio proveedor de registro, registre un tipo personalizado como instancia de ILoggerProvider, disponible mediante el paquete NuGet Microsoft.Extensions.Logging.Abstractions.

Azure Functions agrega Application Insights automáticamente.

Advertencia

  • No agregue AddApplicationInsightsTelemetry() a la colección de servicios, que registra los servicios que entran en conflicto con los servicios proporcionados por el entorno.
  • No registre su propio TelemetryConfiguration ni TelemetryClient si usa la funcionalidad de Application Insights integrada. Si tiene que configurar su propia instancia de TelemetryClient, cree una a través de la TelemetryConfiguration insertada, tal como se muestra en Registrar telemetría personalizada en funciones de C#.

ILogger<T> y ILoggerFactory

El host insertará los servicios ILogger<T> e ILoggerFactory en constructores. Sin embargo, de forma predeterminada, estos nuevos filtros de registro se filtran de los registros de funciones. Debe modificar el host.json archivo para participar en filtros y categorías adicionales.

En el ejemplo siguiente se muestra cómo agregar un ILogger<HttpTrigger> con registros que se exponen al host.

namespace MyNamespace;

public class HttpTrigger
{
    private readonly ILogger<HttpTrigger> _log;

    public HttpTrigger(ILogger<HttpTrigger> log)
    {
        _log = log;
    }

    [FunctionName("HttpTrigger")]
    public async Task<IActionResult> Run(
        [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req)
    {
        _log.LogInformation("C# HTTP trigger function processed a request.");

        // ...
}

En el siguiente archivo de ejemplo host.json se agrega el filtro de registro.

{
    "version": "2.0",
    "logging": {
        "applicationInsights": {
            "samplingSettings": {
                "isEnabled": true,
                "excludedTypes": "Request"
            }
        },
        "logLevel": {
            "MyNamespace.HttpTrigger": "Information"
        }
    }
}

Para obtener más información sobre los niveles de registro, consulte Configuración de los niveles de registro.

Servicios proporcionados por la aplicación de funciones

El servidor de funciones registra muchos servicios. Los siguientes servicios son seguros para tomar como dependencia en la aplicación:

Tipo de servicio Duración Descripción
Microsoft.Extensions.Configuration.IConfiguration Singleton Configuración del entorno en tiempo de ejecución
Microsoft.Azure.WebJobs.Host.Executors.IHostIdProvider Singleton Responsable de proporcionar el identificador de la instancia de host

Si hay otros servicios en los que quiere depender, cree un problema y propongolos en GitHub.

Invalidación de los servicios de host

Actualmente no se admite la sobrescritura de los servicios proporcionados por el host. Si hay servicios que desea invalidar, cree un problema y propongolos en GitHub.

Trabajar con opciones y configuraciones

Los valores definidos en la configuración de la aplicación están disponibles en una IConfiguration instancia, lo que permite leer los valores de configuración de la aplicación en la clase de inicio.

Puede extraer valores de la instancia de IConfiguration a un tipo personalizado. Copiar los valores de configuración de la aplicación a un tipo personalizado facilita la realización de pruebas en tus servicios, permitiendo que estos valores se puedan inyectar fácilmente. La configuración leída en la instancia de configuración debe ser pares clave-valor simples. En el caso de las funciones que se ejecutan en un plan de Elastic Premium, los nombres de configuración de la aplicación solo pueden contener letras, números (0-9), puntos (.), dos puntos (:) y caracteres de subrayado (_). Para obtener más información, consulte Consideraciones sobre la configuración de la aplicación.

Tenga en cuenta la siguiente clase que incluye una propiedad denominada coherente con una configuración de aplicación:

public class MyOptions
{
    public string MyCustomSetting { get; set; }
}

Y un local.settings.json archivo que podría estructurar la configuración personalizada de la siguiente manera:

{
  "IsEncrypted": false,
  "Values": {
    "MyOptions:MyCustomSetting": "Foobar"
  }
}

Desde el método Startup.Configure, puede extraer valores de la instancia IConfiguration a su tipo personalizado utilizando el siguiente código:

builder.Services.AddOptions<MyOptions>()
    .Configure<IConfiguration>((settings, configuration) =>
    {
        configuration.GetSection("MyOptions").Bind(settings);
    });

Al llamar a Bind, se copian los valores que tienen nombres de propiedad coincidentes de la configuración a la instancia personalizada. La instancia de opciones ya está disponible en el contenedor de IoC para insertarla en una función.

El objeto options se inserta en la función como una instancia de la interfaz genérica IOptions . Use la Value propiedad para acceder a los valores que se encuentran en la configuración.

using System;
using Microsoft.Extensions.Options;

public class HttpTrigger
{
    private readonly MyOptions _settings;

    public HttpTrigger(IOptions<MyOptions> options)
    {
        _settings = options.Value;
    }
}

Para obtener más información, consulte Patrón de opciones en ASP.NET Core.

Uso de secretos de usuario de ASP.NET Core

Al desarrollar la aplicación localmente, ASP.NET Core proporciona una herramienta administrador de secretos que permite almacenar información secreta fuera de la raíz del proyecto. De este modo, es menos probable que los secretos se confirmen accidentalmente en el control de código fuente. Azure Functions Core Tools (versión 3.0.3233 o posterior) lee automáticamente los secretos creados por ASP.NET Core Secret Manager.

Para configurar un proyecto de Azure Functions de .NET para usar secretos de usuario, ejecute el siguiente comando en la raíz del proyecto.

dotnet user-secrets init

A continuación, use el dotnet user-secrets set comando para crear o actualizar secretos.

dotnet user-secrets set MySecret "my secret value"

Para acceder a los valores de secretos de usuario en el código de la aplicación de funciones, use IConfiguration o IOptions.

Personalización de orígenes de configuración

Para especificar otros orígenes de configuración, sobrescriba el método ConfigureAppConfiguration en la clase StartUp de la aplicación de funciones.

En el ejemplo siguiente se agregan valores de configuración de archivos de configuración básicos y opcionales específicos de la aplicación.

using System.IO;
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

[assembly: FunctionsStartup(typeof(MyNamespace.Startup))]

namespace MyNamespace;

public class Startup : FunctionsStartup
{
    public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
    {
        FunctionsHostBuilderContext context = builder.GetContext();

        builder.ConfigurationBuilder
            .AddJsonFile(Path.Combine(context.ApplicationRootPath, "appsettings.json"), optional: true, reloadOnChange: false)
            .AddJsonFile(Path.Combine(context.ApplicationRootPath, $"appsettings.{context.EnvironmentName}.json"), optional: true, reloadOnChange: false)
            .AddEnvironmentVariables();
    }
    
    public override void Configure(IFunctionsHostBuilder builder)
    {
    }
}

Agregue proveedores de configuración a la ConfigurationBuilder propiedad de IFunctionsConfigurationBuilder. Para obtener más información sobre el uso de proveedores de configuración, consulte Configuración en ASP.NET Core.

Un FunctionsHostBuilderContext se obtiene de IFunctionsConfigurationBuilder.GetContext(). Use este contexto para recuperar el nombre del entorno actual y resolver la ubicación de los archivos de configuración en la carpeta de la aplicación de funciones.

De forma predeterminada, los archivos de configuración como appsettings.json no se copian automáticamente en la carpeta de salida de la aplicación de funciones. Actualice el .csproj archivo para que coincida con el ejemplo siguiente para asegurarse de que se copian los archivos.

<None Update="appsettings.json">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>      
</None>
<None Update="appsettings.Development.json">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    <CopyToPublishDirectory>Never</CopyToPublishDirectory>
</None>

Pasos siguientes

Para obtener más información, consulte los siguientes recursos: