我试图在VS 2008下用C ++编写的.NET应用程序中使字符串持久化(即,它是文件路径)。我只需要在应用程序启动时阅读它,并在离开时编写它即可。
我正在努力寻找适当的方法来做到这一点。 Web搜索将我定向到ConfigurationSettings和ConfigurationManager对象。似乎第一个是只读的,而第二个在配置参考(框架3.5)中找不到。
我知道我可以对注册表或外部文件执行显式的读/写操作,但是我希望使用更标准的方法。我不希望这需要两行以上的代码。
我在正确的轨道上吗?
答案 0 :(得分:3)
使用VS2008和.NET Framework 3.5,如果将应用程序安装在%ProgramFiles%或%ProgramFiles(x86)%的子文件夹中,则无法创建修改app.config所需的清单,因为它们受到特别保护。操作系统,并且您不能在没有提升权限的情况下写入注册表的HKLM节点。
我想我会编码默认值和一个布尔值,告诉应用程序是否以可移植模式运行到app.config。从app.config中读取默认值,用user.config中的值覆盖变量(如果存在),如果在可移植模式下将其值写入user.config,在非便携式模式下将值写入app.config。 / p>
在自定义类中,与框架提供的任何不良支持无关(没有对app.config的写访问权,没有混合模式)...
app.config:
<?xml版本=“ 1.0”编码=“ utf-8”?>
<启动>
我认为它比2行多了大约250行代码,但确实可以解决问题(抱歉,它在C#中,但是您可能知道如何使它适应C ++)。
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Xml.Linq;
namespace DesktopApp1 {
static class Program {
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main() {
Config myConfig = new Config();
myConfig.Load();
//Change settings during the livetime of the application
myConfig.SomethingPath = @"C:\Temp\Foo\TestUser.dat";
myConfig.PortableMode = false;
//Write it when closing the application
myConfig.Save();
}
}
internal class Config {
//Private Fields
private AppOrUserConfig _Config;
private Boolean _IsUserConfig;
private String _AppConfigPath;
private String _UserConfigPath;
public void Load() {
AppOrUserConfig myDefaultConfig = new AppOrUserConfig();
AppOrUserConfig myAppConfig = new AppOrUserConfig(AppConfigPath, myDefaultConfig);
if (myAppConfig.PortableMode) {
_Config = myAppConfig;
_IsUserConfig = false;
} else {
_Config = new AppOrUserConfig(UserConfigPath, myAppConfig);
_IsUserConfig = true;
}
}
public Boolean Save() {
CheckLoad();
String myFilePath = IsUserConfig ? UserConfigPath : AppConfigPath;
try {
String myContent = _Config.XmlContent;
String myFolder = Path.GetDirectoryName(myFilePath);
Directory.CreateDirectory(myFolder);
File.Delete(myFilePath);
File.WriteAllText(myFilePath, myContent, new UTF8Encoding(true));
return true;
} catch {
}
return false;
}
public Boolean PortableMode {
get {
CheckLoad();
return _Config.PortableMode;
}
set {
CheckLoad();
if (PortableMode == value) return;
if (value) {
_Config.PortableMode = true;
_IsUserConfig = false;
Save();
} else {
String myPath = SomethingPath;
_Config.PortableMode = false;
Save();
Load();
SomethingPath = myPath;
}
}
}
public String SomethingPath {
get {
CheckLoad();
return _Config.SomethingPath;
}
set {
CheckLoad();
_Config.SomethingPath = value;
}
}
private String AppConfigPath {
get {
String myResult = _AppConfigPath;
if (myResult == null) {
myResult = Assembly.GetEntryAssembly().EntryPoint.DeclaringType.Module.FullyQualifiedName + ".config";
_AppConfigPath = myResult;
}
return myResult;
}
}
private String UserConfigPath {
get {
String myResult = _UserConfigPath;
if (myResult == null) {
myResult = Path.Combine(Environment.ExpandEnvironmentVariables(@"%LOCALAPPDATA%\Cragin\FooApp"), Path.GetFileName(AppConfigPath));
_UserConfigPath = myResult;
}
return myResult;
}
}
private Boolean IsUserConfig {
get {
return _IsUserConfig;
}
}
private void CheckLoad() {
if (_Config == null) throw new InvalidOperationException(@"Call method ""Load()"" first.");
}
}
internal class AppOrUserConfig {
//Private Fields
private XDocument _Xml;
//Constructors
public AppOrUserConfig() {
_Xml = XDocument.Parse(@"<?xml version=""1.0"" encoding=""utf-8""?>
<configuration>
<startup>
<supportedRuntime version=""v2.0.50727""/>
</startup>
<appSettings>
<add key=""PortableMode"" value=""Off""/>
<add key=""SomethingPath"" value=""C:\ProgramData\Cragin\SomeLibrary""/>
</appSettings>
</configuration>");
}
public AppOrUserConfig(String filePath, AppOrUserConfig defaultValue) : this() {
XDocument myXml = null;
try {
myXml = XDocument.Parse(File.ReadAllText(filePath));
} catch {
return;
}
AppOrUserConfig myDummy = new AppOrUserConfig(myXml, defaultValue);
PortableMode = myDummy.PortableMode;
SomethingPath = myDummy.SomethingPath;
}
public AppOrUserConfig(XDocument xml, AppOrUserConfig defaultValue) : this() {
if (defaultValue == null) defaultValue = new AppOrUserConfig();
if (xml == null) {
PortableMode = defaultValue.PortableMode;
SomethingPath = defaultValue.SomethingPath;
return;
}
AppOrUserConfig myDummy = new AppOrUserConfig();
myDummy._Xml = xml;
PortableMode = myDummy.GetPortableMode(defaultValue.PortableMode);
SomethingPath = myDummy.GetSomethingPath(defaultValue.SomethingPath);
}
public Boolean PortableMode {
get {
return GetPortableMode(false);
}
set {
(from e in _Xml.Element("configuration").Element("appSettings").Elements("add") where (string)e.Attribute("key") == "PortableMode" select e).Last().Attribute("value").Value = value ? "on" : "off";
}
}
public String SomethingPath {
get {
return GetSomethingPath(@"C:\ProgramData\Cragin\SomeLibrary");
}
set {
(from e in _Xml.Element("configuration").Element("appSettings").Elements("add") where (string)e.Attribute("key") == "SomethingPath" select e).Last().Attribute("value").Value = value ?? "";
}
}
public String XmlContent {
get {
return _Xml.ToString(SaveOptions.None);
}
}
private Boolean GetPortableMode(Boolean defaultValue) {
try {
String myString = (from e in _Xml.Element("configuration").Element("appSettings").Elements("add") where (string)e.Attribute("key") == "PortableMode" select e).Last().Attribute("value").Value;
return ToBoolean(myString);
} catch {
PortableMode = defaultValue;
return defaultValue;
}
}
private String GetSomethingPath(String defaultValue) {
try {
return (from e in _Xml.Element("configuration").Element("appSettings").Elements("add") where (string)e.Attribute("key") == "SomethingPath" select e).Last().Attribute("value").Value;
} catch {
SomethingPath = defaultValue;
return defaultValue;
}
}
private static Boolean ToBoolean(String value) {
value = value.Trim();
switch (value.Length) {
case 1:
if (value[0] == '0') return false;
if (value[0] == '1') return true;
break;
case 5:
if (value.ToLowerInvariant() == "false") return false;
break;
case 4:
if (value.ToLowerInvariant() == "true") return true;
break;
case 3:
if (value.ToLowerInvariant() == "off") return false;
break;
case 2:
if (value.ToLowerInvariant() == "on") return true;
break;
}
throw new FormatException();
}
}
}
我希望它对您或其他人有用。
答案 1 :(得分:1)
我自己通过ConfigurationManager解决了这个问题,它受以下示例的启发:https://docs.microsoft.com/en-us/dotnet/api/system.configuration.appsettingssection?view=netframework-4.8
我的实现有效,但我不理解。
答案 2 :(得分:0)
似乎您可能想使用Isolated Storage:
对于桌面应用程序,隔离存储是一种数据存储机制,它通过定义将代码与保存的数据相关联的标准化方式来提供隔离和安全性。标准化还提供其他好处。管理员可以使用旨在操纵隔离存储的工具来配置文件存储空间,设置安全策略以及删除未使用的数据。使用隔离存储,您的代码不再需要唯一的路径来指定文件系统中的安全位置,并且可以保护数据免受仅具有隔离存储访问权限的其他应用程序的侵害。不需要硬编码信息即可指示应用程序存储区域的位置。
如上所述,您不必担心各种机器上的潜在差异,也不必担心可能会很脆弱的专有解决方案。
您的解决方案虽然可能有效,但似乎属于“专有”类别,可能不是最佳使用配置管理器。