yotiky Tech Blog

とあるエンジニアの備忘録

MRTK v2 - チートシート

目次

検証環境

  • MRTK 2.5.3

機能

Profiles

Spatial Awareness

  • Clone する Profile ファミリー
    • DefaultHoloLens2ConfigurationProfile
    • DefaultMixedRealitySpatialAwarenessSystemProfile
  • 設定
    • DefaultHololens2ConfigurationProfile をクローン
    • MixedRealityToolkit スクリプト > Spatial Awareness セクション で [Enable Spatial Awareness] を ON
    • DefaultMixedRealitySpatialAwarenessSystemProfile をクローン

yotiky.hatenablog.com

ハンドメッシュを表示する

  • Clone する Profile ファミリー
    • DefaultHoloLens2ConfigurationProfile
    • DefaultHoloLens2InputSystemProfile
    • DefaultHoloLens2HandTrackingProfile
  • 設定

    • DefaultHololens2ConfigurationProfile をクローン
    • DefaultHoloLens2InputSystemProfile をクローン
    • DefaultHoloLens2HandTrackingProfile をクローン
    • [Hand Mesh Visualization Modes] で [Player] を選択する

    f:id:yotiky:20210131162954p:plain:w280 f:id:yotiky:20210131163013p:plain:w100

  • Experimental で Pulse メッシュが含まれている

    f:id:yotiky:20210131163556p:plain:w200 f:id:yotiky:20210131163005p:plain:w200

    Pulse shader | Mixed Reality Toolkit Documentation

Mixed Reality Capture (MRC) でハンドメッシュがズレる

  • MixedRealityToolkitConfigurationProfile の Camera の項目で、DefaultHoloLens2CameraProfile をクローン
  • CameraSettingsProviders の DefaultWindowsMixedRealityCameraSettingsProfile をクローンして [Render from PV Camera] をONにする
  • Render from the PV camera (opt-in)

RiggedHandVisualizer (Experimental)

  • f:id:yotiky:20210125044256p:plain:w200
  • Clone する Profile ファミリー
    • DefaultHoloLens2ConfigurationProfile
    • DefaultHoloLens2InputSystemProfile
    • DefaultMixedRealityControllerVisualizationProfile
  • 設定
    • DefaultHololens2ConfigurationProfile をクローン
    • DefaultHoloLens2InputSystemProfile をクローン
    • DefaultMixedRealityControllerVisualizationProfile をクローン
    • Global Left Hand Visualizer および Global Right Hand VisualizerRiggedHandLeft(Right) を設定 f:id:yotiky:20210125044113p:plain

Object Manipulator

Bounds Control

Constraint Manager

Transform の動きに制約を適用できる

Interactable (TODO)

Button

  • MRTK Toolbox もしくは Packages/com.microsoft.mixedreality.toolkit.foundation/SDK/Features/UX/Interactable/Prefabs から追加 f:id:yotiky:20210125032414p:plain

  • 基本的な設定は Button Config Helper コンポーネント

    • OnClick イベントに処理を登録する
    • 見た目を変更する
  • アイコンを追加するには、Icon Set を作成する

yotiky.hatenablog.com

yotiky.hatenablog.com

Keyboard

  • 実機でしか表示されない
public TextMeshPro tmp;
private TouchScreenKeyboard keyboard;

public void OpenKeyboard()
{
    keyboard = TouchScreenKeyboard.Open("", TouchScreenKeyboardType.Default, false, false, false, false);
}

void Update()
{
    if (keyboard != null)
    {
        tmp.text = keyboard.text;
    }
}

Slate

Solver (TODO)

Object Collection (TODO)

Scroll Object Collection (TODO)

Tooltip (TODO)

Slider (TODO)

Progress Indicator (TODO)

Hand Menu (TODO)

Near Menu

  • MRTK Toolbox もしくは Packages/com.microsoft.mixedreality.toolkit.foundation/SDK/Features/UX/Prefabs/Menus から追加 f:id:yotiky:20210125031316p:plain

yotiky.hatenablog.com

App Bar (TODO)

