Search code examples
.netvisual-studionugetvisual-studio-2019packages.config

NuGet packages: Place dll and config files under a sub-directory


Found many outdated and/or relevant-but-not-enough solutions, hence i will give it a shot hoping that i am not asking a duplicate question.

Context

  • I use a plugin system which loads the plugin dlls located under the 'bin/Plugin' folder.
  • Each plugin comes with a config file (ie MyPlugin.dll + MyPlugin.config)
  • Each plugin is distributed using a private NuGet server.
  • There are no '.nuspec' files in my project. The '.nupkg' package is generated using '.csproj' and the 'nuspec' is auto-generated by the nuget pack command.
  • Both the NuGet project and the project that consumes the NuGet are using .NetFramework and packages.config (instead of packageReferences).

Goal

Since the plugins are distributed using NuGet, there are 2 points to be taken care of:

  1. When installing the NuGet package, instead of placing the dll to the 'bin' folder, it should be placed in the 'bin/Plugin' sub-folder.
  2. Include the '.config' in the NuGet package and place it under the same location.

Any suggestions on how to accomplish (1) and (2)?


Removed the previously added unsuccessful steps from the question and posted an answer


Solution

  • Found an almost fully automated solution to my problem (Special thanks to @Perry-Qian-MSFT for guidance in order to get this right).

    Here are the steps to achieve this from a newbie's perspective:

    Problem 1: How to include the files into '.nupkg'

    To include the 'MyPlugin.config' file to the '.nupkg', I've edited the '.csproj' file and added the following:

    <ItemGroup>
      <Content Include="MyPlugin.config">
        <Pack>true</Pack>
        <PackagePath>MyPlugin.config</PackagePath>
      </Content>
    </ItemGroup>
    

    This step will add the 'MyPlugin.config' file under the 'content' folder inside the nuget package. Note that the 'MyPlugin.config' file should be placed at the root level of the NuGet project.

    Problem 2: How copy the files to the project that consumes the nuget

    This is the step where manual editing is needed. Will try to automate this as well and update the answer.

    After the nuget is packed (and before pushing it to the NuGet server), open the 'nupkg' package (using winzip/winrar/7zip etc) and add the following to the '.nuspec' file:

    <metadata>
      <contentFiles>
        <files include="MyPlugin.config" copyToOutput="true" />
      </contentFiles>
    </metadata>
    <files>
      <file src="MyPlugin.config" target=""/>
    </files>
    

    The 'MyPlugin.dll' does not need to be added here, because it is a lib file.

    Save and push the package to the server. Now when the 'consumer' project installs the NuGet, the config file will be added in the project. The config file will NOT be added in the bin directory when building the project yet.

    Problem 3: How to copy the files to the consumer's bin folder, under the 'Plugins' sub-directory

    For this step a 'props' file was utilized. The props file is meant to be packed in the NuGet package, copied in the consumer's root directory and executed by the consumer project upon build.

    Add the 'Directory.build.props' file in the the NuGet's project and edit the 'csproj' to add the following:

      <Content Include="Directory.build.props">
        <Pack>true</Pack>
        <PackagePath>Directory.build.props</PackagePath>
      </Content>
    

    Edit the contents of the "Directory.build.props" file:

    <Project>
      <Target Name="CopyToFolder" AfterTargets="Build">
        <ItemGroup>
          <ConfigFile Include="$(MSBuildThisFileDirectory)MyPlugin.config"></ConfigFile>
        </ItemGroup>
        <ItemGroup>
          <DllFile Include="$(MSBuildThisFileDirectory)bin\MyPlugin.dll"></DllFile>
        </ItemGroup>
        <Copy SourceFiles="@(ConfigFile)" DestinationFolder="$(ProjectDir)bin\Plugins"></Copy>
        <Move SourceFiles="@(DllFile)" DestinationFolder="$(ProjectDir)bin\Plugins" Condition="Exists('%(FullPath)')"></Move>
      </Target>
    </Project>
    

    Add a "Directory.build.props" entry to the 'nuspec' file. Hence, step 2 will be enhanced to:

      <metadata>
        <contentFiles>
          <files include="MyPlugin.config" copyToOutput="true" />
        </contentFiles>
        <contentFiles>
          <files include="Directory.build.props" copyToOutput="true" />
        </contentFiles>
      </metadata>
      <files>
        <file src="MyPlugin.config" target="Plugins"/>
        <file src="Directory.build.props" target="Plugins"/>
      </files>
    

    Now, the props file will end-up in the root directory of the consumer project. By convention, "Directory.build.props" files are automatically executed when building the project (MSBuild). Using a 'Copy' and a 'Move' task, both the 'dll' and the 'config' are placed under the 'bin/Plugins' folder.

    Starting from square 0, i spent a lot of time to achieve this and hopefully it will help others as well :)