RawGuy
@RawGuy

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

VBのWindowsフォームアプリでApp.configを環境ごとに分けてビルド

解決したいこと

Debug、Release、その他複数定義をして、ビルドごとにApp.configを変更したいと考えています。
※可能であれば設定値を暗号化して見えないようにしたい。
よくある要件であり、対処方法が確立されていると予想していますが、やり方がわかりません。

以下のやり方にこだわりがあるわけではありません。
やりたいことは

  • Debug、Release、その他複数定義をして、ビルドごとにApp.configを変更したい
  • できる限り定番のやり方で解決したい
  • ビルド定義を追加するたびにソースを変更するなどのことはしたくない
  • 可能であれば
    • ユーザに設定値を見られたくないので暗号化
    • もしくは、埋め込みリソースとしてexeに組み込みたい

発生している問題・エラー

試行錯誤を繰り返し、ビルドの過程でApp.Debug.configApp.configにコピーしてビルドをして成功はしたと思いました。
しかし手順を整理して再現させようとしたところ、環境によりエラーになる場合とならない場合があり、状況が整理できていません。

該当するソースコード

下記のvbprojの場合、想定通りコピーまではされるが初回のビルドでは、実行時に$(Target).ext.conifgが読み込めずエラーになります。
2回目実行時は、App.conifgから$(Target).ext.configが再作成され、exeにリンクされているせいか、期待通りの動きをします。

一度成功したと思われる、MyPoroject.vbprojファイル

  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <PreBuildEvent>
      copy /Y "$(ProjectDir)App.Debug.config" "$(ProjectDir)App.config"
    </PreBuildEvent>
  </PropertyGroup>

自分で試したこと

  • ビルド後にApp.Debug.config$(TargetName).exe.configとして、出力先にコピーする
    • $(ProjectDir)が取得できたり、できなかったりするためコピー先を
      • $(SolutionDir)MyProjectFolder\bin\Debug\net8.0-windows\$(TargetName).exe.configにする
      • $(OutDir)\$(TargetName).exe.configにする
      • $(TargetDir)$(TargetName).exe.configにする
  • ビルド前にApp.Debug.configApp.configとして、ソースのあるフォルダにコピーする
    • $(SolutionDir)MyProjectFolder\App.configにする
0

2Answer

ターゲットフレームワークは何か書いてください。


【追記】

接続文字列その他の構成情報がデバッグ版とリリース版で異なるので、デバッグ版とリリース版での構成情報を別々の構成ファイルに格納し、リリース版では構成情報をリリース用の情報に上書きして使用するという話だと理解して回答します。

また、ターゲットフレームワークが不明ですが、タグの .NETCore から .NET 6 以降であろうと想像してます。

ASP.NET Core アプリでは、appsettings.json に加えて appsettings.Production.json を追加しておけば、プロジェクトに組み込みの機能が運用環境での環境変数を読み取って、それが Production であれば自動的に appsettings.Production.json から構成情報を取得して上書き・追加を行うようになっています。

Windows Forms アプリには ASP.NET Core のような組み込みの機能はありませんが、アプリのプログラムで動的に appsettings.json の情報を appsettings.Production.json の情報で上書きすることができます。

そういう方法ではいかがですか? それでよければ、詳しい方法については以下の記事を読んでください。

WinForms アプリで構成情報の上書き (CORE)
http://surferonwww.info/BlogEngine/post/2023/08/19/overwrite-configuration-information-in-windows-forms-application.aspx

上の記事のコードでは、ASP.NET Core アプリの「運用環境での環境変数を読み取って・・・」というところまでは実装してありません。そこは質問者さんの要件に合わせて追加で実装してください。

1Like

Comments

  1. @RawGuy

    Questioner

    ありがとうございます。
    フレームワークは「.NET8」です。
    (10月からWindows Formアプリ開発に手を出し始めたくらいの初学者のため、言葉の使い方が間違えているかもしれません。)

    すみません。大事なことを書いていませんでした。

    このWindows Fromアプリを顧客ごとに設定を変えてリリースしたいと考えています。
    顧客は定期的に増えてくるため、

    • 設定ファイルとビルド定義を増やすだけで個社対応をしたい。
      というのが、要求に入ります。

    教えていただいた内容の場合、顧客が増えるたびにコード修正が入れなくてはならないと理解しました。
    ただ、.NET8の場合、App.configではなく、appsettings.jsonを使うほうが標準。というようですので、こちらの観点で調べていこうと思います。

    また、追加の質問ですが、Windows FormアプリではDBの接続場やAPIのトークンなどの機密情報はどこに保持するのが一般的なのでしょうか?
    珍しい要件ではないと思っていますが、調べても回答に辿り着けないため、私のアプローチがズレているような気がしています。

  2. このWindows Fromアプリを顧客ごとに設定を変えてリリースしたいと考えています。
    設定ファイルとビルド定義を増やすだけで個社対応をしたい。

    「設定ファイルとビルド定義」って何ですか?

    何にせよ、「顧客ごとに設定」する情報を構成ファイルに格納するのであれば、顧客ごとに構成ファイルを書き換えるのは当たり前の話で、絶対に「増やすだけ」という話にはならないはずです。

    違いますか?

    また、追加の質問ですが、Windows FormアプリではDBの接続場やAPIのトークンなどの機密情報はどこに保持するのが一般的なのでしょうか?

    app.config とか appsettings.json を構成ファイルに使うのであれば、暗号化した情報を構成ファイルに保持してアプリで復号するということぐらいでしょうか。

    その前に、WinForm アプリから直接 DB にアクセスすること自体が悪手だと思いますので、WinForms ⇔ Web API ⇔ DB という構成を考えることをお勧めします。そうすれば少なくとも WinForms のユーザーからは接続文字列は見えません。

  3. 本題とは関係ない話ですが・・・

    フレームワークは「.NET8」です。

    Windows OS 上で動かす Windows Forms アプリとか WPF アプリは、無理(?)してターゲットフレームワーク .NET で作らない方がよいと思います。

    特定の OS に依存する機能は Visual Studio のテンプレートで作るプロジェクトには含まれてないとか(例: GDI+ に依存するグラフィックス機能、Shift_JIS エンコーディングなど)、ReportViewer や Chart が使えないとか、データソース構成ウィザードが使えないとか乗り越えなければならない壁に比較してメリットが少なそうな気がします。また、Web アプリですと、ASP.NET Web Forms アプリは対応できないという乗り越えられない壁があります。

    ライフサイクル(サポート期間)を考えているなら、.NET 8 より .NET Framework 4.8 の方が長いはずです。

  4. @RawGuy

    Questioner

    ありがとうございます。

    「設定ファイルとビルド定義」って何ですか?

    設定ファイルはApp.configであれば、App.xxxx.configで
    ビルド定義は「Debug」「Release」「xxxx社」のようなイメージです。
    これらはビルド定義とは言わないですかね?

    「増やすだけ」という話にはならないはずです。

    個社ごとのカスタマイズは行わないので、増やすときのコストを可能な限り減らすことを想定しています。

    保持してアプリで復号する

    となると鍵などの管理も面倒になりそうですね。

    WinForms ⇔ Web API ⇔ DB

    おっしゃることはわかりますが、今回の件に限らず小規模アプリだとなかなか厳しいところがあります。

    Windows OS 上で動かす Windows Forms アプリとか WPF アプリは、無理(?)してターゲットフレームワーク .NET で作らない方がよいと思います。

    今後の参考にさせていただきます。

    ライフサイクル(サポート期間)を考えているなら、.NET 8 より .NET Framework 4.8 の方が長いはずです。

    知りませんでした。むしろ逆のイメージを持っていました。

  5. @RawGuy

    Questioner

    失礼しました。

  6. これらはビルド定義とは言わないですかね?

    質問者さんの言う「設定ファイルとビルド定義を増やす」というのは「構成ファイルの追加・差替えとプロジェクトファイルの書換」という意味だと想像しています。そうだとすると、少なくとも自分の知識の範囲では、言わないです。

    なので、少なくとも私にとっては正しい用語ではなくて話が通じてないです。多分、他の人もそうだと思います。

    個社ごとのカスタマイズは行わないので、増やすときのコストを可能な限り減らすことを想定しています。

    前にも書きましたが、「顧客ごとに設定」する情報を構成ファイルに格納するのであれば、顧客ごとに構成ファイルを書き換えて差し替えるのは当たり前の話で、絶対に「増やすだけ」という話にはならないはずです。App.xxxx社.config という構成ファイルは顧客ごとに作るのではないのですか?

    手間がかかろうが何であろうが払うべきコストは払うべきです。今回の質門者さんの案のように、コスト削減(ホントになっている?)のため、普通やらないことを無理してやるのは、かえってコストを増やすことにつながります。保守を考えた場合は特に。もし自分が質問の実装のようなアプリの保守を引き継いだら、こういう普通ではない独自実装した人を恨みますよ。

    普通のやり方、Microsoft が推奨・サポートしているやり方をお勧めします。

    最初の回答で紹介した記事に Microsoft のドキュメント「.NET Framework から .NET にアップグレードした後に最新化する」へのリンクが張ってありますが、その記事に書いてあるように、構成ファイルには appsettings.json を使うことが推奨されてます。

    そして、「WinForms アプリで構成情報の上書き (CORE)」で紹介したように、複数の appsettings.json を作って実行時に上書きする機能が提供されています。その記事は appsettings.json, appsettings.Production.json の 2 つだけの例ですが、さらに、例えば appsettings.User.json という名前の構成ファイルを追加することもできます。

    普通のやり方、Microsoft が推奨・サポートしているやり方はすでに教えたので、後は質問者さんの方で考えてください。

  7. @RawGuy

    Questioner

    ありがとうございます。
    「普通」がわかってないので助かります。