Dialog (Experimental) (TODO)

Hand Coach (Experimental) (TODO)

Pulse Shader (Experimental)

Spatial Awareness

  • Clone する Profile ファミリー
    • DefaultHoloLens2ConfigurationProfile
    • DefaultMixedRealitySpatialAwarenessSystemProfile
    • DefaultMixedRealitySpatialAwarenessMeshObserverProfile
  • 設定
    • Material を新規作成し、SR_Triangles シェーダーに設定し MRTK_Pulse_SpatialMeshBlue もしくは Purple からプロパティをコピーする
    • [Auto Pulse] のチェックをONにする
      • ライブラリに含まれているマテリアルは、OFFになっているのでスクリプトなどから有効にする必要がある
    • DefaultHololens2ConfigurationProfile をクローン
    • MixedRealityToolkit スクリプト > Spatial Awareness セクション で [Enable Spatial Awareness] を ON
    • DefaultMixedRealitySpatialAwarenessSystemProfile をクローン
    • DefaultMixedRealitySpatialAwarenessMeshObserverProfile をクローン
    • Display Settings の Visible Material に 作成したマテリアルを設定する

f:id:yotiky:20210131164752p:plain:w300 f:id:yotiky:20210131164805p:plain:w200

ハンドメッシュ

  • 必要な手順は「ハンドメッシュを表示する」の項目を参照
  • Hand Mesh Prefab に Packages/com.microsoft.mixedreality.toolkit.foundation/SDK/StandardAssets/Prefabs/ArticulatedHandMeshPulse.prefab を設定する

f:id:yotiky:20210131162954p:plain:w300 f:id:yotiky:20210131163556p:plain:w200

Dock (Experimental) (TODO)

ElasticSystem (TODO)

Joy Stick

  • Packages/com.microsoft.mixedreality.toolkit.foundation/SDK/Experimental/Joystick/JoystickPrefab.prefab から追加 f:id:yotiky:20210125035321p:plain
  • Target Object に対象を登録する

Azure Managed ID を利用する

目次

概要

Managed ID は、 Azure Active Directory (Azure AD) で提供されるリソースに割り当てられた ID 。 Managed ID を有効にすることで Azure AD による管理と資格情報を使わないサービス間の認証を可能にする。

以前は Azure Managed Service ID の名称だった。

Managed ID の種類は2種類。

  • システム割り当て

    リソースに対して Azure AD によって作成される。ライフサイクルはリソースとひも付き、リソースに対して1対1となる。

  • ユーザー割り当て

    各リソースとは別にスタンドアローンとして作成される。ライフサイクルは独自になり、複数のリソースに割り当てて共有することができる。

docs.microsoft.com

f:id:yotiky:20210131142751p:plain(引用)

基本的な流れ。

  • Managed ID をサポートするサービス(Source)に対して ID を有効にする。
  • Azure AD 認証をサポートしているサービス(Target)に対して、上記 ID にアクセスを割り当てる。
  • プログラムからは接続情報などは用いず、各 Target のエンドポイントを使ってアクセスする。

docs.microsoft.com

Azure Functions にアクセスを割り当てる場合

対象の Azure Functions を開いて設定から ID を選択する。

f:id:yotiky:20210130214151p:plain:w300

システム割り当て済みをオンにする。

f:id:yotiky:20210130214226p:plain:w300

例えば App Configuration や Azure Storage を開いてアクセス制御(IAM)を選択し、Functions にロールの割り当てを追加する。

f:id:yotiky:20210131031856p:plain

Azure Key Vault ではアクセス制御(IAM)ではなく、アクセスポリシーを使って許可を与える。シークレット、キー、証明書に対して、各リソースがどのような操作を実行できるかを細かく設定できる。

f:id:yotiky:20210131150500p:plain

Azure Key Vault アクセス ポリシーを割り当てる (ポータル) | Microsoft Docs

プログラムからは、App Configuration の設定のアクセスキーからエンドポイントを取得してこれを使って接続する。

