36

I have a bunch of ancillary XML and XSLT files that I want to edit and manage in visual studio.

The files do not logically belong under any code project in my solution and so in order to group them neatly, I have created a "dummy" C# dll project in visual studio and disabled it from building in Debug / release builds).

I wondered if there was a nicer way of achieving the same result (i.e. having all the files visible in solution explorer). What I think really want is a visual studio project type of "content only" but such a thing does not exist (or have I not looked hard enough?).

I have toyed with the idea of adding the files as solution items but then they seem harder to manage because creating a new "solution item folder" does not actually create a folder on disk.

Any one have any ideas?

Chris Fewtrell
  • 7,555
  • 8
  • 45
  • 63

6 Answers6

33

Visual Studio 2015 has a project type called "Shared Project" which is essentially a content only project with no targets. It's listed under Visual C# but it can be used for any files.

enter image description here

stuckintheshuck
  • 2,449
  • 3
  • 27
  • 33
16

A work colleague has come up with a solution.

He has suggested hand editing the project to remove the DefaultTargets from the Project (and delete a load of now unused properties).

MSBuild complains if there are no targets in the project so he has added three empty targets.

The final project looks something like this

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="3.5" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProductVersion>9.0.30729</ProductVersion>
    <SchemaVersion>2.0</SchemaVersion>
    <ProjectGuid>{541463A7-7CFA-4F62-B839-6367178B16BD}</ProjectGuid>
  </PropertyGroup>
  <ItemGroup>
    ... files ...
  </ItemGroup>
  <ItemGroup>
    ... files ...
  </ItemGroup>
  <Target Name="Build"/>
  <Target Name="Rebuild"/>
  <Target Name="Clean"/>
</Project>

Admittedly, this solution requires more fiddling that I would have liked but seems to achieve what I was after: namely a project that does not aattempt to produce any build output.

Chris Fewtrell
  • 7,555
  • 8
  • 45
  • 63
10

Andy posted a link with a solution that's mostly worked for me; basically delete the following line from the project file:

<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

and add the following lines:

<Target Name="Build">
  <Copy
    SourceFiles="@(Content)"
    DestinationFiles="@(Content->'$(OutputPath)%(RelativeDir)%(Filename)%(Extension)')" />
</Target>
<Target Name="Clean">
  <Exec Command="rd /s /q $(OutputPath)" Condition="Exists($(OutputPath))" />
</Target>
<Target Name="Rebuild" DependsOnTargets="Clean;Build">
</Target>

I also found that disabling the project Debug property "Enable the Visual Studio hosting process" (for each configuration) prevented the MyProject.vshost.exe file from being generated.

As David I. McIntosh pointed out in a comment on this answer, if your project is part of a solution with multiple projects and any other projects use the same output path as the content-only project, the above Clean target will delete all of the files in the output path, i.e. the build output of other projects, and would thus only be correct if the content-only project is the first project built (among those sharing the same build output path). The following is a safer and friendlier Clean target for this scenario:

<Target Name="Clean">
  <Delete Files="@(Content->'$(OutputPath)%(RelativeDir)%(Filename)%(E‌​xtension)')"/>
</Target>
Community
  • 1
  • 1
Kenny Evitt
  • 9,291
  • 5
  • 65
  • 93
  • To make this work with TFS Build, do *not* remove the Import of Microsoft.CSharp.Targets, and replace the three instances of `$(OutputPath)` with `$(OutDir)`. It will still work locally as well. – JamesQMurphy Sep 14 '16 at 14:03
  • 2
    The "Clean" target above is dangerous. this is better: ` ` – David I. McIntosh Sep 23 '16 at 19:27
  • @DavidI.McIntosh What's dangerous about it? – Kenny Evitt Sep 23 '16 at 21:03
  • 1
    Because if you have a solution with multiple projects, all putting their output into the same output directory (e.g. a set of libraries you are deploying together), then the above "clean" command will delete _all_ the other targets you just built. This is a disaster. In fact, it completely eliminates the possibility of doing a "rebuild": in the build order, all the projects that get built before the "content" project have their targets .blown away – David I. McIntosh Sep 25 '16 at 01:57
  • 1
    Don't get me wrong: your solution was great.and deserving of an up-vote, exactly what we needed. Except the "clean" was a little too aggressive. – David I. McIntosh Sep 25 '16 at 01:59
  • 1
    @kenny evitt: Also, I just noticed your comment re: the vshost file issue. I will be trying that as well - another gem if it works. thanks. – David I. McIntosh Sep 25 '16 at 02:04
  • @DavidI.McIntosh Good to know! – Kenny Evitt Sep 25 '16 at 14:50
1

Then, try creating a Blank solution. Create Empty project. Have your files in respective folders with in the solution folder. From property window, use the Show all files, include those folders into the project. There is no better solution other then this. I hope.

Prince Ashitaka
  • 8,623
  • 12
  • 48
  • 71
  • Thanks for the reply - I was unaware of the blank project template but the end result is essentially the same as what I have now - i.e. an empty C# project that needs to be disabled from the build in order to prevent compiler warnings. – Chris Fewtrell Aug 23 '10 at 15:27
  • I'm afraid I don't know :(. Will keep watching this along with you :). But, if those warning are only from those xml or xslt files. You can try set the build action as Resource. Since, you are not building it in either of those modes. – Prince Ashitaka Aug 23 '10 at 16:10
1

This answer is just a convenient consolidation of the answers above given by Chris Fewtrell and Kenny Evitt, along with the slight modification in my comments above, and a bit more detail on what the declaration of the content items should/could look like:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <PropertyGroup>
        <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
        <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
        <ProjectGuid>{541463A7-7CFA-4F62-B839-6367178B16BD}</ProjectGuid>
    </PropertyGroup>
    <PropertyGroup Condition="'$(Configuration)|$(Platform)' == '64-bit|AnyCPU'">
        <PlatformTarget>x64</PlatformTarget>
        <OutputPath>..\builds\$(Configuration)\</OutputPath>
        <IntermediateOutputPath>..\builds\$(Configuration)\Intermediate\YourProjectName\</IntermediateOutputPath>
    </PropertyGroup>
    <ItemGroup>
        <Content Include="fileInProjectFolder.csv" />
        <Content Include="SubDir\fileInSubdir.txt" />
        <Content Include="..\actualSourceDirectoryOfFile\app.log.basic.config">
          <Link>targetSubdirInOutputDir\app.log.basic.config</Link>
        </Content>
        <Content Include="..\actualSourceDirectoryOfFile\yetAnotherFile.config">
          <Link>yetAnotherFile.config</Link>
        </Content>
        ... more files ...
    </ItemGroup>
    <Target Name="Build">
        <Copy
            SourceFiles="@(Content)"
            DestinationFiles="@(Content->'$(OutputPath)%(RelativeDir)%(Filename)%(Extension)')" />
    </Target>
    <Target Name="Clean">
        <Delete Files="@(Content->'$(OutputPath)%(RelativeDir)%(Filename)%(E‌​xtension)')"/>
    </Target>
    <Target Name="Rebuild" DependsOnTargets="Clean;Build">
    </Target>
</Project>

Note that this always copies all the "content" files to the output directory - the options "Copy If Newer", "Copy Always" and "Do Not Copy", as presented in the visual studio GUI ( appears as, for example, <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> in the .csproj file) are ignored.

David I. McIntosh
  • 2,038
  • 4
  • 23
  • 45
0

In my situation, I needed to have a set of configuration files that would be common to many projects. To simply achieve this, I performed the following steps:

  1. Create a Class Library project named "Configuration"
  2. Delete all *.cs files from Configuration project
  3. Put configuration files in a "Configuration" folder in the Configuration project
  4. Copy configuration files to required projects in the post-build event. In Configuration project's Properties > Build Events > Post-build event:
xcopy "$(TargetDir)Configuration\*" "$(SolutionDir)TARGET_PROJECT\$(OutDir)" /i /v /q /s /y

In the above, replace TARGET_PROJECT with your actual project

This will copy all the files in the Configurations folder to the output directory of the project that needs the configuration files (eg. MyProject/bin/Debug, etc).

datchung
  • 3,778
  • 1
  • 28
  • 29