SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

マルチターゲットアプリ開発の新しいアプローチ~.NET 9 新テンプレートの基本~

.NET MAUI Blazorで構築したアプリを、モバイル環境に適用しよう

マルチターゲットアプリ開発の新しいアプローチ~.NET 9 新テンプレートの基本~ 第4回

APIキー取得処理の変更(1)

 前回は、起動時にユーザーシークレットからAPIキーを読み込む形にしていましたが、今回はこの処理を変更して、プラットフォームごとにAPIキーの取得元を切り替える実装パターンにしてみます。

 Web環境ではユーザーシークレットを読み込み、モバイルやWindowsアプリ環境では、SecureStorage(APIキーはソースコード埋め込み)を利用する形とします。

作成するサービスと実装クラスの構成

 今回作成するインターフェイスと実装クラスは、次のとおりです。

  • IApiKeyStorageインターフェイス:キーの取得場所を抽象化する。取得メソッドのみを定義
  • ApiKeyServiceクラス:IApiKeyStorageインターフェイスを使ってキーを取得する
  • ApiKeyStorage実装クラス
    • Web: IConfigurationを利用してユーザーシークレットからキーを取得
    • Android/Windowsアプリ:SecureStorageからキーを取得。キーがなければソースコード内の定数を(保存後)参照

 ApiKeyServiceクラスは、IApiKeyStorageの実装クラスを利用、つまり依存する構成になっています。IApiKeyStorageインターフェイスは、APIキーを取得する処理を抽象化して、実装オブジェクトでプラットフォームごとの分岐を吸収するようにします。実装オブジェクトは、それぞれのプロジェクトで注入される形とします。

プラットフォームに応じた実装切り替え
プラットフォームに応じた実装切り替え

インターフェイスの定義

 まずは、ImageGenerator.SharedプロジェクトのServicesフォルダに、IApiKeyStorageインターフェイスを新規作成します。ここは、単にキーを取得する非同期メソッドの宣言だけです。

[リスト1]IApiKeyStorage.cs
public interface IApiKeyStorage
{
    Task<string> GetKeyAsync();    // 非同期で取得
}

共有する実装クラスの作成

 次に、各プロジェクトで共有する実装クラスとなるApiKeyServiceクラスを、ImageGenerator.SharedプロジェクトのServicesフォルダに新規作成します。

[リスト2]IApiKeyStorage.cs
public class ApiKeyService(IApiKeyStorage storage)
{
    public async Task<string> GetApiKeyAsync()
    {
        // 具体的な保存場所は IApiKeyStorageオブジェクトに任せる
        var key = await storage.GetKeyAsync();
        if (string.IsNullOrEmpty(key))
        {
            throw new Exception("not key");
        }
        return key;
    }
}

 ApiKeyServiceクラスは、IApiKeyStorageインターフェイスを実装したクラスのメソッドを呼び出すだけです。このようにすると、同じメソッドの呼び出しで、各プロジェクトに応じた処理を切り替えることができます。

Web環境の実装クラスの作成

 IApiKeyStorageインターフェイスを実装したWebKeyStorageクラスを、ImageGenerator.WebプロジェクトのServicesフォルダに新規作成します。

[リスト3]WebKeyStorage.cs
public class WebKeyStorage(IConfiguration configuration) : IApiKeyStorage
{
    public Task<string> GetKeyAsync()
    {
        // WebではUserSecrets から取得
        var key = configuration["OpenAI:ApiKey"]; 
        return Task.FromResult(key ?? string.Empty);
    }
}

 これは、ユーザーシークレットから取得する処理です。前回では、ユーザーシークレットのJSON文字列をオブジェクトにマッピングしましたが、今回は、MAUIで用意されているIConfigurationオブジェクトのメソッドを使って、直接、読み出しています。IConfigurationオブジェクトは、フレームワークで注入されるため、明示的に作成する必要はありません。

 なお、ImageGenerator.Webプロジェクト用に、ユーザーシークレットを作成する必要があります。ソリューションエクスプローラーでImageGenerator.Webプロジェクトを右クリックし、[ユーザーシークレットの管理]を選択し、前回同様のAPIキーを設定しておきます。

[リスト4]secrets.json
{
  "OpenAI": {
    "ApiKey": "sk-proj-...."
  }
}

モバイル/Windowsアプリ環境の実装クラスの作成

 同様に、IApiKeyStorageインターフェイスを実装したMauiKeyStorageクラスを、ImageGeneratorプロジェクトのServicesフォルダに新規作成します。

[リスト5]MauiKeyStorage.cs
public class MauiKeyStorage() : IApiKeyStorage
{
    private const string ApiKey = "sk-proj-...";
    private const string KeyName = "openai_api_key";

    public async Task<string> GetKeyAsync()
    {
        // MAUI固有のSecureStorageを使用
        var key = await SecureStorage.GetAsync(KeyName);
        if (!string.IsNullOrEmpty(key))
        {
            return key;
        }
        await SecureStorage.SetAsync(KeyName, ApiKey);
        return ApiKey;
    }
}

 ここでは、APIキーをソースに埋め込んでいます。これは、あくまで開発用であり、Gitなどのバージョン管理システムにコミットする際は、キー文字列を削除してください。

 また、実際の本番環境では、外部にキーが漏れないように、ソース埋め込みではない方法を採用すべきです。本番環境に対応した処理は、次回以降で説明する予定です。

SecureStorageとは

 今回利用しているSecureStorageとは、プラットフォーム固有のセキュアな(暗号化された)ストレージ機構をラップしたMAUIのライブラリです。.NET MAUI アプリからは、統一された ISecureStorageインターフェースとして見えますが、内部では各OSのネイティブAPI(Keychain、Keystoreなど)を呼び出しています。開発者が暗号化アルゴリズムや鍵管理を実装しなくても、OSが提供するセキュリティ機能を利用できます。

 今回作成したMauiKeyStorageのGetKeyAsyncメソッドでは、SecureStorageで保存されたAPIキーを参照(SecureStorage.GetAsyncメソッド)しています。保存されていない場合は、ソースコード内の定数を保存(SecureStorage.SetAsyncメソッド)して、その値を返します。

 SecureStorageのデータ構造は、文字列のみで、いわゆるKey-Value形式です。バイナリなどを保存したい場合は、Base64 エンコードなどで文字列に変換する必要があります。

次のページ
APIキー取得処理の変更(2)

この記事は参考になりましたか?

マルチターゲットアプリ開発の新しいアプローチ~.NET 9 新テンプレートの基本~連載記事一覧

もっと読む

この記事の著者

WINGSプロジェクト 高江 賢(タカエ ケン)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。 2026年時点での登録メンバは約50名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS X: @WingsPro_info(公式)、@WingsPro_info/wings(メンバーリスト) Facebook

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるLaravel実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/22811 2025/12/22 11:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー