4

I have a C# DLL project (A) in Visual Studio 2015 with a custom configuration file that I want to copy to the output, so "Copy to output directory" is set to "Copy if newer". This DLL is referenced by another project (B) in the same solution. Whenever I rebuild project B the config file from project A is copied to its output directory, as I want.

The problem is that if I modify only the config file it does not get copied to the output. I think this is because the output of project A has not changed, so MSBuild doesn't bother copying it to project B's output directory.

A workaround I found is to set the Content Type to "Embedded Resource" for the config file, which causes project A to be rebuilt whenever the config file changes. This works, but it's a bit of a hack. Is there a better way to get the same behaviour without actually including the config file inside the DLL?

EM0
  • 5,369
  • 7
  • 51
  • 85
  • There is an option "Copy always", could you please try? – tdat00 Nov 23 '15 at 11:37
  • I don't want to use "Copy always", because the causes project B to be rebuilt all the time. I only want it rebuilt if something has actually changed. – EM0 Nov 23 '15 at 11:39
  • I would not go with an embedded resource. you can just as well include a static class containing consts. How will you redefine what's in the included resource on a target deployment ? – Dbuggy Nov 23 '15 at 12:53

4 Answers4

5

OK, I think I've figured out a way. There is a CustomAdditionalCompileInputs item group defined in Microsoft.CSharp.Core.targets and the CoreCompile target depends on this. So I simply added the following target to make CoreCompile depend on all files with build actions None or 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>
EM0
  • 5,369
  • 7
  • 51
  • 85
  • 3
    If you're using the new project system (if you're using SDK-style projects, then you're using the new project system) then you should add your custom inputs to the `UpToDateCheckInput` group, not `CustomAdditionalCompileInputs`. – Drew Noakes Aug 02 '19 at 03:08
0

Instead of using "Copy if newer" you could accomplish this by using the post built event commands in project settings of project B. Simply setup an xcopy command that copies web.config from the project A directory into the build output folder of Project B. There's some build parameters that's helpful to set the correct directories instead of hard-coding all directories names.

Look at this stackoverflow post:

Copy file(s) from one project to another using post build event...VS2010

Community
  • 1
  • 1
Kaveh Hadjari
  • 217
  • 1
  • 10
  • This might work, but would require manually listing all config files in all projects that reference project A. I think having the config file as an embedded resource is "cleaner" than this. – EM0 Nov 23 '15 at 12:38
0

Normally when using a DLL you would configure not the DLL but in the project you use the DLL.

To explain lets assume you have a DLL which you reuse in two executable projects. Project B references project A, and project C references project A. project A is in this case the DLL and project B and project C are executables. Lets further assume that project A uses an config setting but that actual value needs to be different for both project B and project C.

What you do in this case is to specify the settings needed by the dll in the application configuration of exe B and exe C. Also note that when the application is deployed the configuration may be different again.

To show how to include the configuration of the DLL in the application configuration i created the following. Most important is how the namespaces are used in the final app.config.

class lib

namespace ClassLibrary1
{
    public class Class1
    {
        public string Message()
        {
            return Settings.Default.Message;
        }
    }
}

console app

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

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

            Console.ReadKey();

        }
    }
}

Configuration of Console App

<?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>

Running this application using the dll will show the following output

Hello from DLL

Hello from application

I hope this helps.

Dbuggy
  • 901
  • 8
  • 16
  • I understand that, but it is useful to me to have common settings as well (shared between referencing projects). – EM0 Nov 23 '15 at 12:37
  • If you really want to reuse settings i would create a post build step which changes the configuration of the project file using XSLT. – Dbuggy Nov 23 '15 at 12:46
  • Also take a look [here](http://stackoverflow.com/a/1009227/2107576) and read the answer from Chris. He gives also a good insight on why you normally don't reuse configuration. But he also explains how you could :) – Dbuggy Nov 23 '15 at 12:49
0

If you're using VS 2015 you could also use whats called a shared project, when you reference a shared project the source code files contained in the shared projects is copied and synced to the referencing projects. In this way you could sync your config file to the other referencing projects, and it happens even before build.

Kaveh Hadjari
  • 217
  • 1
  • 10