定番のやり方というのは無いと思いますが、コマンドラインビルドみたいな事は出来るので、環境毎の切り替えが必要なファイルをコピーしてからビルドするようなバッチファイルでも作成したらどうでしょう?バッチファイルの引数で環境を切り替えるか、環境毎にバッチファイルを作るかはお好きにどうぞ。

暗号化云々に関しては、ローカルに置いてる時点であまりセキュリティ的に意味は無いと思います。どちらにせよ復号化しないと使えないし、復号化のためのキーをどこかに持たないといけないという堂々巡りになります。更に言えば、.NETプログラムは簡単に逆コンパイル可能なので、どうやって復号しているかまで分かります。難読化ツールのようなものはあるでしょうが、結局のところあなたがどこまでカジュアルに読めなくなればいいと考えてるか次第で方法は変わると思います。平文でさえなければいいなら、Base64にでもエンコードすればいいと思います。
DBアクセス方法を完全に隠蔽したいなら、WebAPI化のように構成で防ぐのがいいと思います。

0Like

Comments

  1. .NET Framework 版の ASP.NET Web アプリの場合は定番のやり方があります。

    WinForms や WPF での「定番のやり方」とまでは言えないかもしれませんが、同等なことは可能です。ネットを調べてみるとよく行われている方法のようです。

    詳しくは以下の記事に書きましたので、興味があれば読んでください。

    App.Debug.config と App.Relese.config を使った構成ファイル作成

    なお、接続文字列など構成情報の暗号化の話ですが、これも .NET Framework 版の ASP.NET Web アプリの場合は定番のやり方があります。

    web.configの暗号化

    同様なことが App.config でもできるそうで、以下の Microsoft のドキュメントに書いてあります。(未検証・未確認です)

    App.config の例

  2. Release, Debugくらいのパターンならいいんですけど、顧客ごとに的な事も書いてるので、そうなってくるとプロジェクトファイルの構成が肥大化しそうという懸念はありますね。
    暗号化については、参考になりました。

  3. 私の回答で紹介した記事は appsettings.json, appsettings.Production.json の 2 つだけの例ですが、さらに、例えば appsettings.User.json という名前の構成ファイルを追加することもできます。私の質問者さんへのお勧めはそちらです。

Your answer might help someone💌