(VB.Net)プロジェクトにDIコンテナを構成してフォームを表示するまでの手順 - tsukimisoba/Blog GitHub Wiki

2025/05/23 記載
環境: Windows 11
VB.NET 2022
Framework: Net9.0

プロジェクトにDIコンテナを構成してフォームを表示するまでの手順

目的

  • VB.Net でDIコンテナ実装手順の確立
  • Net9 環境でプロジェクト構築手順の確立
  • Net9 環境でNlog実装手順の確立
  • Net9 環境で appsettings.json 使用方法の確立
  • VB.Net でテストプロジェクト作成手順の確立

構成図

/MainApp
├── /Controllers      # コントローラー
│   ├── FormController.vb
│   └── IFormController.vb
├── /Models           # モデル
├── /Views            # ビュー
│   ├── Mainform.vb
│   └── Subform.vb
├── /Services         # ビジネスロジック
│   └── ApplicationContext.vb
├── /Config           # 設定ファイル(環境設定など)
│   ├── appsettings.json
│   └── AppSettings.vb
└── Program.vb        # アプリケーションのエントリーポイント

シーケンス図


手順

  1. NuGetパッケージの追加
  2. Sub Main() メソッドを実装した Program.vb スタートアップオブジェクトファイルの作成
  3. プロジェクトファイル ~.vbproj の修正
  4. プロジェクトのスタートアップ を Sub Main() へ変更
  5. DIコンテナ制御クラス ApplicationContext クラスの実装
  6. appsettings.json の作成
  7. AppSettingsクラス の実装
  8. IFormController インタフェースの実装
  9. FormController の実装
  10. メインフォーム( Mainform ) の実装
  11. サブフォーム( SubForm ) の実装
  12. テストプロジェクトの作成
  13. 単体テストロジックの作成
  14. 単体テストの実施

手順詳細

手順1. NuGetパッケージの追加

必要なパッケージをインストールします。

dotnet add package Microsoft.Extensions.Configuration
dotnet add package Microsoft.Extensions.Configuration.Xml
dotnet add package Microsoft.Extensions.Configuration.Json
dotnet add package Microsoft.Extensions.DependencyInjection
dotnet add package NLog.Extensions.Logging

手順2. Sub Main() メソッドを実装した Program.vb スタートアップオブジェクトファイルの作成

Imports Microsoft.Extensions.Configuration
Imports NLog
Imports NLog.Config
Imports NLog.Targets

Module Program
    ''' <summary>
    ''' アプリケーションのメインエントリーポイント
    ''' </summary>
    <STAThread>
    Sub Main()
        ' Windows Forms アプリケーションの初期化
        Application.EnableVisualStyles()
        Application.SetCompatibleTextRenderingDefault(False)

        ' NLog の初期化
        InitializeNLog()

        ' DIコンテナの初期化
        ApplicationContext.Initialize()

        Try
            ' メインフォームの取得と実行
            Dim formController As FormController = ApplicationContext.GetRequiredServiceByTypeString("FormController")
            Application.Run(formController.ShowForm("Mainform"))
        Finally
            ApplicationContext.Cleanup()
        End Try
    End Sub

    ''' <summary>
    ''' NLogを初期化します
    ''' </summary>
    Private Sub InitializeNLog()
        ' 設定ファイルの読み込み
        Dim configuration As IConfiguration = New ConfigurationBuilder() _
            .SetBasePath(AppDomain.CurrentDomain.BaseDirectory) _
            .AddJsonFile("Config\\appsettings.json", optional:=False, reloadOnChange:=True) _
            .Build()

        ' AppSettings の設定
        Dim appSettings As New AppSettings()
        appSettings.NlogFilePath = configuration("NlogSettings:NlogFilePath")
        appSettings.NlogLevel = configuration("NlogSettings:NlogLevel")
        appSettings.NlogLayout = configuration("NlogSettings:NlogLayout")

        Dim config As New LoggingConfiguration()

        ' ファイルターゲットの設定
        Dim fileTarget As New FileTarget("fileTarget") With {
            .FileName = appSettings.NlogFilePath,
            .Layout = appSettings.NlogLayout
        }

        ' ログレベルの設定
        Dim logLevel As LogLevel = LogLevel.FromString(appSettings.NlogLevel)
        config.AddRule(logLevel, LogLevel.Fatal, fileTarget)

        ' NLogに設定を適用
        LogManager.Configuration = config
    End Sub

