C# Settings.Default.<property> 始终返回默认值而不是持久存储(XML 文件)中的值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/192641/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Settings.Default.<property> always returns default value instead of value in persistant storage (XML file)
提问by Pretzel
I recently wrote a DLL in C# (.Net 2.0) which contains a class that requires an IP address. A co-worker of mine altered the class to retrieve the IP from a ".dll.config" (XML) file -- This apparently is automatically generated by the "Application Settings" file he created (Settings1.settings). The benefit of this was to allow the end-user to change the IP address in the XML/config file at will.
我最近用 C# (.Net 2.0) 编写了一个 DLL,其中包含一个需要 IP 地址的类。我的一个同事更改了类以从“.dll.config”(XML) 文件中检索 IP——这显然是由他创建的“应用程序设置”文件 (Settings1.settings) 自动生成的。这样做的好处是允许最终用户随意更改 XML/配置文件中的 IP 地址。
Unfortunately, when I check his code out of the tree and try to compile (or use) this new code, any application calling this DLL only gets the default value, rather than the value from the file.
不幸的是,当我从树中检查他的代码并尝试编译(或使用)这个新代码时,任何调用这个 DLL 的应用程序只获得默认值,而不是文件中的值。
The constructor that calls the config file looks like this:
调用配置文件的构造函数如下所示:
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);
}
}
I found a reference to this problem on the MSDN forumswhere a user said:
我在 MSDN 论坛上找到了对这个问题的引用,其中一位用户说:
the 'old' values (the ones you define at development time) are hard coded. If the franework isn't able to access or open the config file it will use the defaults instead. This will always happen if you use settings in a dll.
“旧”值(您在开发时定义的值)是硬编码的。如果框架无法访问或打开配置文件,它将使用默认值。如果您使用 dll 中的设置,这将始终发生。
Does this mean that I cannot store an external value for a DLL in a config file? (My co-worker has somehow made this work...)
Since my framework appears to be unable to access or open the config file, how do I figure out why it's failing? Or even detect when this happens?
这是否意味着我无法在配置文件中存储 DLL 的外部值?(我的同事以某种方式完成了这项工作......)
由于我的框架似乎无法访问或打开配置文件,我如何找出它失败的原因?甚至检测何时发生?
Decker: That helps a bit. Unfortunately, I am writing this DLL to a specification, so I don't actually have access to the Application's config file. As you'll note above, my co-worker created a "Settings1.settings" file. I didn't understand this at the time, but it seems now that adding the "1" keeps it out of the settings space of any application that calls it.
德克尔:这有点帮助。不幸的是,我正在根据规范编写此 DLL,因此我实际上无权访问应用程序的配置文件。如上所述,我的同事创建了一个“设置1.settings”文件。我当时不明白这一点,但现在看来,添加“1”使其远离调用它的任何应用程序的设置空间。
I guess what I'm trying to figure out is why the DLL doesn't seem to find the config file sitting next to it in the same directory. Tracing thru the code step-by-step reveals nothing.
我想我想弄清楚的是为什么 DLL 似乎没有在同一目录中找到位于它旁边的配置文件。一步一步地跟踪代码并没有发现任何东西。
As an aside, I can change the "Output Type" of my assembly from "Class Library" to "Windows Application" and add the following lines at the beginning of my DLL code:
顺便说一句,我可以将我的程序集的“输出类型”从“类库”更改为“Windows 应用程序”,并在我的 DLL 代码的开头添加以下几行:
[STAThread]
public static void Main(string[] args)
{
System.Windows.Forms.Application.Run(new form());
}
When I run this, it generates a different config file (a ".exe.config") and that one I can alter and have it pull the new data from the file. So I'm a bit confused. Any ideas?
当我运行它时,它会生成一个不同的配置文件(“.exe.config”),我可以更改该文件并让它从文件中提取新数据。所以我有点困惑。有任何想法吗?
采纳答案by bouvard
I'm addressing this exact issue in an application I'm in the midst of prototyping. Although Decker's suggestion of hacking the config files together should work I think this is a pretty inconvenient manual hack to perform as part of a build cycle. Instead of that I've decided that the cleanest solution is to just have each library parse its own library.dll.config file. Its still not perfect and it requires some extra boiler-plate code, but it seems to be the only way to get around the byzantine way that .Net handles these app.config files.
我正在我正在进行原型设计的应用程序中解决这个确切的问题。尽管 Decker 建议将配置文件组合在一起应该可行,但我认为这是一个非常不方便的手动 hack,作为构建周期的一部分来执行。相反,我决定最干净的解决方案是让每个库解析自己的 library.dll.config 文件。它仍然不完美,它需要一些额外的样板代码,但它似乎是绕过 .Net 处理这些 app.config 文件的拜占庭方式的唯一方法。
回答by Serhat Ozgel
Apparently your application is trying to read from the default config file (which is probably the application's config file). To make sure, add the key-value pair in the dll's config file to the application's config file, run the application and see if it is read this time.
显然您的应用程序正在尝试从默认配置文件(这可能是应用程序的配置文件)中读取。为了确定,将dll的配置文件中的键值对添加到应用程序的配置文件中,运行应用程序并查看这次是否被读取。
回答by Serhat Ozgel
I've seen a similar problem when using app.config. Try running your application from the .exe instead of from Visual Studio & see if it then behaves as expected.
我在使用 app.config 时遇到过类似的问题。尝试从 .exe 而不是从 Visual Studio 运行您的应用程序,然后查看它是否按预期运行。
回答by Howard Pinsley
I use this technique all time time. Often I have a library assembly that requires certain settings, and I need them set both by testing projects as well as the primary "executable" assemblies -- be they web projects or Windows service projects.
我一直在使用这种技术。通常我有一个需要某些设置的库程序集,我需要通过测试项目以及主要的“可执行”程序集来设置它们——无论是 Web 项目还是 Windows 服务项目。
You're correct in that when you create a settings file for any project, it adds an application config file. The value you enter for any setting is stored in two places -- the config file AND in attributes on the classes created by the settings infrastructure. When a config file is not found, the values embedded in the attributes are used.
您是正确的,当您为任何项目创建设置文件时,它会添加一个应用程序配置文件。您为任何设置输入的值存储在两个位置——配置文件和设置基础结构创建的类的属性中。当未找到配置文件时,将使用嵌入在属性中的值。
Here is a snippet that shows such an attribute:
这是显示此类属性的片段:
Here is a snippet that shows the default value of the ConcordanceServicesEndpointName in the generated class:
这是一个片段,显示了生成的类中 ConcordanceServicesEndpointName 的默认值:
[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("InternalTCP")]
public string ConcordanceServicesEndpointName {
get {
return ((string)(this["ConcordanceServicesEndpointName"]));
}
}
What you want to do is copy the configuration section out of the app.config file from the library assembly project and merge it (carefully) into the applicable web.config or app.config for the main assembly. At runtime, that's the only config file that is used.
您想要做的是从库程序集项目的 app.config 文件中复制配置部分,并将其(小心地)合并到适用的 web.config 或 app.config 主程序集。在运行时,这是唯一使用的配置文件。
Here is an example:
下面是一个例子:
<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>
You should copy these sections into the "true" config file.
您应该将这些部分复制到“true”配置文件中。
回答by Pretzel
I think I just found an explanation of why this isn't working for my DLL and my test application. Here is the concluding exception from some guy's blog:
我想我刚刚找到了为什么这对我的 DLL 和我的测试应用程序不起作用的解释。这是某人博客的结论性例外:
The fix for this is to either make sure your application and the support assemblies have the same namespace or to make sure you merge the contents of AppName.exe.config and DllName.dll.config (yes when you compile a .dll now it generates this file, however it is ignored if you copy it to the application directory and is not automatically merged)
对此的修复是确保您的应用程序和支持程序集具有相同的命名空间,或者确保您合并 AppName.exe.config 和 DllName.dll.config 的内容(是的,当您编译 .dll 时,它现在生成此文件,但是如果您将其复制到应用程序目录并且不会自动合并,则会被忽略)
So either I have to keep the DLL and Application in the same namespace -or- I have to merge the contents of the DLL config file with the Application's config file.
因此,要么我必须将 DLL 和应用程序保留在同一个命名空间中 - 要么 - 我必须将 DLL 配置文件的内容与应用程序的配置文件合并。
(Doesn't this sort of defeat the purpose of the DLL? I thought a DLL was supposed to be an independent library.)
(这不是违背了 DLL 的目的吗?我认为 DLL 应该是一个独立的库。)
Perhaps this is why it works for my co-worker. The production application shares the same namespace as the DLL. (My test app clearly does not...)
也许这就是为什么它适用于我的同事。生产应用程序与 DLL 共享相同的命名空间。(我的测试应用程序显然没有......)
UPDATE:I just sat down with my co-worker recently and talked about this problem again and it seems that it was never working for him either, but he hadn't realized it because he had set the initial value to be the same as the device we were trying to use. So of course it appeared to work at first, but as soon as we deployed it elsewhere with slightly different settings it was broken again.
更新:我最近刚和我的同事坐下来再次谈论这个问题,似乎它也从来没有为他工作过,但他没有意识到这一点,因为他将初始值设置为与我们尝试使用的设备。所以当然一开始它似乎可以工作,但是一旦我们将它部署到其他地方,设置略有不同,它又被破坏了。
回答by Sam Schutte
I have had this same problem for a long time - it's annoying.
我有很长一段时间都遇到同样的问题 - 这很烦人。
I like the idea of making your own config file and having each DLL parse it, though it still might be easy to miss having to change the config.
我喜欢制作自己的配置文件并让每个 DLL 解析它的想法,尽管更改配置仍然很容易错过。
One thing I have done in the past to at least make this a little easier is to make sure that any config values that the Setting1.Settings file are invalid.
我过去做过的一件事是确保 Setting1.Settings 文件中的任何配置值都无效。
For instance, I have a class that uses LINQ-To-SQL to talk to the DB. So it has a Setting1.settings file that it stores the connection string to database in. The default value that is entered (upon dragging and dropping the database tables into the designer) is the connection string of the dev database.
例如,我有一个使用 LINQ-To-SQL 与数据库对话的类。所以它有一个 Setting1.settings 文件,它存储到数据库的连接字符串。输入的默认值(将数据库表拖放到设计器中时)是 dev 数据库的连接字符串。
Once I have the DBML file created based off of the test database, I can go in and edit the Settings file and type in a database name like "FAKE_DATABASE".
一旦我基于测试数据库创建了 DBML 文件,我就可以进入并编辑设置文件并输入数据库名称,如“FAKE_DATABASE”。
That way, if you use the DLL in another project, and then forget to merge the config files to add in the proper config value for the DLL, at least you'll get an error saying something like "Cannot connect to FAKE_DATABASE".
这样,如果您在另一个项目中使用 DLL,然后忘记合并配置文件以添加 DLL 的正确配置值,至少您会收到一条错误消息,说“无法连接到 FAKE_DATABASE”。
Of course, if you have to work with the designer again, you'll have to change the value back to the value of your dev database.
当然,如果您必须再次与设计器合作,则必须将值更改回开发数据库的值。
Huge pain. They've gotta change this somehow.
巨大的痛苦。他们必须以某种方式改变这一点。
回答by Sam Schutte
It is possible that in your DLL you have the access modifier (for the Settings1.Settings) set to Internal (Friend for VB). Try changing the Access MOdifier to Public and see if that lets your application read/write values from dll's config.
有可能在您的 DLL 中您将访问修饰符(对于 Settings1.Settings)设置为 Internal(对于 VB 为 Friend)。尝试将 Access MOdifier 更改为 Public,看看是否可以让您的应用程序从 dll 的配置中读取/写入值。
回答by MRHIMAN
The mistake I think you all make is that you apparently make referece to the DLL Settings via Settings1.Default.IPAddress
while you are simply suppossed to do this Settings1.IPAddress
.
我认为你们都犯的错误是你显然是通过Settings1.Default.IPAddress
引用DLL 设置,而你只是应该这样做Settings1.IPAddress
。
The difference is that when you use Settings1.Default.IPAddress
the values are gotten from the hardcoded values imbeded in the assembly file (.dll or .exe) as Attribute [global::System.Configuration.DefaultSettingValueAttribute(...)].
不同之处在于,当您使用Settings1.Default.IPAddress
这些值时,这些值是从作为属性 [global::System.Configuration.DefaultSettingValueAttribute(...)] 嵌入在程序集文件(.dll 或 .exe)中的硬编码值中获取的。
While Settings1.IPAddress
is the value that is editable in the file .dll.config
(XML file)**. so any changes you make to the XML file, it is not reflected in hardcoded default value in the assembly.
虽然Settings1.IPAddress
是文件.dll.config
(XML 文件)中可编辑的值**。因此,您对 XML 文件所做的任何更改都不会反映在程序集中的硬编码默认值中。
Not this:
不是这个:
IP = IPAddress.Parse(Settings1.Default.IPAddress);
But try this:
但是试试这个:
*IP = IPAddress.Parse(Settings1.IPAddress);
回答by kasper
The answer from Howard covers the theory.
霍华德的回答涵盖了这个理论。
One quick and dirty way of solving this is to parse the xml config file manually.
解决此问题的一种快速而肮脏的方法是手动解析 xml 配置文件。
string configFile = Assembly.GetExecutingAssembly().Location + ".config";
XDocument.Load(configFile).Root.Element("appSettings")....