Menggunakan injeksi dependensi di .NET Azure Functions

Azure Functions mendukung pola desain perangkat lunak injeksi dependensi (DI), yang merupakan teknik untuk melakukan Inversion of Control (IoC) antara kelas dan dependensinya.

  • Injeksi dependensi di Azure Functions dibangun pada fitur Injeksi Dependensi Inti .NET. Sebaiknya Anda sudah memahami injeksi dependensi Inti .NET. Ada perbedaan dalam cara Anda mengganti dependensi dan bagaimana nilai konfigurasi dibaca dengan Azure Functions pada paket Konsumsi.

  • Dukungan untuk injeksi dependensi dimulai dengan Azure Functions 2.x.

  • Pola injeksi dependensi berbeda tergantung pada apakah fungsi C# Anda berjalan dalam proses atau di luar proses.

Penting

Panduan dalam artikel ini hanya berlaku untuk fungsi pustaka kelas C #, yang berjalan dalam proses dengan runtime. Model injeksi dependensi kustom ini tidak berlaku untuk fungsi terisolasi .NET, yang memungkinkan Anda menjalankan fungsi .NET di luar proses. Model proses pekerja terisolasi .NET bergantung pada pola injeksi dependensi Inti ASP.NET reguler. Untuk mempelajari lebih lanjut, lihat Injeksi dependensi dalam panduan proses pekerja terisolasi .NET.

Prasyarat

Sebelum dapat menggunakan injeksi dependensi, Anda harus menginstal paket NuGet berikut:

Mendaftarkan layanan

Untuk mendaftarkan layanan, buat metode untuk mengonfigurasi dan menambahkan komponen ke instansIFunctionsHostBuilder. Host Azure Functions membuat contoh instans IFunctionsHostBuilder dan meneruskannya langsung ke metode Anda.

Peringatan

Untuk aplikasi fungsi yang berjalan dalam paket Konsumsi atau Premium, modifikasi pada nilai konfigurasi yang digunakan dalam pemicu dapat menyebabkan kesalahan penskalaan. Setiap perubahan pada properti ini oleh kelas FunctionsStartup akan menyebabkan kesalahan startup aplikasi fungsi.

Injeksi IConfiguration dapat menyebabkan perilaku tak terduga. Untuk mempelajari selengkapnya tentang menambahkan sumber konfigurasi, lihat Menyesuaikan sumber konfigurasi.

Untuk mendaftarkan metode, tambahkan rakitan FunctionsStartup atribut yang menentukan nama tipe yang digunakan selama startup.

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

Contoh ini menggunakan paket Microsoft.Extensions.Http yang diperlukan untuk mendaftarkan HttpClient saat startup.

Peringatan

Serangkaian langkah pendaftaran berjalan sebelum dan sesudah runtime memproses kelas startup. Oleh karena itu, ingatlah item berikut:

  • Kelas startup dimaksudkan hanya untuk pengaturan dan pendaftaran. Hindari menggunakan layanan yang terdaftar di startup selama proses startup. Misalnya, jangan mencoba untuk mencatat pesan di pencatat yang sedang didaftarkan selama startup. Titik proses pendaftaran ini terlalu dini untuk menyiapkan fungsi layanan Anda. Configure Setelah metode dijalankan, runtime Functions terus mendaftarkan dependensi lain, yang dapat memengaruhi cara layanan Anda beroperasi.

  • Kontainer injeksi dependensi hanya memegang jenis yang terdaftar secara eksplisit. Satu-satunya layanan yang tersedia sebagai jenis injeksi adalah apa yang disiapkan dalam Configure metode . Akibatnya, tipe spesifik Fungsi seperti BindingContext dan tidak tersedia selama pengaturan atau sebagai tipe ExecutionContext suntik.

  • Mengonfigurasi autentikasi ASP.NET tidak didukung. Host Functions mengonfigurasi layanan autentikasi ASP.NET untuk mengekspos API dengan benar untuk operasi siklus hidup inti. Konfigurasi lain di kelas kustom Startup dapat mengambil alih konfigurasi ini, menyebabkan konsekuensi yang tidak diinginkan. Misalnya, panggilan builder.Services.AddAuthentication() dapat memutuskan autentikasi antara portal dan host, yang mengarah ke pesan seperti runtime Azure Functions tidak dapat dijangkau.