End Module

手順3. プロジェクトファイル ~.vbproj の修正

以下を参照
VB.NETでスタートアップを Main() にする方法


手順4. プロジェクトのスタートアップ を Sub Main() へ変更

以下を参照
VB.NETでスタートアップを Main() にする方法


手順5. DIコンテナ制御クラス ApplicationContext クラスの実装

Imports System.Reflection
Imports Microsoft.Extensions.DependencyInjection

Public Class ApplicationContext
    Private Shared _serviceProvider As ServiceProvider
    ''' <summary>
    ''' サービスプロバイダ
    ''' </summary>
    ''' <returns>サービスプロバイダ</returns>
    Public Shared ReadOnly Property ServiceProvider As IServiceProvider
        Get
            Return _serviceProvider
        End Get
    End Property
    ''' <summary>
    ''' 初期化
    ''' </summary>
    Public Shared Sub Initialize()
        Dim services As New ServiceCollection()

        ' AppSettings をシングルトンとして登録
        services.AddSingleton(Of AppSettings)

        ' サービス登録
        services.AddSingleton(Of FormController)()
        ' フォーム登録
        services.AddTransient(Of Mainform)()
        services.AddTransient(Of Subform)()

        _serviceProvider = services.BuildServiceProvider()
    End Sub

    ''' <summary>
    ''' 型名でサービスの取得
    ''' </summary>
    ''' <param name="typeName">型名</param>
    ''' <returns></returns>
    Public Shared Function GetRequiredServiceByTypeString(typeName As String) As Object
        Dim targetType As Type = Assembly.GetExecutingAssembly().GetType("MainApp." + typeName)
        Return ApplicationContext.ServiceProvider.GetRequiredService(targetType)
    End Function

    ''' <summary>
    ''' サービスプロバイダのクリーンアップ
    ''' </summary>
    Public Shared Sub Cleanup()
        _serviceProvider?.Dispose()
    End Sub

End Class

手順6. appsettings.json の作成

{
  "NlogSettings": {
    "NlogFilePath": "${basedir}\\log\\Applog_${shortdate}.log",
    "NlogLevel": "Info",
    "NlogLayout": "${longdate}|${level:uppercase=true}|${message}"
  }
}

手順7. AppSettingsクラス の実装

''' <summary>
''' アプリケーション設定を管理するクラス
''' </summary>
Public Class AppSettings
    ''' <summary>
    ''' NLogのログファイルパス
    ''' </summary>
    Public Property NlogFilePath As String

    ''' <summary>
    ''' NLogのログレベル
    ''' </summary>
    Public Property NlogLevel As String

    ''' <summary>
    ''' NLogのログレイアウト
    ''' </summary>
    Public Property NlogLayout As String

End Class

手順8. IFormController インタフェースの実装

''' <summary>
''' フォーム制御用インターフェース
''' </summary>
Public Interface IFormController

    ''' <summary>
    ''' フォームを表示します
    ''' </summary>
    Function ShowForm(Optional ByVal formName As String = "") As Form

    ''' <summary>
    ''' フォームを非表示にします
    ''' </summary>
    Sub HideForm(Optional ByVal formName As String = "")

    ''' <summary>
    ''' フォームを表示します
    ''' </summary>
    Sub ShowNextForm(nextFormName As String)

    ''' <summary>
    ''' フォームを表示します
    ''' </summary>
    Sub ShowBackForm()
End Interface

手順9. FormController の実装

Imports NLog

''' <summary>
''' フォーム制御を管理するクラス
''' </summary>
Public Class FormController
    Implements IFormController

    Private ReadOnly _logger As Logger

    Private _beginFormName As String
    Private _viewFormName As String
    Private _viewForm As Form

    Public ReadOnly Property ViewForm As Form
        Get
            Return _viewForm
        End Get
    End Property

    ''' <summary>
    ''' FormControllerクラスのコンストラクタ
    ''' </summary>
    ''' <param name="mainForm">メインフォーム</param>
    ''' <param name="subForm">サブフォーム</param>
    Public Sub New()
        _logger = LogManager.GetCurrentClassLogger()
    End Sub

    ''' <summary>
    ''' フォームを表示します
    ''' </summary>
    Public Function ShowForm(Optional ByVal formName As String = "") As Form Implements IFormController.ShowForm
        _viewForm = GetTargetForm(formName)
        _logger.Info(_viewFormName + "を表示します")
        _viewForm.Show()
        Return _viewForm
    End Function

    ''' <summary>
    ''' フォームを非表示にします
    ''' </summary>
    Public Sub HideForm(Optional ByVal formName As String = "") Implements IFormController.HideForm
        _viewForm = GetTargetForm(formName)
        _logger.Info(_viewFormName + "を非表示にします")
        _viewForm.Hide()
    End Sub

    ''' <summary>
    ''' フォームを遷移する
    ''' </summary>
    ''' <param name="nextFormName"></param>
    Public Sub ShowNextForm(nextFormName As String) Implements IFormController.ShowNextForm
        _beginFormName = _viewFormName
        _logger.Info(nextFormName + "を表示します")
        HideForm()
        ShowForm(nextFormName)
    End Sub

    ''' <summary>
    ''' 前画面に戻る
    ''' </summary>
    Public Sub ShowBackForm() Implements IFormController.ShowBackForm
        _logger.Info(_beginFormName + "を表示します")
        HideForm()
        ShowForm(_beginFormName)
    End Sub

    Private Function GetTargetForm(formName As String) As Form
        If String.IsNullOrEmpty(formName) Then
            If _viewForm IsNot Nothing Then
                Return _viewForm
            Else
                Return Nothing
            End If
        End If
        _viewFormName = formName
        Return DirectCast(ApplicationContext.GetRequiredServiceByTypeString(formName), Form)
    End Function
End Class

手順10. メインフォーム( Mainform ) の実装

''' <summary>
''' メインフォームクラス
''' </summary>
Public Class MainForm
    Private ReadOnly _formController As IFormController

    ''' <summary>
    ''' MainFormクラスのコンストラクタ
    ''' </summary>
    ''' <param name="formController">フォームコントローラー</param>
    Public Sub New()
        _formController = ApplicationContext.GetRequiredServiceByTypeString("FormController")
        InitializeComponent()
    End Sub

    Private Sub ButtonToSubForm_Click(sender As Object, e As EventArgs) Handles ButtonToSubForm.Click
        _formController.ShowNextForm("Subform")
    End Sub

End Class

手順11. サブフォーム( SubForm ) の実装

''' <summary>
''' サブフォームクラス
''' </summary>
Public Class SubForm
    Private ReadOnly _formController As IFormController

    ''' <summary>
    ''' SubFormクラスのコンストラクタ
    ''' </summary>
    ''' <param name="formController">フォームコントローラー</param>
    Public Sub New()
        _formController = ApplicationContext.GetRequiredServiceByTypeString("FormController")
        InitializeComponent()
    End Sub

    ''' <summary>
    ''' 戻るボタンクリックイベント
    ''' </summary>
    Private Sub ButtonBack_Click(sender As Object, e As EventArgs) Handles ButtonBack.Click
        _formController.ShowBackForm()
    End Sub

End Class

⚠️ **GitHub.com Fallback** ⚠️