Settings.Default。<property>始终返回默认值而不是持久存储(XML文件)</property>中的值

时间:2008-10-10 18:53:46

标签: c# .net dll application-settings

我最近在C#(。Net 2.0)中编写了一个DLL,其中包含一个需要IP地址的类。我的同事改变了类以从“.dll.config”(XML)文件中检索IP - 这显然是由他创建的“应用程序设置”文件(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 reference to this problem on the MSDN forums用户说:

  

'旧'值(您在开发时定义的值)是硬编码的。如果franework无法访问或打开配置文件,它将使用默认值。如果您在dll中使用设置,则总会发生这种情况。

  1. 这是否意味着我无法在配置文件中存储DLL的外部值? (我的同事以某种方式完成了这项工作......)

  2. 由于我的框架似乎无法访问或打开配置文件,我该如何找出它失败的原因?甚至可以检测到这种情况何时发生?

  3. Decker :这有点帮助。不幸的是,我正在将此DLL写入规范,因此我实际上无法访问应用程序的配置文件。如上所述,我的同事创建了“设置 1 .settings”文件。我当时并不理解这一点,但现在似乎添加“1”会使其超出任何调用它的应用程序的设置空间。

    我想我想弄清楚的是为什么DLL似乎没有找到位于同一目录旁边的配置文件。通过代码逐步跟踪不会显示任何内容。

    顺便说一句,我可以将程序集的“输出类型”从“类库”更改为“Windows应用程序”,并在我的DLL代码的开头添加以下行:

        [STAThread]
        public static void Main(string[] args)
        {
            System.Windows.Forms.Application.Run(new form());
        }
    

    当我运行它时,它会生成一个不同的配置文件(“.exe.config”),并且我可以改变它并让它从文件中提取新数据。所以我有点困惑。有什么想法吗?

9 个答案:

答案 0 :(得分:7)

我一直都在使用这种技术。通常我有一个需要某些设置的库程序集,我需要通过测试项目以及主要的“可执行”程序集来设置它们 - 无论是Web项目还是Windows服务项目。

你说得对,在为任何项目创建设置文件时,它会添加一个应用程序配置文件。您为任何设置输入的值存储在两个位置 - 配置文件和设置基础结构创建的类中的属性。找不到配置文件时,将使用属性中嵌入的值。

以下是显示此类属性的代码段:

这是一个片段,显示生成的类中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>

您应该将这些部分复制到“true”配置文件中。

答案 1 :(得分:2)

我正在处理我正在进行原型设计的应用程序中的这个问题。虽然Decker建议将配置文件一起攻击,但我认为这是一个非常不方便的手动黑客,可以作为构建周期的一部分来执行。而不是我已经决定最干净的解决方案是让每个库解析自己的library.dll.config文件。它仍然不完美,它需要一些额外的样板代码,但它似乎是绕过拜占庭方式的唯一方法.Net处理这些app.config文件。

答案 2 :(得分:2)

我长期遇到同样的问题 - 这很烦人。

我喜欢创建自己的配置文件并让每个DLL解析它的想法,尽管它仍然可能很容易错过必须更改配置。

我过去做过的一件事至少要让它更容易一点,就是确保Setting1.Settings文件无效的任何配置值。

例如,我有一个使用LINQ-To-SQL与DB通信的类。因此它有一个Setting1.settings文件,它将连接字符串存储到数据库中。输入的默认值(将数据库表拖放到设计器中时)是dev数据库的连接字符串。

一旦我根据测试数据库创建了DBML文件,我就可以进入并编辑Settings文件并输入数据库名称,如“FAKE_DATABASE”。

这样,如果你在另一个项目中使用DLL,然后忘记合并配置文件以添加DLL的正确配置值,至少你会收到一个错误,上面写着“无法连接到FAKE_DATABASE” ”

当然,如果您必须再次使用设计器,则必须将值更改回dev数据库的值。

巨大的痛苦。他们必须以某种方式改变它。

答案 3 :(得分:1)

显然您的应用程序正在尝试从默认配置文件(可能是应用程序的配置文件)中读取。为了确保,将dll的配置文件中的键值对添加到应用程序的配置文件中,运行应用程序并查看此次是否读取它。

答案 4 :(得分:1)

我想我刚刚找到了为什么这对我的DLL和我的测试应用程序不起作用的解释。以下是some guy's blog的结论性例外:

  

对此的修复是要么确保您的应用程序和支持程序集具有相同的命名空间,要么确保合并AppName.exe.config和DllName.dll.config的内容(当您编译.dll时是的现在它生成了这个文件,但是如果你将它复制到应用程序目录并且没有自动合并它会被忽略)

所以要么我必须将DLL和Application保存在同一个命名空间中 - 或者 - 我必须将DLL配置文件的内容与应用程序的配置文件合并。

(这不是破坏了DLL的目的吗?我认为DLL应该是一个独立的库。)

也许这就是为什么它适用于我的同事。生产应用程序与DLL共享相同的命名空间。 (我的测试应用程序显然没有...)

更新:我最近和我的同事坐下来再次谈论这个问题,似乎它也没有为他工作,但他没有意识到这一点,因为他有将初始值设置为与我们尝试使用的设备相同。所以当然它最初似乎起作用,但是一旦我们在其他地方部署了稍微不同的设置它再次被打破。

答案 5 :(得分:0)

使用app.config时我遇到过类似的问题。尝试从.exe运行您的应用程序,而不是从Visual Studio&amp;看看它是否表现得像预期的那样。

答案 6 :(得分:0)

在您的DLL中,您可以将访问修饰符(对于Settings1.Settings)设置为Internal(Friend for VB)。尝试将Access MOdifier更改为Public,看看是否允许您的应用程序从dll配置读取/写入值。

答案 7 :(得分:0)

霍华德的答案涵盖了理论。

解决此问题的一种快速而简单的方法是手动解析xml配置文件。

bool checkTargetAlive = false; 

答案 8 :(得分:-1)

我认为你们所犯的错误就是你显然是通过Settings1.Default.IPAddress来引用DLL设置,而你只是假设这样做Settings1.IPAddress

不同之处在于,当您使用Settings1.Default.IPAddress时,值将从汇编文件(.dll或.exe)中嵌入的硬编码值中获取为Attribute [global :: System.Configuration.DefaultSettingValueAttribute(... )]。

虽然Settings1.IPAddress是文件.dll.config(XML文件)中可编辑的值**。因此,您对XML文件所做的任何更改都不会反映在程序集中的硬编码默认值中。

不是这个:

IP = IPAddress.Parse(Settings1.Default.IPAddress);

但试试这个:

*IP = IPAddress.Parse(Settings1.IPAddress);