Settings.Default。<プロパティ>永続ストレージ(XMLファイル)の値ではなく、常にデフォルト値を返します
-
08-07-2019 - |
質問
最近、IPアドレスを必要とするクラスを含むDLLをC#(.Net 2.0)で作成しました。私の同僚がクラスを変更して、「。dll.config」からIPを取得しました。 (XML)ファイル-これは明らかに「アプリケーション設定」によって自動的に生成されます;彼が作成したファイル(Settings1.settings)。この利点は、エンドユーザーがXML / configファイルのIPアドレスを自由に変更できるようにすることでした。
残念ながら、ツリーから彼のコードをチェックアウトしてこの新しいコードをコンパイル(または使用)しようとすると、このDLLを呼び出すアプリケーションは、ファイルの値ではなくデフォルト値のみを取得します。
構成ファイルを呼び出すコンストラクターは次のようになります。
public class form : System.Windows.Forms.Form
{
public form()
{
// This call is required by the Windows Form Designer.
InitializeComponent();
IP = IPAddress.Parse(Settings1.Default.IPAddress);
}
}
aが見つかりましたユーザーが言ったMSDNフォーラムでのこの問題への参照:
「古い」値(開発時に定義する値)はハードコードされています。フレームワークが設定ファイルにアクセスまたは開くことができない場合は、代わりにデフォルトが使用されます。これは、dllの設定を使用する場合に常に発生します。
-
これは、構成ファイルにDLLの外部値を保存できないことを意味しますか? (私の同僚はどういうわけかこの仕事をしました...)
-
私のフレームワークは設定ファイルにアクセスしたり開いたりすることができないように見えるので、どうして失敗したのかを知るにはどうすればいいですか?または、これがいつ発生するかを検出しますか?
デッカー:それは少し役立ちます。残念ながら、私はこのDLLを仕様に沿って記述しているため、実際にはアプリケーションの構成ファイルにアクセスできません。前述のとおり、同僚が" Settings 1 .settings"を作成しました。ファイル。当時はこれを理解していませんでしたが、今は「1」を追加するようです。それを呼び出すアプリケーションの設定スペースからそれを保ちます。
私が理解しようとしているのは、DLLが同じディレクトリ内でその隣にある設定ファイルを見つけられないように思える理由です。コードを段階的にトレースしても何も明らかになりません。
余談ですが、「出力タイプ」を変更できます。 「クラスライブラリ」からのアセンブリの「Windowsアプリケーション」へDLLコードの先頭に次の行を追加します。
[STAThread]
public static void Main(string[] args)
{
System.Windows.Forms.Application.Run(new form());
}
これを実行すると、別の構成ファイル(" .exe.config")が生成され、その構成ファイルを変更して、ファイルから新しいデータを取得することができます。だから私は少し混乱しています。アイデアはありますか?
解決
私はプロトタイプ作成中のアプリケーションでこの正確な問題に取り組んでいます。構成ファイルを一緒にハッキングするというDeckerの提案は機能するはずですが、これはビルドサイクルの一部として実行するにはかなり不便な手動ハックだと思います。その代わりに、最もクリーンなソリューションは、各ライブラリが独自のlibrary.dll.configファイルを解析することであると判断しました。まだ完全ではなく、追加の定型コードが必要ですが、.Netがこれらのapp.configファイルを処理するビザンチンの方法を回避する唯一の方法のようです。
他のヒント
私は常にこの手法を使用しています。多くの場合、特定の設定を必要とするライブラリアセンブリがあり、プロジェクトと主要な「実行可能ファイル」の両方をテストすることで設定する必要があります。アセンブリ-WebプロジェクトでもWindowsサービスプロジェクトでも。
プロジェクトの設定ファイルを作成すると、アプリケーション構成ファイルが追加されます。設定に入力する値は、設定ファイルと設定インフラストラクチャによって作成されたクラスの属性の2つの場所に保存されます。構成ファイルが見つからない場合、属性に埋め込まれた値が使用されます。
このような属性を示すスニペットを次に示します。
生成されたクラスのConcordanceServicesEndpointNameのデフォルト値を示すスニペットを次に示します。
[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("InternalTCP")]
public string ConcordanceServicesEndpointName {
get {
return ((string)(this["ConcordanceServicesEndpointName"]));
}
}
実行したいのは、ライブラリアセンブリプロジェクトのapp.configファイルから構成セクションをコピーし、メインアセンブリの適切なweb.configまたはapp.configに(慎重に)マージすることです。実行時に、それが使用される唯一の設定ファイルです。
例を次に示します。
<configSections>
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="LitigationPortal.Documents.BLL.DocumentsBLLSettings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</sectionGroup>
</configSections>
<applicationSettings>
<LitigationPortal.Documents.BLL.DocumentsBLLSettings>
<setting name="ConcordanceServicesEndpointName" serializeAs="String">
<value>InternalTCP</value>
</setting>
</KayeScholer.LitigationPortal.Documents.BLL.DocumentsBLLSettings>
</applicationSettings>
これらのセクションを&quot; true&quot;にコピーする必要があります構成ファイル。
私は長い間この同じ問題を抱えていました-迷惑です。
独自の設定ファイルを作成し、各DLLで解析するというアイデアは気に入っていますが、設定を変更する必要があります。
過去にこれを少しだけ簡単にするために行ったことの1つは、Setting1.Settingsファイルの設定値が無効であることを確認することです。
たとえば、LINQ-To-SQLを使用してDBと通信するクラスがあります。そのため、データベースへの接続文字列を保存するSetting1.settingsファイルがあります。(データベーステーブルをデザイナーにドラッグアンドドロップする際に)入力されるデフォルト値は、devデータベースの接続文字列です。
テストデータベースに基づいてDBMLファイルを作成したら、設定ファイルを開いて編集し、「FAKE_DATABASE」などのデータベース名を入力できます。
その方法で、別のプロジェクトでDLLを使用し、構成ファイルをマージしてDLLの適切な構成値を追加するのを忘れると、少なくとも&quot; Cannot connect toなどのエラーが表示されますFAKE_DATABASE&quot;。
もちろん、デザイナーと再度作業する必要がある場合は、値を開発データベースの値に戻す必要があります。
大きな痛み。彼らは何とかこれを変更する必要があります。
明らかに、アプリケーションはデフォルトの構成ファイル(おそらくアプリケーションの構成ファイル)から読み取ろうとしているようです。確認するには、dllの構成ファイルのキーと値のペアをアプリケーションの構成ファイルに追加し、アプリケーションを実行して、今回読み取られるかどうかを確認します。
DLLとテストアプリケーションでこれが機能しない理由の説明を見つけたと思います。 誰かのブログの最後の例外は次のとおりです。
これに対する修正は、アプリケーションとサポートアセンブリの名前空間が同じであることを確認するか、AppName.exe.configとDllName.dll.configの内容をマージすることです(.dllをコンパイルするときはい)これでこのファイルが生成されますが、アプリケーションディレクトリにコピーした場合は無視され、自動的にはマージされません)
したがって、DLLとアプリケーションを同じネームスペースに保持するか、DLL構成ファイルの内容をアプリケーションの構成ファイルにマージする必要があります。
(この種のDLLはDLLの目的に反しませんか?DLLは独立したライブラリであると考えられていました。)
おそらく、これが私の同僚のために働く理由です。本番アプリケーションは、DLLと同じ名前空間を共有します。 (私のテストアプリは明らかにそうではありません...)
更新:最近同僚と座ってこの問題について再び話しましたが、彼にとってもうまくいかなかったようですが、彼は初期値を、使用しようとしているデバイスと同じになるように設定します。当然、最初は動作しているように見えましたが、わずかに異なる設定で他の場所に展開するとすぐに再び壊れました。
app.configの使用時に同様の問題が発生しました。 Visual Studioの代わりに.exeからアプリケーションを実行してみてください&amp;その後、期待どおりに動作するかどうかを確認します。
DLLで、アクセス修飾子(Settings1.Settings用)が内部(VBのフレンド)に設定されている可能性があります。 Access MOdifierをPublicに変更してみて、それによってアプリケーションがdllの設定から値を読み書きできるかどうかを確認してください。
ハワードからの答えは理論をカバーしています。
これを解決するための手っ取り早い方法の1つは、xml構成ファイルを手動で解析することです。
string configFile = Assembly.GetExecutingAssembly().Location + ".config";
XDocument.Load(configFile).Root.Element("appSettings")....
私が皆さんが犯す間違いは、 Settings1.IPAddress
を実行するように単純に想定されている間に、 Settings1.Default.IPAddress
を介してDLL設定を参照することです。 >。
違いは、 Settings1.Default.IPAddress
を使用すると、アセンブリファイル(.dllまたは.exe)に属性[global :: System。]に埋め込まれたハードコーディングされた値から値が取得されることです。 Configuration.DefaultSettingValueAttribute(...)]。
Settings1.IPAddress
は、ファイル .dll.config
(XMLファイル)**で編集可能な値です。したがって、XMLファイルに加えた変更は、アセンブリのハードコーディングされたデフォルト値には反映されません。
これではない:
IP = IPAddress.Parse(Settings1.Default.IPAddress);
しかしこれを試してください:
*IP = IPAddress.Parse(Settings1.IPAddress);