如何确保对C#项目中的配置文件所做的更改会导致重新生成DLL?

如何确保对C#项目中的配置文件所做的更改会导致重新生成DLL?,c#,build,msbuild,visual-studio-2015,C#,Build,Msbuild,Visual Studio 2015,我在Visual Studio 2015中有一个C#DLL项目(a),其中有一个自定义配置文件,我希望将其复制到输出,因此“复制到输出目录”设置为“如果更新,则复制”。此DLL被同一解决方案中的另一个项目(B)引用。每当我重建项目B时,项目A中的配置文件都会复制到它的输出目录,正如我所希望的那样 问题是,如果我只修改配置文件,它不会被复制到输出中。我认为这是因为项目A的输出没有更改,所以MSBuild不需要将其复制到项目B的输出目录中 我发现的一个解决方法是将配置文件的内容类型设置为“Embed

我在Visual Studio 2015中有一个C#DLL项目(a),其中有一个自定义配置文件,我希望将其复制到输出,因此“复制到输出目录”设置为“如果更新,则复制”。此DLL被同一解决方案中的另一个项目(B)引用。每当我重建项目B时,项目A中的配置文件都会复制到它的输出目录,正如我所希望的那样

问题是,如果我只修改配置文件,它不会被复制到输出中。我认为这是因为项目A的输出没有更改,所以MSBuild不需要将其复制到项目B的输出目录中

我发现的一个解决方法是将配置文件的内容类型设置为“Embedded Resource”,这样每当配置文件发生更改时都会重新生成项目A。这是可行的,但有点麻烦。有没有更好的方法可以在不将配置文件包含在DLL中的情况下获得相同的行为?

而不是使用“更新时复制”您可以通过使用project B的project settings中的post-build event命令来实现这一点。只需设置一个xcopy命令,将web.config从project A目录复制到project B的build output文件夹中。有些生成参数有助于设置正确的目录,而不是硬编码所有目录名字

请看这篇文章:


通常在使用DLL时,您不会配置DLL,而是在项目中使用DLL

为了解释,我们假设您有一个DLL,可以在两个可执行项目中重用它。项目B引用项目A,项目C引用项目A。在本例中,项目A是DLL,项目B和项目C是可执行文件。让我们进一步假设项目A使用配置设置,但项目B和项目C的实际值都需要不同

在这种情况下,您要做的是在exe B和exe C的应用程序配置中指定dll所需的设置。还要注意,部署应用程序时,配置可能会再次不同

为了说明如何在应用程序配置中包含DLL的配置,我创建了以下内容。最重要的是如何在最终的app.config中使用名称空间

类库

namespace ClassLibrary1
{
    public class Class1
    {
        public string Message()
        {
            return Settings.Default.Message;
        }
    }
}
控制台应用程序

namespace ConsoleApplication3
{
    class Program
    {
        static void Main(string[] args)
        {

            Console.WriteLine(new Class1().Message());
            Console.WriteLine(Settings.Default.Message);

            Console.ReadKey();

        }
    }
}
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
        <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
            <section name="ConsoleApplication3.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
            <section name="ClassLibrary1.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
        </sectionGroup>
    </configSections>
    <applicationSettings>
        <ConsoleApplication3.Properties.Settings>
            <setting name="Message" serializeAs="String">
                <value>Hello from application</value>
            </setting>
        </ConsoleApplication3.Properties.Settings>
      <ClassLibrary1.Properties.Settings>
          <setting name="Message" serializeAs="String">
            <value>Hello from DLL</value>
          </setting>
        </ClassLibrary1.Properties.Settings>
    </applicationSettings>
</configuration>
控制台应用程序的配置

namespace ConsoleApplication3
{
    class Program
    {
        static void Main(string[] args)
        {

            Console.WriteLine(new Class1().Message());
            Console.WriteLine(Settings.Default.Message);

            Console.ReadKey();

        }
    }
}
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
        <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
            <section name="ConsoleApplication3.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
            <section name="ClassLibrary1.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
        </sectionGroup>
    </configSections>
    <applicationSettings>
        <ConsoleApplication3.Properties.Settings>
            <setting name="Message" serializeAs="String">
                <value>Hello from application</value>
            </setting>
        </ConsoleApplication3.Properties.Settings>
      <ClassLibrary1.Properties.Settings>
          <setting name="Message" serializeAs="String">
            <value>Hello from DLL</value>
          </setting>
        </ClassLibrary1.Properties.Settings>
    </applicationSettings>
</configuration>

你好,来自应用程序
你好,来自DLL
使用dll运行此应用程序将显示以下输出

Hello from DLL

Hello from application


我希望这会有所帮助。

如果您使用VS 2015,您也可以使用所谓的共享项目,当您引用共享项目时,共享项目中包含的源代码文件将被复制并同步到引用项目。通过这种方式,您可以将您的配置文件同步到其他引用项目,甚至在构建之前

好吧,我想我已经想出了一个办法。在Microsoft.CSharp.Core.targets中定义了一个
CustomAdditionalCompileInputs
项目组,
CoreComile
目标依赖于此。因此,我简单地添加了以下目标,以使CoreCompile依赖于所有具有构建操作的文件
None
Content

  <Target Name="EnsureRecompiledOnConfigFileChanges" BeforeTargets="BeforeBuild">
    <!-- Recompile the project if any items of type "None" or "Content" change in case some of them are config files for a DLL. -->
    <ItemGroup>
      <CustomAdditionalCompileInputs Include="@(None)" />
      <CustomAdditionalCompileInputs Include="@(Content)" />
    </ItemGroup>
  </Target>


有一个选项“始终复制”,请尝试一下好吗?我不想使用“始终复制”,因为这会导致项目B一直被重建。我只希望在实际发生变化时重建它。我不会使用嵌入式资源。您也可以包含一个包含常量的静态类。您将如何重新定义目标部署中包含的资源中的内容?我理解这一点,但拥有公共设置(在引用项目之间共享)对我也很有用。如果您真的想重用设置,我将创建一个生成后步骤,使用XSLT更改项目文件的配置。另外,请查看并阅读Chris的答案。他还很好地解释了为什么您通常不重用配置。但他也解释了如何做到:)这可能可行,但需要手动列出引用项目A的所有项目中的所有配置文件。我认为将配置文件作为嵌入式资源比这更“干净”。如果您使用的是新的项目系统(如果您使用的是SDK样式的项目,那么您使用的是新的项目系统)然后,您应该将自定义输入添加到
UpdateCheckInput
组,而不是
CustomAdditionalCompileInputs