Search code examples
c#visual-studionugetvisual-studio-2019csproj

Visual Studio Debug vs Release builds: Local and nuget resources


I've recently created a number of public repositories on github for various C# libraries and projects I've developed. Today I ran into an issue involving how such projects consume other libraries I've written. I came up with a tentative solution but would appreciate feedback on best practices, other approaches, etc.

By way of explanation assume I have two projects in two different solutions. One is a general-purpose library I've written and the other is an executable which consumes that library to do something. Typically I use the following disk structure to encompass this:

C:\Programming
+ -> GPLibrary
     + -> GPLibrary
          + -> GPLibrary.csproj
          + -> ...other files
+ -> ConsumingApp
     + -> ConsumingApp
          +-> ConsumingApp.csproj
          + -> ...other files

Within the ConsumingApp solution I create a solution folder called 'externals' which contains a reference to GPLibrary.

I do this because I often find I need to tweak GPLibrary to expand its functionality and I don't want to go through the trouble of publishing lots of minor updates to nuget or a local repository. I use source control to put GPLibrary onto a development branch to accumulate these minor changes and, when there are enough of them, I merge the development branch back into the main branch and create/publish updated nuget packages.

This works fine...provided you have set up your solutions and projects the way I have. If you haven't, and you clone one of my public repositories you won't be able to build it unless and until you duplicate my disk structure and solution folder approach. This isn't convenient for other developers.

The solution I came up with was to modify my csproj files to pull my libraries locally when using a Debug configuration and from nuget when using a Release configuration. An example:

<Choose>
    <When Condition=" '$(Configuration)'=='Debug' ">
        <ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
            <ProjectReference Include="..\..\EFCoreUtilities\EFCoreUtilities\EFCoreUtilities.csproj" />
            <ProjectReference Include="..\..\J4JLogging\AutoFacJ4JLogging\AutofacJ4JLogging.csproj" />
            <ProjectReference Include="..\..\J4JLogging\ConsoleChannel\ConsoleChannel.csproj" />
            <ProjectReference Include="..\..\J4JLogging\FileChannel\FileChannel.csproj" />
            <ProjectReference Include="..\..\J4JLogging\J4JLogging\J4JLogging.csproj" />
        </ItemGroup>
    </When>
    <When Condition=" '$(Configuration)'=='Release'">
        <ItemGroup>
            <PackageReference Include="J4JSoftware.EFCore.Utilities" Version="0.5.0" />
            <PackageReference Include="J4JSoftware.Logging" Version="2.5.1" />
            <PackageReference Include="J4JSoftware.Logging.Console" Version="2.5.1" />
            <PackageReference Include="J4JSoftware.Logging.File" Version="2.5.1" />
            <PackageReference Include="J4JSoftware.Logging.Autofac" Version="2.5.1" />
        </ItemGroup>
    </When>
</Choose>

Other developers would still need to duplicate my approach to build Debug versions of ConsumingApp but they ought to be able to build Release versions just fine.

Is there a better/simpler way to do this? Should I perhaps create my own special-purpose configuration ("DebugJ4J") so that both the "normal" debug and release configurations can take advantage of nuget but I can still use my approach locally?

BTW, I tried simply having multiple ItemGroup sections, each with a Condition clause but that didn't seem to work. Not sure why. But the Choose approach does.


Solution

  • Is there a better/simpler way to do this? Should I perhaps create my own special-purpose configuration ("DebugJ4J") so that both the "normal" debug and release configurations can take advantage of nuget but I can still use my approach locally?

    Actually, your idea is the better choice. To create a new configuration DebugJ4J of your own so that you can do any other operation or use your own path of the local files on your local machine.

    So when other community members use your sample, they can also use Debug or Release Configuration without

    To create a new Configuration called DebugJ4J

    Build-->Configuration Manager-->New Project Configuration-->

    enter image description here

    Then add these:

    When Condition=" '$(Configuration)'=='DebugJ4J'">
           <ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
                <ProjectReference Include="..\..\EFCoreUtilities\EFCoreUtilities\EFCoreUtilities.csproj" />
                <ProjectReference Include="..\..\J4JLogging\AutoFacJ4JLogging\AutofacJ4JLogging.csproj" />
                <ProjectReference Include="..\..\J4JLogging\ConsoleChannel\ConsoleChannel.csproj" />
                <ProjectReference Include="..\..\J4JLogging\FileChannel\FileChannel.csproj" />
                <ProjectReference Include="..\..\J4JLogging\J4JLogging\J4JLogging.csproj" />
            </ItemGroup>
    //add any local project reference of your own here.
    ............................
    .............................
        </When>
    <When Condition=" '$(Configuration)'=='Release'">
            <ItemGroup>
                <PackageReference Include="J4JSoftware.EFCore.Utilities" Version="0.5.0" />
                <PackageReference Include="J4JSoftware.Logging" Version="2.5.1" />
                <PackageReference Include="J4JSoftware.Logging.Console" Version="2.5.1" />
                <PackageReference Include="J4JSoftware.Logging.File" Version="2.5.1" />
                <PackageReference Include="J4JSoftware.Logging.Autofac" Version="2.5.1" />
            </ItemGroup>
        </When>
    .........
    
    // Debug configuration
    

    In this function, you can use these nuget packages in both of Debug and Release Configuration and then add your new functions on the DebugJ4J Configuration.

    Note that you should add condition on the itemgroup and then include all the xml nodes in that itemgroup. Like this:

    <ItemGroup Condition="xxxxx">
    
    ..................
    
    // all files under this condition
    
    </ItemGroup>