class Startup : FunctionsStartup
{
    public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
    {
        
        builder.ConfigurationBuilder.AddAzureAppConfiguration(options =>
                options.Connect(new Uri(builtConfig["AppConfigEndpoint"]), new ManagedIdentityCredential()));
    }
}

マネージド ID を使用して App Configuration にアクセスする - Azure App Configuration | Microsoft Docs

Blob ストレージの場合。

    var containerEndpoint = string.Format("https://{0}.blob.core.windows.net/{1}",
                                                accountName,
                                                containerName);
    var containerClient = new BlobContainerClient(new Uri(containerEndpoint),
                                                                    new DefaultAzureCredential());

マネージド ID を使用してデータへのアクセスを認証する - Azure Storage | Microsoft Docs

Key Vault もエンドポイントを使って接続する。

class Startup : FunctionsStartup
{
    public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
    {
            var builtConfig = builder.ConfigurationBuilder.Build();

            builder.ConfigurationBuilder.AddAzureKeyVault(new Uri(builtConfig["KeyVaultEndpoint"]), new DefaultAzureCredential());
    }
}

関連記事

参考

Azure Functions で Azure App Configuration から設定を読み込む

Azure App Configuration は複数のアプリケーションで、アプリケーション設定と機能フラグを一元に管理し共有するサービス。

目次

App Configuration を設定する

Azure App Configuration を作成する。

操作の構成エクスプローラーから「鍵」と「値」を追加する。

f:id:yotiky:20210131021953p:plain

App Configuration ストアに接続する

接続文字列

実装

作成した App Configuration の設定からアクセスキーを選択し、読み取り専用キーから接続文字列をコピーする。

f:id:yotiky:20210131021159p:plain

Functions のアプリケーション設定に接続文字列を登録する。

f:id:yotiky:20210131024550p:plain

Nuget で Azure.Extensions.AspNetCore.Configuration.Secrets をインストールする。

Statup クラスで、接続文字列を使って Azure App Configuration プロバイダーを追加する。

class Startup : FunctionsStartup
{
    public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
    {
        builder.ConfigurationBuilder.AddAzureAppConfiguration(builtConfig["AppConfigConnectionString"]);
    }
}

Functions 側は インジェクションした IConfiguration から App Configuration に追加した鍵で取得できる。

    public class Function1
    {
        private readonly IConfiguration _configuration;
        public Function1(IConfiguration configuration)
        {
            _configuration = configuration;
        }

        [FunctionName("Function1")]
        public async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogInformation(_configuration["AppConfig:ConnectionString"]);

            return new OkObjectResult("This HTTP triggered function executed successfully.");
        }
    }

エンドポイント

Azure Functions に Managed Id を設定

デプロイ済みの Azure Functions の設定から ID を選択する。

f:id:yotiky:20210130214151p:plain:w300

システム割り当て済みをオンにする。

f:id:yotiky:20210130214226p:plain:w300

App Configuration へのアクセスの許可

App Configuration のアクセス制御(IAM)を選択し、Functions にロールの割り当てを追加する。

f:id:yotiky:20210131031856p:plain

実装

App Configuration の設定で読み取り専用キーからエンドポイントをコピーする。

Functions のアプリケーション設定にエンドポイントを登録する。

f:id:yotiky:20210131024550p:plain

Statup クラスで、エンドポイントを使って Azure App Configuration プロバイダーを追加する。 Functions 側は接続文字列の項目と同じ。

class Startup : FunctionsStartup
{
    public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
    {
        
        builder.ConfigurationBuilder.AddAzureAppConfiguration(options =>
                options.Connect(new Uri(builtConfig["AppConfigEndpoint"]), new ManagedIdentityCredential()));
    }
}

関連記事

yotiky.hatenablog.com

Azure Functions で Startup クラスを定義して DI を利用する

Azure Functions は、v2 で DI を正式にサポート。

Startup クラスを(自分で)定義し、 DI を設定することで Azure Functions にインジェクションすることができるようになる。

目次

