Использование внедрения зависимостей в Функциях Azure .NET

Функции Azure поддерживают шаблон разработки программного обеспечения с внедрением зависимостей (DI), который является приемом инверсии управления (IoC) между классами и их зависимостями.

  • Внедрение зависимостей в Функциях Azure основано на функциях внедрения зависимостей .NET Core. Рекомендуется ознакомиться с Внедрением зависимостей .NET Core. Существуют различия в переопределении зависимостей и считывании значений конфигурации, если служба Функций Azure использует план потребления.

  • Поддержка внедрения зависимостей появилась в Функциях Azure 2.x.

  • Зависимости внедряются по-разному, если C# функция выполняется внутри процесса или вне процесса.

Важно!

Рекомендации в этой статье относятся только к функциям библиотеки классов C#, которые выполняются внутри процесса со средой выполнения. Эта пользовательская модель внедрения зависимостей не применяется к изолированным функциям .NET, что позволяет запускать функции .NET вне процесса. Модель изолированного рабочего процесса .NET зависит от обычных шаблонов внедрения зависимостей core ASP.NET Core. Дополнительные сведения см . в руководстве по внедрению зависимостей в руководстве по изолированному рабочему процессу .NET.

Необходимые компоненты

Прежде чем можно будет использовать внедрение зависимостей, необходимо установить следующие пакеты NuGet:

Регистрация служб

Чтобы зарегистрировать службы, создайте метод для настройки и добавления компонентов в экземпляр IFunctionsHostBuilder. Узел функций Azure создает экземпляр IFunctionsHostBuilder и передает его непосредственно в метод.

Предупреждение

Для приложений-функций, выполняющихся в планах "Потребление" или "Премиум", изменение значений конфигурации, используемых в триггерах, может привести к ошибкам масштабирования. Любые изменения этих свойств классом FunctionsStartup приводят к ошибке при запуске приложения-функции.

IConfiguration Внедрение может привести к неожиданному поведению. Дополнительные сведения о добавлении источников конфигурации см. в разделе "Настройка источников конфигурации".

Чтобы зарегистрировать метод, добавьте атрибут сборки FunctionsStartup, указывающий имя типа, используемого во время запуска.

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>();
    }
}

В этом примере используется пакет Microsoft.Extensions.Http, необходимый для регистрации HttpClient при запуске.

Предупреждения

Последовательность действий по регистрации выполняется до и после того, как среда выполнения обработает класс запуска. Поэтому помните следующие важные моменты.

  • Класс запуска предназначен только для установки и регистрации. Не используйте службы, зарегистрированные при запуске, в процессе запуска. Например, не пытайтесь зарегистрировать сообщение в средстве ведения журнала, регистрируемом во время запуска. Эта точка процесса регистрации слишком ранняя, чтобы службы были доступны для использования. Configure После запуска метода среда выполнения Функций продолжает регистрировать другие зависимости, которые могут повлиять на работу служб.

  • Контейнер внедрения зависимостей содержит только явно зарегистрированные типы. Единственными службами, доступными как внедренные типы, являются то, что настраивается в методе Configure . В результате такие относящиеся к Функциям типы, как BindingContext и ExecutionContext, недоступны во время установки или в качестве типов для внедрения.

  • Настройка проверки подлинности ASP.NET не поддерживается. Узел функций настраивает службы проверки подлинности ASP.NET для правильного предоставления API для основных операций жизненного цикла. Другие конфигурации в пользовательском Startup классе могут переопределить эту конфигурацию, что приводит к непредвиденным последствиям. Например, вызов builder.Services.AddAuthentication() может нарушить проверку подлинности между порталом и узлом, что приводит к тому, что сообщения, такие как Функции Azure среда выполнения, недоступна.

Использование внедренных зависимостей

Внедрение конструктора используется для обеспечения доступности зависимостей в функции. Использование внедрения конструктора требует, чтобы статические классы не использовались для внедренных служб или для классов функций.

В следующем примере показано, как зависимости IMyService и HttpClient вставляются в функцию, активируемую 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.");
    }
}

В этом примере используется пакет Microsoft.Extensions.Http, необходимый для регистрации HttpClient при запуске.

Время существования служб

Приложения Функций Azure предоставляют те же самые времена существования служб, что и внедрение зависимостей ASP.NET. Для приложения Функций различные времена существования службы ведут себя следующим образом.

  • Временные. Временные службы создаются при каждом разрешении службы.
  • Область действия: время существования службы область соответствует времени выполнения функции. Службы с заданной областью создаются один раз во время выполнение функции. Последующие запросы к этой службе во время выполнения повторно используют существующий экземпляр службы.
  • Singleton: время существования службы singleton соответствует времени существования узла и повторно используется во время выполнения функций в этом экземпляре. Для подключений и клиентов рекомендуется использовать службы со временем жизни «отдельная», например экземпляры DocumentClient или HttpClient.

Просмотрите или скачайте образцы служб с различными временами существования на GitHub.

Службы ведения журналов

Если вам нужен собственный поставщик средств ведения журнала, зарегистрируйте настраиваемый тип как экземпляр ILoggerProvider, доступный в пакете NuGet Microsoft.Extensions.Logging.Abstractions.

Application Insights автоматически добавляется Функциями Azure.

