SHOEISHA iD

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

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

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

.NET MAUI BlazorでAI画像生成アプリ構築。OpenAIのAPIで本番実装に移行しよう

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


APIキーの安全な管理

 APIキーなどの機密情報は、コード内に直接記述するのではなく、環境変数やシークレット管理機能 (たとえば、Azure Key Vaultなど)を使用するべきです。これは、コードがGitHubなどで公開された場合に漏洩してしまうことを防ぐためです。

ユーザーシークレット機能

 アプリの開発中では、.NET Coreのユーザーシークレット機能を使用して、APIキーを安全に管理できます。この機能は、APIキーなどの機密情報をソースコードや構成ファイルとしてではなく、ローカルの別の場所に保存して、参照する機能です。Gitなどのバージョン管理システムに、誤ってAPIキーをコミットしてしまうリスクを減らせます。

 まず、ImageGenerator.Sharedプロジェクトでユーザーシークレットを有効にします。ソリューションエクスプローラーでプロジェクトを右クリックし、[ユーザーシークレットの管理]を選択します。すると、必要なパッケージの追加を求めるダイアログが表示されて、「はい」を選択すると、secrets.jsonという空のJSONファイルが開かれます。

パッケージの追加
パッケージの追加

 このJSONファイルに、次のようにAPIキーを設定します。

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

 sk-proj-....の部分には、実際に取得したAPIキーを入力します。このファイルは、デフォルトでは、%APPDATA%\Microsoft\UserSecrets\<user_secrets_id>\secrets.jsonに保存されます。<user_secrets_id> は、プロジェクトによって異なる一意の識別子です。

 secrets.jsonは、プロジェクトのソースコードから分離されており、Gitなどのバージョン管理システムで誤ってコミットされるのを防ぎます。

設定クラスの作成

 次に、この設定を読み込むためのクラスとして、ImageGenerator.SharedプロジェクトのServicesフォルダに、OpenAISettingsクラスを作成します。

[リスト2]OpenAISettings.csの一部
public class OpenAISettings
{
    public string? ApiKey { get; set; }  // (1)
}

 このクラスは、単にAPIキーのプロパティを提供するだけです(1)。DIコンテナを通じて設定値を受け取るためのモデルとして機能します。

コンテナの登録

 DIコンテナにAPIキーを登録するコードを追加します。MAUIプロジェクトのMauiProgram.csファイルとWebプロジェクトのProgram.csファイルに、次のコードを追加します。

[リスト3]MauiProgram.csの一部
builder.Services.AddSingleton<IImageGenerationService, MockImageService>();

// ユーザーシークレットから設定を読み込み、DIコンテナに登録
builder.Configuration.AddUserSecrets<OpenAISettings>();
var openAISettings = new OpenAISettings();
builder.Configuration.GetSection("OpenAI").Bind(openAISettings);
builder.Services.AddSingleton(openAISettings);

 AddUserSecrets<OpenAISettings>()でユーザーシークレットを読み込み、OpenAISettingsのインスタンスを作成し、secrets.jsonの「OpenAI」セクションの値をバインド(設定をクラスのプロパティに割り当て)しています。最後に、AddSingletonメソッドを使ってDIコンテナに登録しています。

 この設定により、アプリケーション内のどこからでも、DIを通じてAPIキーへのアクセスが可能になります。

画像生成サービスの実装

 それでは、実際にImage Generation APIを呼び出す画像生成サービスを実装していきましょう。前回作成したモックサービスの代わりに、APIを呼び出すサービスを作成します。

依存性注入(DI)による実装切り替え
依存性注入(DI)による実装切り替え

OpenAIImageServiceの作成

 ImageGenerator.SharedプロジェクトのServicesフォルダに、新しいサービスクラス(OpenAIImageService)を作成します。

[リスト4]OpenAIImageService.csの一部
public class OpenAIImageService(OpenAISettings settings)  : IImageGenerationService
{
    // OpenAIクライアントを初期化 (1)
    private readonly ImageClient _client = new("dall-e-3", settings.ApiKey);

    public async Task<string> GenerateImageAsync(string prompt)
    {
        try
        {
            // 画像生成パラメータの設定 (2)
            ImageGenerationOptions options = new()
            {
                Quality = GeneratedImageQuality.Standard,      // 品質
                Size = GeneratedImageSize.W1024xH1024,         // サイズ
                ResponseFormat = GeneratedImageFormat.Uri,     // URLを返す
                Style = GeneratedImageStyle.Vivid              // 画像スタイル
            };

            // APIを呼び出し (3)
            var result = await _client.GenerateImageAsync(prompt, options);

            return result.Value.ImageUri.ToString();
        }
        catch (Exception ex)
        {
            // エラーログを記録して再スロー
            Console.WriteLine($"画像生成エラー: {ex.Message}");
            throw;
        }
    }
}

 ここでは、プライマリコンストラクタ構文でOpenAIImageServiceクラスを定義しています。DIコンテナから、OpenAISettingsインスタンスが自動的に渡されます。初期化部分では、dall-e-3モデルとDIコンテナから受け取ったAPIキーを指定して、ImageClientオブジェクトを生成しています(1)。このクライアントを通じてOpenAI APIと通信します。

 GenerateImageAsyncメソッド内では、画像生成のためのパラメータを設定しています(2)。主なパラメータは次のとおりです。

画像生成パラメータ
プロパティ 概要
Size 画像のサイズ(1024x1024ピクセルなど)
Quality 画像の品質(標準または高品質)
ResponseFormat 応答形式(URLまたは画像データ)
Style 画像スタイル(VividまたはNatural)

 設定したパラメータを使ってAPIのGenerateImageAsyncメソッドを実行し、生成された画像のURLを受け取ります(3)。非同期処理(async/await)を使用することで、画像生成中もアプリのUIがフリーズしないようになっています。エラーが発生した場合には、ログに記録した上で、例外を再スローして呼び出し元に通知します。

サービスの登録

 作成したOpenAIImageServiceをDIコンテナに登録します。MAUIプロジェクトのMauiProgram.csとWebプロジェクトのProgram.csの両方で、サービス登録部分を次のように変更します。これにより、前回のモックサービスの代わりに、実際にOpenAI APIを呼び出すサービスが使用されるようになります。

[リスト5]サービス登録の変更
// 変更前
builder.Services.AddSingleton<IImageGenerationService, MockImageService>();
↓
// 変更後
builder.Services.AddSingleton<IImageGenerationService, OpenAIImageService>();

次のページ
エラーハンドリングの改善

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

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

もっと読む

この記事の著者

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

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 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本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

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

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

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/22376 2025/10/21 11:29

おすすめ

アクセスランキング

アクセスランキング

イベント

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

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

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

メールバックナンバー

アクセスランキング

アクセスランキング