検証環境

  • Azure Functions v3
  • Microsoft.Azure.Functions.Extensions v1.1.0
  • Microsoft.Extensions.Http v3.1.11
    • v5.0.0 だとMicrosoft .Extentions.DependencyInjection のライブラリがバージョン不一致を起こす
  • Azure.Extensions.AspNetCore.Configuration.Secrets v1.0.2
  • Microsoft.Extensions.Configuration.AzureKeyVault v3.1.11
  • Microsoft.Azure.Services.AppAuthentication v1.6.0
  • Microsoft.Azure.KeyVault v3.0.5
  • Microsoft.Extensions.Azure v1.0.0

インストール

Nuget で Microsoft.Azure.Functions.Extensions をインストールする。

使い方

基本的な使い方

今回は DI するために適当なクラスを用意する。

public interface IMyService { }
public class MyServiceA : IMyService { }
public class MyServiceB : IMyService { }
public class MyServiceC : IMyService { }

まず FunctionsStartup を継承した Statup クラスを新規作成する。

using Microsoft.Azure.Functions.Extensions.DependencyInjection;

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

namespace FunctionApp1
{
    class Startup : FunctionsStartup
    {
        public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
        {
            base.ConfigureAppConfiguration(builder);
        }
        public override void Configure(IFunctionsHostBuilder builder)
        {
            builder.Services.AddTransient<MyServiceA>();
            builder.Services.AddTransient<IMyService, MyServiceA>();

            builder.Services.AddScoped<MyServiceB>();
            builder.Services.AddScoped<IMyService, MyServiceB>();

            builder.Services.AddSingleton<MyServiceC>();
            builder.Services.AddSingleton<IMyService, MyServiceC>();
        }
    }
}

アセンブリ属性FunctionsStartupAttributeStartup クラスを指定する。

IFunctionsHostBuilder を使ってサービスを登録する。登録メソッドは登録するサービスの有効期間毎に別れており、各インスタンスの有効期間は以下の3通りになる。

  • 一時的(Transient)
  • スコープ(Scoped)
    • Function(関数)実行ごとに1回生成される
  • シングルトン(Singleton)
    • ホストの有効期間と一致する
    • DocumentClientHttpClient など接続やクライアントに推奨されている

なお IFunctionsConfigurationBuilderFunctionsHostBuilderContext を取得すると以下の3つの値が取得できる。

    var context = builder.GetContext();
    var rootPath = context.ApplicationRootPath;
    var configuration = context.Configuration;
    var environment = context.EnvironmentName;      


関数側は、 Azure Functions のクラスとメソッドの static を外し、コンストラクタを実装してインジェクションするための引数を追加する。

public class Function1
{
    private readonly MyServiceA _serviceA;
    private readonly MyServiceB _serviceB;
    private readonly MyServiceC _serviceC;
    private readonly IMyService _service;

    public Function1(
        MyServiceA serviceA,
        MyServiceB serviceB,
        MyServiceC serviceC,
        IMyService service)
    {
        _serviceA = serviceA;
        _serviceB = serviceB;
        _serviceC = serviceC;
        // 3つの有効期間で同じインターフェイスを登録してると Scoped のインスタンスが入ってくるらしい
        _service = service;
    }

    [FunctionName("Function1")]
    public async Task<IActionResult> Run(
        [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
        ILogger log)
    {
        return new OkObjectResult("This HTTP triggered function executed successfully.");
    }
}

参考:

環境変数を設定する

IConfigurationStartup クラスの中で何もしなくてもインジェクションされる。ローカル実行時も ConfigurationBuilder と違い明示的に local.settings.json を追加しなくて良い。

    public class Function1
    {
        private readonly IConfiguration _configuration;
        public Function1(IConfiguration configuration)
        {
            _configuration = configuration;
        }

        [FunctionName("Function1")]
        public async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogInformation(_configuration["AzureWebJobsStorage"]);
            log.LogInformation(_configuration["APPLICTION_SETTINGS_VALUE"]);
            log.LogInformation(_configuration.GetConnectionString("DB_CONNECTION_STRING"));

            return new OkObjectResult("This HTTP triggered function executed successfully.");
        }
    }

f:id:yotiky:20210128210604p:plain

f:id:yotiky:20210129211630p:plain