Предупреждение

  • Не добавляйте AddApplicationInsightsTelemetry() в коллекцию служб, иначе будут зарегистрированы службы, конфликтующие со службами, предоставляемыми средой.
  • Не регистрируйте собственные TelemetryConfiguration или TelemetryClient при использовании встроенных функций Application Insights. Если вам нужно настроить собственный экземпляр TelemetryClient, создайте его с помощью внедренной TelemetryConfiguration, как показано в разделе Запись пользовательских данных телеметрии в функциях C#.

ILogger<T> и ILoggerFactory

Узел внедряет в конструкторы службы ILogger<T> и ILoggerFactory. По умолчанию эти новые фильтры ведения журнала убираются из журналов функции. Необходимо изменить host.json файл, чтобы выбрать дополнительные фильтры и категории.

В следующем примере показано, как добавить ILogger<HttpTrigger> с журналами, которые отображаются для узла.

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.");

        // ...
}

В следующем примере файла host.json добавлен фильтр журнала.

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

Дополнительные сведения об уровнях ведения журнала см. в разделе Настройка уровней ведения журнала.

Службы, предоставляемые приложением-функцией

Узел функции регистрирует множество служб. Следующие службы можно уверенно использовать в качестве зависимости в приложении.

Тип службы Время существования Description
Microsoft.Extensions.Configuration.IConfiguration Отдельная Конфигурация среды выполнения
Microsoft.Azure.WebJobs.Host.Executors.IHostIdProvider Отдельная Отвечает за предоставление идентификатора экземпляра узла.

Если существуют другие службы, от которых требуется зависимость, создайте вопрос и предложите его на GitHub.

Переопределение служб узла

Переопределение служб, предоставляемых узлом, в настоящее время не поддерживается. Если имеются службы, которые необходимо переопределить, создайте вопрос и предложите его на GitHub.

Работа с настройками и параметрами

Значения, определенные в параметрах приложения, доступны в экземпляре IConfiguration, который позволяет считывать значения параметров приложения в классе запуска.

Значения можно извлечь из экземпляра IConfiguration в пользовательский тип. Копирование значений параметров приложения в пользовательский тип упрощает тестирование служб, делая эти значения внедряемыми. Параметры, считываемые в экземпляр конфигурации, должны быть простыми парами «ключ-значение». Для функций, выполняемых в плане Elastic Premium, имена параметров приложения могут содержать только буквы, цифры (), точки (0-9.), двоеточия (:) и символы подчеркивания (_). Дополнительные сведения см . в рекомендациях по настройке приложений.

Рассмотрим следующий класс, который включает свойство, именуемое consistent, с параметром приложения,

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

и файл local.settings.json, который может структурировать пользовательский параметр следующим образом.

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

Внутри метода Startup.Configure можно извлечь значения из экземпляра IConfiguration в пользовательский тип с помощью следующего кода.

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

Вызов Bind копирует значения, которые соответствуют именам свойств из конфигурации, в пользовательский экземпляр. Экземпляр параметров теперь доступен в контейнере IoC для внедрения в функцию.

Объект параметров внедряется в функцию как экземпляр универсального интерфейса IOptions. Используйте свойство Value для доступа к значениям, найденным в конфигурации.

using System;
using Microsoft.Extensions.Options;

public class HttpTrigger
{
    private readonly MyOptions _settings;

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

Дополнительные сведения см . в разделе "Параметры" в ASP.NET Core.

Использование секретов пользователя ASP.NET Core

При локальной разработке приложения ASP.NET Core предоставляет средство диспетчера секретов, позволяющее хранить секретную информацию за пределами корневого каталога проекта. Это уменьшает вероятность случайного попадания секретов в систему управления исходным кодом. Azure Functions Core Tools (версия 3.0.3233 или более поздняя) автоматически считывает секреты, созданные диспетчером секретов ASP.NET Core.

Чтобы настроить проект Функций Azure для .NET на использование секретов пользователя, выполните следующую команду в корневом каталоге проекта.

dotnet user-secrets init

Затем используйте команду dotnet user-secrets set для создания или обновления секретов.

dotnet user-secrets set MySecret "my secret value"

Для доступа к секретам пользователя в коде приложения-функции используйте IConfiguration или IOptions.

Настройка источников конфигурации

Чтобы указать другие источники конфигурации, переопределите ConfigureAppConfiguration метод в классе приложения-функции StartUp .

Следующий пример добавляет значения конфигурации как из базовых, так и необязательных файлов параметров приложения для конкретной среды.

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)
    {
    }
}

Добавьте поставщиков конфигурации в свойство ConfigurationBuilder у IFunctionsConfigurationBuilder. Дополнительные сведения об использовании поставщиков конфигурации см. в разделе Конфигурация в ASP.NET Core.

FunctionsHostBuilderContext берется из IFunctionsConfigurationBuilder.GetContext(). Этот контекст используется для получения имени текущей среды и определения расположения файлов конфигурации в папке приложения-функции.

По умолчанию файлы конфигурации, такие как appsettings.json не копируются автоматически в выходную папку приложения-функции. Обновите .csproj файл, чтобы он соответствовал следующему образцу, чтобы убедиться, что файлы копируются.

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

Следующие шаги

Дополнительные сведения см. на следующих ресурсах: