Emad Ibrahim
Optimal Solutions Integration, Inc.
October 2004
概要: この記事では、Visual Basic 2005 で My.Settings クラスを使って簡単にアプリケーションやユーザーの設定を保存する方法を説明します。
**メモ **この記事とコード例は、以前は "Whidbey" というコードネームが付けられていた Microsoft Visual Studio 2005 のプレリリース版に基づいています。 この記事に含まれるすべての情報は、変更される可能性があります。
目次
はじめに
従来の方法
より優れた新しい方法
高度な設定
まとめ
はじめに
Windows フォーム アプリケーションでは、アプリケーションを実行するのにデータが必要です。 多くの場合、開発者はこのデータをコードに含めることを避けようとします。コード内に記述すると、変更が発生するたびにアプリケーションを再コンパイルしなくてはならないからです。 アプリケーションが Web サービスやデータベースを利用しているなら、URL や接続文字列を個別のファイルに格納して、簡単に変更したいと思うでしょう。 また、アプリケーションがウィンドウのレイアウトや UI のカスタマイズを記憶しているなら、この情報をユーザーごとに個別に保存したいとも思うでしょう。
従来、このようなデータは INI ファイル、レジストリ、構成ファイルなど、さまざまな場所に格納されていました。 Microsoft .NET Framework 1.0 では、app.config ファイルという概念が採用されました。app.config は、このような設定を格納するために使用する、XML ファイルです。 この方法のどちらにも、いくつかの問題点があります。
- 設定がタイプセーフではない。
- ファイルの読み書きなどの処理にかなりの量のコーディングが必要。
- レジストリを使った方法では、レジストリにアクセスするためのセキュリティのアクセス許可がアプリケーションに必要。
- アプリケーションでユーザー単位の設定を維持するのが難しい。
このような課題に対応するために、新しいアプリケーションの設定アーキテクチャでは、クライアント上でアプリケーション単位とユーザー単位の両方の設定を保存するための簡単な方法が用意されています。 Visual Studio かコード エディタを使用して、名前、データ型、既定値、スコープ (アプリケーション単位かユーザー単位) を指定することで、与えられたプロパティの設定を定義します。
アプリケーションの設定は、設定がアプリケーション単位なのかユーザー単位なのかに応じて、データを XML としてそれぞれ個別の構成ファイル (.config) に保存して機能しています。 アプリケーション単位の設定は読み取り専用です。 アプリケーション単位の設定はプログラム情報であるため、通常、上書きする必要はありません。 一方、ユーザー単位の設定は、アプリケーションが部分信頼モードで動作中であっても、実行時に安全に読み取りや書き込みを行うことができます。
従来の方法
.NET Framework 1.0 では、構成ファイルとして app.config ファイルを使用するという概念が採用されました。 アプリケーションは app.config ファイルを使って、そのアプリケーションに固有の多くの設定を保存しています。 このファイルは単純な XML ファイルであるため、メモ帳で簡単に編集して、アプリケーションの設定を変更したり新しい設定を追加したりすることができます。 SMTP サーバーのアドレスやデータベースの接続文字列などを保存するのに適しているといえるでしょう。 しかし、.NET Framework 1.0 の実装には、不十分な点もいくつかありました。 その 1 つは、ファイルに書き戻すための簡単な方法がないことです。 アプリケーションのページやフォームを使って設定を変更する場合は、ファイルを XML ファイルとしてロードして変更し、書き戻す必要がありました。 また、構成ファイルのプロパティへのアクセスがタイプセーフではありませんでした。 たとえば、次のコードは正常にコンパイルできますが、PageSize の設定が整数でないと、ランタイム エラーが発生します (タイプセーフではない)。
Dim PageSize As Integer =
Configuration.ConfigurationSettings.AppSettings("PageSize")
ユーザーや開発者がこのアプリケーションの設定に、(以下のように) に数値以外の値を設定してしまうのを防ぐ方法がないため、実行時にエラーが発生します。
<add key="PageSize" value="ten"/>
より優れた新しい方法
.NET Framework 2.0 では、このような問題点のほとんどが解決され、さらに機能が向上しています。 まず注目すべき点は、新しい設定を簡単に作成できることです。 従来のように構成ファイルを開いて新しい設定を入力する必要はありません。 代わりにプロジェクト プロパティ フォームの Settings Designer を開き、新しい設定を追加します。 Settings Designer では、各設定の名前、型、スコープ (アプリケーション単位/ユーザー単位) を選択します。
スコープ
アプリケーション単位の設定は読み込み専用で、アプリケーションの全ユーザーで共有されます。 これらの設定は、app.config ファイルの <applicationSettings> セクションに格納されます。
**メモ **これは、前述の .NET Framework 1.0. で使われていた <appSettings> セクションとは異なります。
実行時に app.config ファイルが bin フォルダに作成され、ファイル名にはアプリケーションの名前が付けられます (MySettingsDemo.exe.config)。 アプリケーション単位の設定の例としては、データベース接続文字列、Web サービスの URL、サーバーの IP アドレスなどがあります。
<applicationSettings>
<MySettingsDemo.MySettings>
<setting name="SMTPServerIP" serializeAs="String">
<value>127.0.0.1</value>
</setting>
<setting name="MyServicesURL" serializeAs="String">
<value>https://localhost/myservices.asmx</value>
</setting>
</MySettingsDemo.MySettings>
</applicationSettings>
ユーザー単位の設定は、各ユーザーに対して固有です。 実行時にアプリケーション コードから安全に読み書きできます。 設定は user.config ファイルに保存されます。 正確には、アプリケーション/ユーザーごとに、非移動用と移動用の 2 つの user.configs があります。 Visual Basic 2005 のベータ版に付属のドキュメントには、user.config ファイルの名前はユーザー名に応じた名前 (joe.config) になると記載されていますが、実際はそうではありません。 user.config ファイルは <c:\Documents and Settings>\<username>\[Local Settings\]Application Data\<companyname>\<appdomainname>_<eid>_<hash>\<verison> に作成されます。 この場合、
<c:\Documents and Settings>は、ユーザー データのディレクトリで、非移動用 (上記の Local Settings) または移動用です。<username>は、ユーザー名です。<companyname>は、CompanyNameAttribute の値 (設定されている場合) です。 設定されていない場合、この要素は無視されます。<appdomainname>は、AppDomain.CurrentDomain.FriendlyName です。 通常、既定値は .exe の名前になります。<eid>は、ハッシュで利用できる証拠に応じて URL、StrongName、Path のいずれかになります。<hash>は、CurrentDomain から収集された証拠の SHA1 ハッシュで、次の順序になります。StrongName
URL
どちらも利用できない場合は .exe のパスが使われます。
<version>は、AssemblyInfo の AssemblyVersionAttribute 設定です。
パスの例を以下に示します。
C:\Documents and Settings\Emad.BROKENOAK\Local Settings\Application
Data\MySettingsDemo\MySettingsDemo_9cfe5ef1\1.0.0.0
上記のパスを開くと、図 1 のようになります。
図 1. パスの例
**メモ **ここで示すユーザー設定構成ファイルの場所は Beta 1 について説明したもので、Visual Basic 2005 の最終版での場所はまだ確定していません。
user.config ファイルは、新しいユーザーが最初にそのアプリケーションを実行するときに自動的に作成され、既定値以外の値がユーザー単位の設定に書き込まれます。 設定は app.config ファイルの <userSettings> セクションに定義されます。 設定の既定値 (初期値) も app.config ファイル内に定義されます。 app.config ファイルの既定値を以下に示します。
<userSettings>
<MySettingsDemo.MySettings>
<setting name="LastSearchedItem" serializeAs="String">
<value />
</setting>
<setting name="FormSize" serializeAs="String">
<value>400, 400</value>
</setting>
<setting name="FormLocation" serializeAs="String">
<value>0, 0</value>
</setting>
</MySettingsDemo.MySettings>
</userSettings>
ユーザー単位の設定は、一般にユーザーごとに異なるアプリケーションの環境設定を保存するのに適しています。 たとえば、ユーザー単位の設定には、フォント サイズ、ウィンドウ位置、MRU リストなどの表示設定があります。
このアーキテクチャは非常に柔軟で、アプリケーションが部分信頼モードで動作中でも、ユーザーごとに設定や環境設定を保存することが可能です。
設定の作成
アプリケーションの検索ボックスに、最後に検索した項目の値を保存できるようにしてみましょう。 まず、図 2 に示すようなアプリケーションの UI を作成します。
.gif)
図 2. 検索ボックスの UI の作成
次に、最後に検索した項目の文字列の設定を作成します。 完成した検索ボックスは図 3 のようになります。
ソリューション エクスプローラで、[My Project] をダブルクリックします。
[設定] タブをクリックして、Settings Designer を表示します。
設定の名前、型、スコープに、それぞれ「LastSearchedItem」、「String」、「ユーザー」と入力します。
[値] 列にこの設定の初期値を入力するか ("何を検索しますか?" など)、または空白のままにします。
.gif)
図 3. 完成した検索ボックス
設定の裏側
Settings Designer で新しい設定を追加すると、その背後でさまざまな処理が行われます。 まず、設定を定義するために、セクションを定義するエントリが app.config ファイルに追加されます。
<configSections>
<sectionGroup
name="applicationSettings"type="System.Configuration.ApplicationSettingsGroup, System,
Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<section name="MySettingsDemo.MySettings"
type="System.Configuration.ClientSettingsSection, System,
Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</sectionGroup>
</configSections>
次に、設定の定義自体が app.config ファイルに追加されます (以下を参照)。 定義した設定の型に応じて、applicationSettings、userSettings、connectionStrings セクションのいずれかまたはすべてが追加されます。
<userSettings>
<MySettingsDemo.MySettings>
<setting name="LastSearchedItem" serializeAs="String">
<value />
</setting>
<setting name="FormSize" serializeAs="String">
<value>400, 400</value>
</setting>
<setting name="FormLocation" serializeAs="String">
<value>0, 0</value>
</setting>
</MySettingsDemo.MySettings>
</userSettings>
<connectionStrings>
<add name="MySettingsDemo.MySettings.ConnectionString"
connectionString="Server=TABLET; User ID=sa; Password=1234;
Database=Northwind; Persist Security Info=True"
providerName="System.Data.SqlClient" />
</connectionStrings>
<applicationSettings>
<MySettingsDemo.MySettings>
<setting name="SMTPServerIP" serializeAs="String">
<value>192.168.2.11</value>
</setting>
<setting name="MyServicesURL" serializeAs="String">
<value>https://localhost/MyServices/Service1.asmx</value>
</setting>
</MySettingsDemo.MySettings>
</applicationSettings>
設定へのアクセス
これで設定が追加されたため、今度は設定を取得して更新します。 設定の取得はとても簡単です。 以下に例を示します。
My.Settings.LastSearchedItem
図 4 に、アプリケーションの設定フィールドに IntelliSense を通してアクセスする方法を示します。この機能により、使用する必要のある正確な設定値を簡単に探すことができます。
.gif)
図 4. IntelliSense 機能
設定を使用するには、プロパティにバインドするという方法もあります。 この方法では、コードを記述する必要がほとんどありません。 たとえば、FormLocation 設定をフォームの Location プロパティにバインドすることが可能です。
- フォームの [プロパティ] ウィンドウで、[Data]、[ApplicationSettings]、[PropertyBinding] の順に展開します。
- 図 5 に示すように、Location プロパティを探し、FormLocation 設定を選択します。
.gif)
図 5. FormLocation 設定の選択
これにより、フォームのデザイナ分離コード クラスにコードが作成されます。
Me.DataBindings.Add(New System.Windows.Forms.Binding("Location",
MySettingsDemo.MySettings.Value, "FormLocation", True,
MySettingsDemo.MySettings.Value.LastSearchedItem, Nothing,
System.Windows.Forms.BindingUpdateMode.OnPropertyChanged))
Binding クラスの構造での最後のパラメータに注意してください。 このパラメータは、設定の更新モードを定義します。 変更や検証行う際に更新するように設定したり、一切更新しないように設定することができます。 デザイナで生成される既定のコードでは、変更時に更新されるようになっています。
設定をプロパティにバインドすると、設定の読み取りや書き込みを気にかける必要がなくなります。 プロパティは必要に応じて自動的に設定され、値が変更された場合でも、その値は自動的に保存されます。 コードを 1 行も記述することなく、これらすべてを行うことができます。
**メモ **設定は、Visual Basic Windows フォーム アプリケーションのような特定のプロジェクト タイプの場合にのみ、自動的に保存されます。 クラス ライブラリ プロジェクトなど、その他の場合は、My.Settings クラスの Save メソッドを明示的に呼び出す必要があります。
プロパティが [property-binding] ウィンドウの一覧に表示されない場合でも、コードを使って同じことを実行できます。 何らか理由で、Size プロパティはバインド可能なプロパティとして表示されません。 これはこのバージョンでの設計上の判断ですが、最終版ではすべてのプロパティがバインドできるようになります。 そのためには、フォームの DataBindings コレクションに新しく Binding を追加します。 Binding クラスは、プロパティ名、設定名、データ ストア、更新モードを定義するために使用します。 したがって、Size プロパティを FormSize 設定にバインドするには、フォームのロード イベントで手動でバインディングを作成します。
Me.DataBindings.Add(New System.Windows.Forms.Binding("Size", _
MySettingsDemo.MySettings.Value, _
"FormSize"))
高度な設定
設定をより細かく制御したい場合は、すべての設定クラスの親クラスである ApplicationSettingsBase の派生クラスを作成します。 各設定を、get と set の両方が定義されたプロパティとして定義します。 プロパティがアプリケーション単位の設定の場合は、ApplicationScopedSettingAttribute で修飾します。プロパティがユーザー単位の設定の場合は、UserScopedSettingAttribute で修飾します。 実際、Settings Designer も同じことを行っています。 以下に、Settings Designer によって生成された MySettings.vb ファイルの一部を示します。
Partial NotInheritable Class MySettings
Inherits System.Configuration.ApplicationSettingsBase
<System.Diagnostics.DebuggerNonUserCode(), _
System.Configuration.UserScopedSettingAttribute(), _
System.Configuration.DefaultSettingValueAttribute("400, 400")> _
Public Property FormSize() As System.Drawing.Size
Get
Return CType(Me("FormSize"),System.Drawing.Size)
End Get
Set
Me("FormSize") = value
End Set
End Property
<System.Diagnostics.DebuggerNonUserCode(), _
System.Configuration.SpecialSetting(System.Configuration.SpecialSetting.ConnectionString), _
System.Configuration.ApplicationScopedSettingAttribute(), _
System.Configuration.DefaultSettingValueAttribute("Server=TABLET;
User ID=sa; Password=1234; Database=Northwind; Persist Security In"& _
"fo=True")> _
Public ReadOnly Property ConnectionString() As String
Get
Return CType(Me("ConnectionString"),String)
End Get
End Property
<System.Diagnostics.DebuggerNonUserCode(), _
System.Configuration.ApplicationScopedSettingAttribute(), _
System.Configuration.DefaultSettingValueAttribute("192.168.2.11")> _
Public ReadOnly Property SMTPServerIP() As String
Get
Return CType(Me("SMTPServerIP"),String)
End Get
End Property
...
**メモ **接続文字列は SpecialSetting 属性で修飾します。 この設定も、構成ファイル内に専用のセクションが作成されます。
また、これが Partial クラスである点に注意してください。つまり、プロジェクトに別のファイルを作成し、このクラスの別の部分を記述できます。 この手法を使うことで、デザイナによって生成されたファイルは変更せずに設定を微調整できます。 設定をより正確に制御するために、このクラスにイベント処理を追加します。 処理できるイベントは次の 3 つです。
- SettingChanging
- SettingsSaving
- PropertyChanging
設定機能は、プラグ可能なプロバイダ インフラストラクチャの上に位置している点に注意してください。 現在の Visual Studio 2005 には、構成ファイルにアクセスできるプロバイダとしては LocalFileSettingsProvider のみが含まれています。 これ以外のプロバイダも、Local File Settings Provider の代わりに、またはそれに追加する形でプラグイン可能です。 この良い例は、雲型シナリオでの設定 です。このシナリオでは、Web サービスを使って設定をデータベースに格納し、ユーザーがログインしたあらゆる場所から設定を取り出します。**
まとめ
アプリケーションの設定を扱う以前のアーキテクチャにはいくつかの制限がありましたが、.NET Framework 2.0 の新しいアプリケーションの設定アーキテクチャでは、これらの問題の多くが解決されています。 これまで説明してきたように、この新しいアーキテクチャでは、Visual Basic 2005 を利用して、設定の作成、バインド、取得、および更新を簡単に行うことができます。 また、アプリケーション単位の設定やユーザー単位の設定にも対応しています。 この新しいアーキテクチャによって生産性が確実に向上し、開発者は複雑なアプリケーション設定を理解するのに何日も何週間も費やすことなく、業務上の課題を解決することに集中できます。
Emad Ibrahim 氏 (MCSD、MCAD) は、Optimal Solutions Integration, Inc
のテクニカル アーキテクトです。