HttpClient を利用する

Nuget で Microsoft.Extensions.Http をインストールする。
v5.0.0 だとMicrosoft .Extentions.DependencyInjection のライブラリがバージョン不一致を起こすので注意。

サービスに HttpClient を登録する。(この1行なくてもインジェクションされるけどどうなんだろうか)

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

Functions 側はコンストラクタで受け取る。

    private readonly HttpClient _httpClient;

    public Function1(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }

ロガーを利用する

host.jsonlogLevel を追加する。 FunctionApp1の部分は出力対象とする名前空間やクラス名を指定する。

{
  "version": "2.0",
  "logging": {
    "applicationInsights": {
      "samplingExcludedTypes": "Request",
      "samplingSettings": {
        "isEnabled": true
      }
    },
    "logLevel": {
      "FunctionApp1": "Information"
    }
  }
}

Functions で利用する場合は、コンストラクタで受け取るだけ。 デフォルトで付いてくるメソッド引数の log は削除して問題ない。

    private readonly ILogger<Function1> _logger;

    public Function1(ILogger<Function1> logger)
    {
        _logger = logger;
    }

    [FunctionName("Function1")]
    public async Task<IActionResult> Run(
        [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req)
    {
        _logger.LogInformation("ILogger<Functions1> _logger");

        return new OkObjectResult("This HTTP triggered function executed successfully.");
    }

Functions 以外のクラスで利用する場合は、対象のクラスに ILogger をインジェクションしてもらうために、Startup クラスの Configure メソッドでサービスに登録する。 こうすることでロガーをクラス間でたらい回しにしなくて済む。

public class LogWriter
{
    private readonly ILogger<LogWriter> _logger;
    public LogWriter(ILogger<LogWriter> logger)
    {
        _logger = logger;
    }

    public void Write()
    {
        _logger.LogInformation("ILogger<LogWriter> _logger");
    }
}
class Startup : FunctionsStartup
{
    public override void Configure(IFunctionsHostBuilder builder)
    {
        builder.Services.AddTransient<LogWriter>();
    }
}

Functions 側では目的のクラスをインジェクションしてもらいそれを利用する。

    private readonly ILogger<Function2> _logger;
    private readonly LogWriter _logWriter;

    public Function2(
        ILogger<Function2> logger,
        LogWriter logWriter)
    {
        _logger = logger;
        _logWriter = logWriter;
    }

    [FunctionName("Function2")]
    public async Task<IActionResult> Run(
        [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req)
    {
        _logger.LogInformation("ILogger<Functions2> _logger");
        _logWriter.Write();

        return new OkObjectResult("This HTTP triggered function executed successfully.");
    }

f:id:yotiky:20210129234436p:plain

参考:Azure Functions におけるロガーの扱いとフィルタの注意点 - しばやん雑記

appsettings.json を読み込む

ASP.NET Core でよく使われる appsettings.json を読み込む。local.settings.json では配列や特殊なオブジェクトなどを定義できない。

プロジェクトに appsettings.json を追加して、出力ディレクトリに「常にコピーする」ように設定する。実行環境毎の設定は appsettings.Development.json などを追加する。

f:id:yotiky:20210130011947p:plain:w300

{
  "SampleAppSettings": {
    "Name": "SampleAppSettings",
    "Items": [
      {
        "Key": "Key1",
        "Message": "Message1"
      },
      {
        "Key": "Key2",
        "Message": "Message2"
      }
    ]
  }
}

設定を受け取るクラスを定義する。

public class SampleAppSettings
{
    public string Name { get; set; }
    public Item[] Items { get; set; }
}

public class Item
{
    public string Key { get; set; }
    public string Message { get; set; }
}

Startup クラスで appsettings.json を読み込んで、設定を受け取るクラスを登録する。

public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
{
    base.ConfigureAppConfiguration(builder);

    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)
{
    builder.Services.Configure<SampleAppSettings>(context.Configuration.GetSection("SampleAppSettings"));
}

参考:構成ソースのカスタマイズ - .NET Azure Functions で依存関係の挿入を使用する

Functions 側は IOption<SampleAppSettings> で受け取る。

public Function1(IOptions<SampleAppSettings> sampleAppSettings)
{
}

参考:Azure Functions V2 の Startup.cs で appsettings.json を読み込む(2019年5月バージョン) - BEACHSIDE BLOG


設定にオブジェクト単位ではなく、個別のパラメータを定義してバインドすることもできる。 local.settings.jsonMyOptions:Value1MyOptions:Value2 を追加する。

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet",
    "MyOptionsSettings:Value1": "local.settings.json-Value1",
    "MyOptionsSettings:Value2": "local.settings.json-Value2"
  }
}

設定を受け取るクラスを定義する。

public class MyOptions
{
    public string Value1 { get; set; }
    public string Value2 { get; set; }
}

Startup クラスで設定を読み込んで、MyOptions クラスを MyOptionSettings セクションにバインドする。

public override void Configure(IFunctionsHostBuilder builder)
{
    builder.Services.AddOptions<MyOptions>()
        .Configure<IConfiguration>((target, configuration) =>
        {
            configuration.GetSection("MyOptionsSettings").Bind(target);
            // もしくは
            //configuration.Bind("MyOptionsSettings", target);
        });
}

Functions 側は IOptions<MyOptions> で受け取る。

public Function1(IOptions<MyOptions> options)
{
}

f:id:yotiky:20210130204011p:plain

参考:Azure Functions で設定情報を使いたい - Qiita

オプション

環境変数を含むアプリ設定に定義されている値は IConfiguration で読み取ることできる。 さらに、ASP.NET Core ではオプションパターンを使って IConfiguration から任意のクラスに値を抽出することができる。 このパターンで関連する設定をグループ化する。

docs.microsoft.com

参考:

Key Valut を読み込む

Azure Key Vault のアクセスポリシーは「取得」と「一覧」を設定する。

f:id:yotiky:20210131004000p:plain:w200

Key Vault のエンドポイントをアプリケーション設定などに保存する。local.settings.json の例。

f:id:yotiky:20210131004546p:plain

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet",
    "KeyVaultEndpoint": "https://<KeyVaultName>.vault.azure.net/"
  }
}

Nuget で以下のパッケージをインストールする。

  • Azure.Extensions.AspNetCore.Configuration.Secrets

Startup で、Key Vault のエンドポイントを使って Configuration に追加する。

class Startup : FunctionsStartup
{
    public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
    {
            var builtConfig = builder.ConfigurationBuilder.Build();

            builder.ConfigurationBuilder.AddAzureKeyVault(new Uri(builtConfig["KeyVaultEndpoint"]), new DefaultAzureCredential());
    }
}

※Options を使う場合は、「appsettings.json を読み込む」の項目を参照。

Functions 側は インジェクションした IConfiguration からシークレットの名前で取得できる。

    public class Function1
    {
        private readonly IConfiguration _configuration;
        public Function1(IConfiguration configuration)
        {
            _configuration = configuration;
        }

        [FunctionName("Function1")]
        public async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogInformation(_configuration["keys-blobconnectionstring"]);

            return new OkObjectResult("This HTTP triggered function executed successfully.");
        }
    }

以下は、既に非推奨となっているライブラリであるが、実装例として残しておく。

Nuget で以下のパッケージをインストールする。

Startup で、Key Vault を参照して Configuration に追加する。

class Startup : FunctionsStartup
{
    public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
    {
        var builtConfig = builder.ConfigurationBuilder.Build();
        var tokenProvider = new AzureServiceTokenProvider();
        var keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(tokenProvider.KeyVaultTokenCallback));
    
        builder.ConfigurationBuilder.AddAzureKeyVault(builtConfig["KeyVaultEndpoint"], keyVaultClient, new DefaultKeyVaultSecretManager());
    }
}

参考:

Blob Storage の Client を利用する

Nuget で以下のパッケージをインストールする。

  • Microsoft.Extensions.Azure
  • Azure.Storage.Blobs

Startup で、Blob Service Client を追加する。接続先が複数ある場合は名前を付けておく。

class Startup : FunctionsStartup
{
    public override void Configure(IFunctionsHostBuilder builder)
    {
        var context = builder.GetContext();
        builder.Services.AddAzureClients(x =>
        {
            var connectionString = context.Configuration["AzureWebJobsStorage"];
            x.AddBlobServiceClient(connectionString);
            //x.AddBlobServiceClient(connectionString).WithName("BlobClientA");
        });
    }
}

Functions 側では、BlobServiceClient を受け取る。

public Function2(BlobServiceClient blobClient)
{
}

名前付きのクライアントを取得するには、IAzureClientFactory<BlobServiceClient> をインジェクションしてもらう。

public Function2(IAzureClientFactory<BlobServiceClient> clientFactory)
{
    var namedClient = clientFactory.CreateClient("BlobClientA");
}

参考:【.NET】BlobServiceClientFactoryはあったんだ! – 10bace LOG

Table Storage の Client を利用する

Nuget で以下のパッケージをインストールする。

Startup で、CloudTableClient を追加する。

class Startup : FunctionsStartup
{
    public override void Configure(IFunctionsHostBuilder builder)
    {
        var context = builder.GetContext();
        builder.Services.AddSingleton(_ =>
        {
            var connectionsString = context.Configuration["AzureWebJobsStorage"];
            var storageAccount = CloudStorageAccount.Parse(connectionsString);
            return storageAccount.CreateCloudTableClient();
        });
    }
}

Functions 側では、CloudTableClient を受け取る。

public Function2(CloudTableClient tableClient)
{
}

昔の書き込みはスレッドセーフじゃないってあるが、最近はライフサイクルは Singleton で良さそう。

Queue Storage の Client を利用する

QueueClientインスタンスqueuName に結びつくため、キュー毎にラップしたクラスなどを用意して別々に生成する必要がある。

yotiky.hatenablog.com

App Configuration を読み込む

App Configuration のエンドポイントをアプリケーション設定などに保存する。

Nuget で以下のパッケージをインストールする。

  • Azure.Extensions.AspNetCore.Configuration.Secrets

Startup で、App Configuration のエンドポイントを使って Configuration に追加する。

class Startup : FunctionsStartup
{
    public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
    {
            var builtConfig = builder.ConfigurationBuilder.Build();

            builder.ConfigurationBuilder.AddAzureAppConfiguration(options =>
                options.Connect(new Uri(builtConfig["AppConfigEndpoint"]), new ManagedIdentityCredential()));
    }
}

設定や接続文字列を使うなど詳細は以下を参照。

yotiky.hatenablog.com

関連記事

Azure Functions で Azure Key Valut から設定を読み込む