Gunakan dependensi yang disuntikkan

Injeksi konstruktor digunakan untuk membuat dependensi Anda tersedia dalam fungsi. Penggunaan injeksi konstruktor mengharuskan Anda tidak menggunakan kelas statis untuk layanan yang disuntikkan atau untuk kelas fungsi Anda.

Contoh berikut menunjukkan bagaimana dependensi IMyService dan HttpClient disuntikkan ke fungsi yang dipicu 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.");
    }
}

Contoh ini menggunakan paket Microsoft.Extensions.Http yang diperlukan untuk mendaftarkan HttpClient saat startup.

Masa pakai layanan

Aplikasi Azure Functions menyediakan masa pakai layanan yang sama seperti Injeksi Dependensi ASP.NET . Untuk aplikasi Functions, masa pakai layanan yang berbeda berperilaku sebagai berikut:

  • Sementara :Layanan sementara dibuat berdasarkan setiap resolusi layanan.
  • Tercakup:Masa pakai tercakup sesuai dengan masa pakai eksekusi fungsi. Layanan tercakup dibuat sekali per eksekusi fungsi. Kemudian permintaan untuk layanan tersebut selama eksekusi menggunakan kembali instans layanan yang ada.
  • Singleton: Masa pakai singleton cocok dengan masa pakai host dan digunakan kembali di seluruh eksekusi fungsi pada instans tersebut. Layanan seumur hidup Singleton direkomendasikan untuk koneksi dan klien, misalnya instans DocumentClient atauHttpClient.

Lihat atau unduh sampel masa pakai layanan yang berbeda di GitHub.

Layanan pengelogan

Jika Anda memerlukan penyedia pembuatan log Anda sendiri, daftarkan jenis kustom sebagai contoh ILoggerProvider, yang tersedia melalui paket NuGetMicrosoft.Extensions.Logging.Abstractions.

Application Insights ditambahkan oleh Azure Functions secara otomatis.

Peringatan

  • Jangan tambahkan AddApplicationInsightsTelemetry() ke koleksi layanan, yang mendaftarkan layanan yang bertentangan dengan layanan yang disediakan oleh lingkungan.
  • Jangan daftarkan TelemetryConfiguration atau TelemetryClient sendiri jika Anda menggunakan fungsionalitas Application Insights bawaan. Jika Anda perlu mengonfigurasi instans TelemetryClient Anda sendiri, buat instans Anda melalui instans injeksi TelemetryConfiguration seperti yang ditunjukkan dalam Log telemetri kustom dalam fungsi C #.

ILogger<T> dan ILoggerFactory

Host menginjeksi layanan ILogger<T>dan ILoggerFactory ke konstruktor. Namun, secara default filter logging baru ini difilter keluar dari log fungsi. Anda perlu mengubah host.json file untuk ikut serta dalam filter dan kategori tambahan.

Contoh berikut menunjukkan cara menambahkan log ILogger<HttpTrigger> yang diekspos ke 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.");

        // ...
}

Contoh file host.json berikut menambahkan filter log.

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

Untuk informasi selengkapnya tentang tingkat log, lihat Mengonfigurasi tingkat log.

Aplikasi fungsi yang disediakan layanan

Host fungsi mendaftarkan banyak layanan. Layanan berikut ini aman untuk diambil sebagai dependensi dalam aplikasi Anda:

Jenis Layanan Seumur hidup Deskripsi
Microsoft.Extensions.Configuration.IConfiguration Singleton Konfigurasi runtime
Microsoft.Azure.WebJobs.Host.Executors.IHostIdProvider Singleton Bertanggung jawab untuk memberikan ID instans host

Jika ada layanan lain yang ingin Anda ambil dependensinya, buat masalah dan usulkan di GitHub.

Menimpa layanan host

Layanan penimpa yang disediakan oleh host saat ini tidak didukung. Jika ada layanan yang ingin Anda ganti, buat masalah dan usulkan di GitHub.

