私が達成したいことは非常に簡単です:私は情報を読むためにパスを使うWindowsフォーム(.NET 3.5)アプリケーションを持っています。このパスは、私が提供するオプションフォームを使用して、ユーザーが変更できます。
今、私は後で使用するためにファイルにパス値を保存したいです。これは、このファイルに保存されている多くの設定のうちの1つです。このファイルはアプリケーションフォルダに直接置かれます。
私は3つの選択肢が利用可能であることを理解しています。
私は、.NET構成ファイルに値を保存することは考えられていないことを読みました。レジストリに関しては、私はそれからできるだけ遠く離れたいと思います。
これは、構成設定を保存するためにカスタムXMLファイルを使用する必要があるということですか?もしそうなら、私はそれ(C#)のコード例を見たいと思います。
私はこの問題に関して他の議論を見ました、しかしそれはまだ私には明らかではありません。
Visual Studioを使用している場合は、永続的な設定を取得するのはとても簡単です。ソリューションエクスプローラーでプロジェクトを右クリックし、[プロパティ]を選択します。 [設定]タブを選択し、設定が存在しない場合はハイパーリンクをクリックします。 [設定]タブを使用してアプリケーション設定を作成します。 Visual Studioは、 ApplicationSettingsBase から継承されたシングルトンクラスSettings
を含むファイルSettings.settings
およびSettings.Designer.settings
を作成します。コードからこのクラスにアクセスして、アプリケーション設定を読み書きできます。
Properties.Settings.Default["SomeProperty"] = "Some Value";
Properties.Settings.Default.Save(); // Saves settings in application configuration file
この手法は、コンソール、Windowsフォーム、およびその他のプロジェクトの種類の両方に適用できます。
設定の scope プロパティを設定する必要があることに注意してください。 [Application scope]を選択した場合は、Settings.Default。<your property>は読み取り専用になります。
実行可能ファイルと同じディレクトリ内のファイルに保存することを計画している場合は、 _ json _ という形式を使用したNiceソリューションを次に示します。
using System;
using System.IO;
using System.Web.Script.Serialization;
namespace MiscConsole
{
class Program
{
static void Main(string[] args)
{
MySettings settings = MySettings.Load();
Console.WriteLine("Current value of 'myInteger': " + settings.myInteger);
Console.WriteLine("Incrementing 'myInteger'...");
settings.myInteger++;
Console.WriteLine("Saving settings...");
settings.Save();
Console.WriteLine("Done.");
Console.ReadKey();
}
class MySettings : AppSettings<MySettings>
{
public string myString = "Hello World";
public int myInteger = 1;
}
}
public class AppSettings<T> where T : new()
{
private const string DEFAULT_FILENAME = "settings.json";
public void Save(string fileName = DEFAULT_FILENAME)
{
File.WriteAllText(fileName, (new JavaScriptSerializer()).Serialize(this));
}
public static void Save(T pSettings, string fileName = DEFAULT_FILENAME)
{
File.WriteAllText(fileName, (new JavaScriptSerializer()).Serialize(pSettings));
}
public static T Load(string fileName = DEFAULT_FILENAME)
{
T t = new T();
if(File.Exists(fileName))
t = (new JavaScriptSerializer()).Deserialize<T>(File.ReadAllText(fileName));
return t;
}
}
}
レジストリはダメです。アプリケーションを使用しているユーザーが、レジストリに書き込むための十分な権限を持っているかどうかはわかりません。
app.config
ファイルを使用して、アプリケーションレベルの設定を保存できます(これは、アプリケーションを使用する各ユーザーに対して同じです)。
ユーザー固有の設定をXMLファイルに保存します。このファイルは 分離ストレージ または SpecialFolder.ApplicationData ディレクトリに保存します。
その次に、.NET 2.0以降と同様に、値をapp.config
ファイルに格納することができます。
ApplicationSettings
クラスはapp.configファイルへの設定の保存をサポートしていません。これは設計上非常に重要です。適切にセキュリティ保護されたユーザーアカウント(Vista UACと考えています)で実行されるアプリケーションは、プログラムのインストールフォルダーに書き込み権限を持っていません。
ConfigurationManager
クラスを使ってシステムと戦うことができます。しかし、簡単な回避策は、Settingsデザイナに入り、設定の範囲をUserに変更することです。それが困難を引き起こす場合(たとえば、設定がすべてのユーザーに関連している場合)、オプション昇格のプロンプトを要求できるように、オプション機能を別のプログラムに入れる必要があります。または設定を使用して差し控える。
私はこれのために私が作ったライブラリを共有したいと思いました。これは小さなライブラリですが、.settingsファイルに対する大きな改善点(私見)です。
このライブラリは Jot(GitHub) と呼ばれています - これは古いです - コードプロジェクトの記事 私はそれについて書きました。
ウィンドウのサイズと位置を追跡するためにこれを使用する方法は次のとおりです。
public MainWindow()
{
InitializeComponent();
_stateTracker.Configure(this)
.IdentifyAs("MyMainWindow")
.AddProperties(nameof(Height), nameof(Width), nameof(Left), nameof(Top), nameof(WindowState))
.RegisterPersistTrigger(nameof(Closed))
.Apply();
}
.settingsファイルと比較した場合の利点: コードがかなり少なくなり、各プロパティに言及する必要があるのでエラーが発生しにくくなります once 。
設定ファイルでは、各プロパティを five times:1回ずつ明示的にプロパティを作成し、さらに4回追加して値を前後にコピーする必要があります。
ストレージ、シリアル化などは完全に設定可能です。ターゲットオブジェクトがIOCコンテナによって作成されたとき、それが解決するすべてのオブジェクトに自動的にトラッキングを適用するように[フックする] []することができます。それに[Trackable]属性をつけてください。
- データをグローバルに、または追跡対象オブジェクトごとに永続化して適用する場合 - データのシリアル化方法 - 格納場所(ファイル、データベース、オンライン、分離ストレージ、レジストリなど) - 適用/永続化をキャンセルできるルールプロパティのデータ
私を信頼してください、図書館は一流です!
Registry/configurationSettings/XML引数は、まだ非常にアクティブです。技術が進歩したので私はそれらすべてを使ったが、私のお気に入りは Threedのシステム と Isolated Storage を組み合わせたものに基づいている。
次のサンプルでは、propertiesという名前のオブジェクトを独立した記憶域内のファイルに保存できます。といった:
AppSettings.Save(myobject, "Prop1,Prop2", "myFile.jsn");
プロパティは、次の方法で回復できます。
AppSettings.Load(myobject, "myFile.jsn");
これは単なるサンプルであり、ベストプラクティスを示唆するものではありません。
internal static class AppSettings
{
internal static void Save(object src, string targ, string fileName)
{
Dictionary<string, object> items = new Dictionary<string, object>();
Type type = src.GetType();
string[] paramList = targ.Split(new char[] { ',' });
foreach (string paramName in paramList)
items.Add(paramName, type.GetProperty(paramName.Trim()).GetValue(src, null));
try
{
// GetUserStoreForApplication doesn't work - can't identify.
// application unless published by ClickOnce or Silverlight
IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForAssembly();
using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(fileName, FileMode.Create, storage))
using (StreamWriter writer = new StreamWriter(stream))
{
writer.Write((new JavaScriptSerializer()).Serialize(items));
}
}
catch (Exception) { } // If fails - just don't use preferences
}
internal static void Load(object tar, string fileName)
{
Dictionary<string, object> items = new Dictionary<string, object>();
Type type = tar.GetType();
try
{
// GetUserStoreForApplication doesn't work - can't identify
// application unless published by ClickOnce or Silverlight
IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForAssembly();
using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(fileName, FileMode.Open, storage))
using (StreamReader reader = new StreamReader(stream))
{
items = (new JavaScriptSerializer()).Deserialize<Dictionary<string, object>>(reader.ReadToEnd());
}
}
catch (Exception) { return; } // If fails - just don't use preferences.
foreach (KeyValuePair<string, object> obj in items)
{
try
{
tar.GetType().GetProperty(obj.Key).SetValue(tar, obj.Value, null);
}
catch (Exception) { }
}
}
}
簡単な方法は、設定データオブジェクトを使用し、ローカルフォルダにアプリケーションの名前を付けてXMLファイルとして保存し、起動時にそれを読み戻すことです。
これは、フォームの位置とサイズを格納する例です。
設定データオブジェクトは強く型付けされていて使いやすいです:
[Serializable()]
public class CConfigDO
{
private System.Drawing.Point m_oStartPos;
private System.Drawing.Size m_oStartSize;
public System.Drawing.Point StartPos
{
get { return m_oStartPos; }
set { m_oStartPos = value; }
}
public System.Drawing.Size StartSize
{
get { return m_oStartSize; }
set { m_oStartSize = value; }
}
}
保存とロードのためのマネージャクラス:
public class CConfigMng
{
private string m_sConfigFileName = System.IO.Path.GetFileNameWithoutExtension(System.Windows.Forms.Application.ExecutablePath) + ".xml";
private CConfigDO m_oConfig = new CConfigDO();
public CConfigDO Config
{
get { return m_oConfig; }
set { m_oConfig = value; }
}
// Load configuration file
public void LoadConfig()
{
if (System.IO.File.Exists(m_sConfigFileName))
{
System.IO.StreamReader srReader = System.IO.File.OpenText(m_sConfigFileName);
Type tType = m_oConfig.GetType();
System.Xml.Serialization.XmlSerializer xsSerializer = new System.Xml.Serialization.XmlSerializer(tType);
object oData = xsSerializer.Deserialize(srReader);
m_oConfig = (CConfigDO)oData;
srReader.Close();
}
}
// Save configuration file
public void SaveConfig()
{
System.IO.StreamWriter swWriter = System.IO.File.CreateText(m_sConfigFileName);
Type tType = m_oConfig.GetType();
if (tType.IsSerializable)
{
System.Xml.Serialization.XmlSerializer xsSerializer = new System.Xml.Serialization.XmlSerializer(tType);
xsSerializer.Serialize(swWriter, m_oConfig);
swWriter.Close();
}
}
}
これでインスタンスを作成してフォームのloadイベントとcloseイベントで使用できます。
private CConfigMng oConfigMng = new CConfigMng();
private void Form1_Load(object sender, EventArgs e)
{
// Load configuration
oConfigMng.LoadConfig();
if (oConfigMng.Config.StartPos.X != 0 || oConfigMng.Config.StartPos.Y != 0)
{
Location = oConfigMng.Config.StartPos;
Size = oConfigMng.Config.StartSize;
}
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
// Save configuration
oConfigMng.Config.StartPos = Location;
oConfigMng.Config.StartSize = Size;
oConfigMng.SaveConfig();
}
そして生成されたXMLファイルも読むことができます:
<?xml version="1.0" encoding="utf-8"?>
<CConfigDO xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<StartPos>
<X>70</X>
<Y>278</Y>
</StartPos>
<StartSize>
<Width>253</Width>
<Height>229</Height>
</StartSize>
</CConfigDO>
私はweb.config
やapp.config
を使うという提案された解決策が好きではありません。あなた自身のXMLを読んでみてください。XML設定ファイル - これ以上web.configを見てください。
カスタムXMLファイルを使用する代わりに、JSONまたはYAMLファイルなど、よりユーザーフレンドリーなファイル形式を使用することもできます。
設定ファイルは、ここにリストされているように(すべてのユーザーに対して、そしてユーザーごとに)複数の特別なフォルダーに保存することができます。 Environment.SpecialFolder Enumeration および複数のファイル(デフォルトは読み取り専用、役割ごと、ユーザーごとなど)
複数の設定を使用することを選択した場合は、それらの設定をマージできます。たとえば、default + BasicUser + AdminUserの設定をマージします。あなたはあなた自身のルールを使うことができます:最後のものは値などを上書きします.
私が言うことができる限りでは、.NETは組み込みのアプリケーション設定機能を使用して永続的な設定をサポートしています。
Windowsフォームのアプリケーション設定機能を使用すると、クライアントコンピューターでカスタムアプリケーションとユーザー設定を簡単に作成、保存、および管理できます。 Windowsフォームのアプリケーション設定では、データベース接続文字列などのアプリケーションデータだけでなく、ユーザーアプリケーション設定などのユーザー固有のデータも保存できます。 Visual Studioまたはカスタムマネージコードを使用して、新しい設定を作成し、それらをディスクから読み書きしたり、フォームのプロパティにバインドしたり、ロードおよび保存する前に設定データを検証したりできます。 - http://msdn.Microsoft.com/ja-jp/library/k4s6c3a0.aspx
「これは、構成設定を保存するためにカスタムXMLファイルを使用する必要があることを意味しますか?」いいえ、必ずしもそうとは限りません。そのような操作にはSharpConfigを使います。
たとえば、設定ファイルがそのようなものであれば
[General]
# a comment
SomeString = Hello World!
SomeInteger = 10 # an inline comment
このような値を取得することができます
var config = Configuration.LoadFromFile("sample.cfg");
var section = config["General"];
string someString = section["SomeString"].StringValue;
int someInteger = section["SomeInteger"].IntValue;
.Net 2.0以上と互換性があります。設定ファイルをその場で作成し、後で保存することができます。出典: http://sharpconfig.net/ Github: https://github.com/cemdervis/SharpConfig
助けになれば幸いです。
時々あなたは伝統的なweb.configまたはapp.configファイルに保存されているそれらの設定を取り除きたいです。あなたはあなたの設定エントリの展開と分離されたデータデザインのよりきめ細かい制御が欲しいです。または、実行時に新しいエントリを追加できるようにすることが要件です。
私は2つの良い選択肢を想像することができます:
強く型付けされたバージョンの利点は、強く型付けされた設定の名前と値です。名前やデータ型が混在する危険性はありません。欠点は、より多くの設定をコーディングしなければならず、実行時に追加できないことです。
オブジェクト指向バージョンでは、新しい設定を実行時に追加できるという利点があります。しかし、あなたは強く型付けされた名前と値を持っていません。文字列識別子には注意が必要です。値を取得するときに、以前に保存したデータ型を知っている必要があります。
あなたは両方の完全に機能的な実装のコードを見つけることができます _ここ_ 。
public static class SettingsExtensions
{
public static bool TryGetValue<T>(this Settings settings, string key, out T value)
{
if (settings.Properties[key] != null)
{
value = (T) settings[key];
return true;
}
value = default(T);
return false;
}
public static bool ContainsKey(this Settings settings, string key)
{
return settings.Properties[key] != null;
}
public static void SetValue<T>(this Settings settings, string key, T value)
{
if (settings.Properties[key] == null)
{
var p = new SettingsProperty(key)
{
PropertyType = typeof(T),
Provider = settings.Providers["LocalFileSettingsProvider"],
SerializeAs = SettingsSerializeAs.Xml
};
p.Attributes.Add(typeof(UserScopedSettingAttribute), new UserScopedSettingAttribute());
var v = new SettingsPropertyValue(p);
settings.Properties.Add(p);
settings.Reload();
}
settings[key] = value;
settings.Save();
}
}