Azure Key Valut は、トークン、パスワード、証明書、API キー、接続文字列、その他のシークレットを安全に格納し、それらへのアクセスを厳密に制御できるサービス。(参考

目次

Azure Functions に Managed Id を設定

デプロイ済みの Azure Functions の設定から ID を選択する。

f:id:yotiky:20210130214151p:plain:w300

システム割り当て済みをオンにする。

f:id:yotiky:20210130214226p:plain:w300

Azure Key Vault を設定

Azure Key Valut を作成していなければ作成する。

f:id:yotiky:20210130214812p:plain:w400

作成した Key Valut で設定からシークレットを選択し、キーと値を登録する。

f:id:yotiky:20210130215715p:plain:w300

f:id:yotiky:20210130215846p:plain

続いて、設定からアクセスポリシーを選択し、アクセスポリシーを追加する。

f:id:yotiky:20210130215427p:plain:w300

シークレットのアクセス許可を「取得」、プリンシパルの選択で Azure Functions のオブジェクトIDを入力して、リソースを選択する。追加し終わったら一覧で保存する。

f:id:yotiky:20210130220354p:plain

アプリケーション設定に Key Vault の識別子を設定

Key Valut で作成したキーを開いて、シークレット識別子をコピーする。

f:id:yotiky:20210130220909p:plain

Azure Functions のアプリケーション設定で、シークレット識別子を以下の書式で値として設定する。

@Microsoft.KeyVault(SecretUri=<シークレット識別子>)

正常に接続できるとキーコンテナーの参照にチェックが付く。 f:id:yotiky:20210130221845p:plain

コードからアプリケーション設定を取得すると Key Vault の値が展開される。

var connectionString = Configuration["BLOB_CONNECTION_STRING_KEYVAULT"]

参考

blog.beachside.dev

関連記事

Azure Functions で Azure Storage への接続情報

目次

検証環境

  • Azure Functions v3
  • Azure Blob Storage
  • Azure.Storage.Blobs v12.8.0 (ライブラリ)

直書き

サンプルコード向けなら直書き。

var blobServiceClient = new BlobServiceClient("connectionString");
var blobContainerClient = blobServiceClient.GetBlobContainerClient("blobContainerName");
var blobClient = blobContainerClient.GetBlobClient("blobName");

設定情報から取得

設定

ポータルで Azure Functions の構成からアプリケーション設定と接続文字列を設定できる。

アプリケーション設定には環境変数を設定する。
接続文字列にはDBの接続文字列を設定する。一応 Custom を選択するとストレージの接続文字列も使えなくはない。

f:id:yotiky:20210128202527p:plain:w300

tech-blog.cloud-config.jp

Azure Functions をローカル実行する時は、local.settings.json が設定として使われる。

AzureWebJobsStorage は、Azure Functions 作成時にリンクしたストレージの接続文字列が設定される。local.settings.jsonUseDevelopmentStorage=true が設定されている場合は、ストレージエミュレーターに接続される。

今回は、ValuesAPPLICTION_SETTINGS_VALUEConnectionStringsDB_CONNECTION_STRING を追加した。

ポータル上だと次の通り。

f:id:yotiky:20210128212501p:plain

local.settings.json では次のようになる。

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet",
    "APPLICTION_SETTINGS_VALUE": "ApplicationSettingsValue"
  },
  "ConnectionStrings": {
    "DB_CONNECTION_STRING": "DBConnectionString"
  }
}

f:id:yotiky:20210128210604p:plain

実装

.NET Framework 版である v1 では、ConfigurationManager を使用していた。
.NET Core 版である v2 以降では、ConfigurationMBuilder を使用する。

ConfigurationMBuilderlocal.settings.json を追加してから Build() する。 ローカル実行の設定が不要な場合は、Configuration = new ConfigurationBuilder().Build(); でも動く。

Values は、Configuration[<key>] で取得する。
ConnectionStrings は、Configuration.GetConnectionString(<key>) で取得する。

using Microsoft.Extensions.Configuration;

public static class Function1
{
    private static IConfigurationRoot Configuration { get; }
    static Function1()
    {
        var builder = new ConfigurationBuilder()
            .AddJsonFile("local.settings.json", true)
            .AddEnvironmentVariables();
    
        Configuration = builder.Build();
    }

    [FunctionName("Function1")]
    public static async Task<IActionResult> Run(
        [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
        ILogger log)
    {
        var appSettingsValue = Configuration["APPLICTION_SETTIGS_VALUE"];
        var connectionString = Configuration.GetConnectionString("DB_CONNECTION_STRING");

f:id:yotiky:20210128213716p:plain

実際は接続に必要な情報を設定した上で利用する。

var blobServiceClient = new BlobServiceClient(Configuration["connectionString"]);
var blobContainerClient = blobServiceClient.GetBlobContainerClient(Configuration["blobContainerName"]);
var blobClient = blobContainerClient.GetBlobClient(Configuration["blobName"]);

参考

blog.shibayan.jp

関連記事

GPL v2 / LGPL v2.1 のデュアルライセンスについて

これは、GPLv2 もしくは LGPLv2.1 のデュアルライセンス についての覚書です。 ライセンスについては素人なので間違っている可能性があります。

一般財団法人ソフトウェア情報センターの「IoT 時代における OSS の利用と法的諸問題 Q&A 集」において、「D-3-8 LGPLリバースエンジニアリングの許可」の項目が非常に分かりやすかった。