Bekerja dengan opsi dan pengaturan

Nilai yang ditentukan dalam pengaturan aplikasi yang tersedia dalam instans IConfiguration, yang memungkinkan Anda membaca nilai pengaturan aplikasi di kelas startup.

Anda dapat mengekstrak nilai dari IConfiguration instans menjadi tipe kustom. Menyalin nilai pengaturan aplikasi ke jenis kustom memudahkan pengujian layanan Anda dengan membuat nilai-nilai ini dapat diinjeksi. Pengaturan yang dibaca ke dalam instans konfigurasi haruslah pasangan kunci/nilai sederhana. Untuk fungsi yang berjalan dalam paket Elastic Premium, nama pengaturan aplikasi hanya dapat berisi huruf, angka (0-9), titik (.), titik dua (:) dan garis bawah (_). Untuk informasi selengkapnya, lihat Pertimbangan pengaturan aplikasi.

Pertimbangkan kelas berikut yang menyertakan properti bernama yang konsisten dengan setelan aplikasi:

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

Dan file local.settings.json yang mungkin menata pengaturan kustom sebagai berikut:

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

Dari dalam metode Startup.Configure, Anda dapat mengekstrak nilai dari instans IConfiguration menjadi tipe kustom Anda menggunakan kode berikut:

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

Memanggil nilai salinan Bind yang memiliki nama properti yang cocok dari konfigurasi ke dalam instans kustom. Pilihan instans sekarang tersedia dalam wadah IoC untuk diinjeksikan ke fungsi.

Objek opsi disuntikkan ke fungsi sebagai instans antarmuka IOptions generik. Gunakan properti Value untuk mengakses nilai yang ditemukan dalam konfigurasi Anda.

using System;
using Microsoft.Extensions.Options;

public class HttpTrigger
{
    private readonly MyOptions _settings;

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

Untuk informasi selengkapnya, lihat Pola opsi di ASP.NET Core.

Menggunakan rahasia pengguna ASP.NET Core

Saat Anda mengembangkan aplikasi secara lokal, ASP.NET Core menyediakan alat Secret Manager yang memungkinkan Anda menyimpan informasi rahasia di luar akar proyek. Hal ini mencegah rahasia secara tidak sengaja diterapkan pada kontrol sumber. Azure Functions Core Tools (versi 3.0.3233 atau yang lebih baru) secara otomatis membaca rahasia yang dibuat Secret Manager dari ASP.NET Core.

Untuk mengonfigurasi proyek .NET Azure Functions untuk menggunakan rahasia pengguna, jalankan perintah berikut di root proyek.

dotnet user-secrets init

Kemudian gunakan perintah dotnet user-secrets set untuk membuat atau memperbarui rahasia.

dotnet user-secrets set MySecret "my secret value"

Untuk mengakses nilai rahasia pengguna dalam kode aplikasi fungsi Anda, gunakan IConfiguration atau IOptions.

Mengkustomisasi sumber konfigurasi

Untuk menentukan sumber konfigurasi lain, ambil alih ConfigureAppConfiguration metode di kelas aplikasi StartUp fungsi Anda.

Sampel berikut menambahkan nilai konfigurasi dari file pengaturan aplikasi dasar dan lingkungan khusus lingkungan opsional.

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

Tambahkan penyedia konfigurasi ke properti ConfigurationBuilder dari IFunctionsConfigurationBuilder. Untuk informasi selengkapnya tentang menggunakan penyedia konfigurasi, lihat Konfigurasi di ASP.NET Core.

FunctionsHostBuilderContext diperoleh dari IFunctionsConfigurationBuilder.GetContext(). Gunakan konteks ini untuk mengambil nama lingkungan saat ini dan mengatasi lokasi file konfigurasi di folder aplikasi fungsi Anda.

Secara default, file konfigurasi seperti appsettings.json tidak disalin secara otomatis ke folder output aplikasi fungsi. Perbarui file Anda .csproj agar sesuai dengan sampel berikut untuk memastikan file disalin.

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

Langkah berikutnya

Untuk informasi selengkapnya, lihat sumber daya berikut: