I am currently working on a MVC3 project with Razor.
I have switchen on compilation of Views to be aware of spelling errors etc. at compile-time.
As soon as I switch on the <MvcBuildViews>true</MvcBuildViews> in the projects configuration file a get the following error during compile:
Error 1 It is an error to use a section registered as allowDefinition='MachineToApplication' beyond application level. This error can be caused by a virtual directory not being configured as an application in IIS.
I read several possible solutions to the problem, mostly concerning IIS and virtual Directories or Applications.
The problem is, that I do not use IIS, but instead use the default Visual Studio Development Server.
What can I do to solve this problem?
I have tried a lot of different solutions available in the web, but either they did not quite fit onto my problem, or they did not work.
To recap my problem:
After switching CompileViews on, I immediately got the above error during compile.
I am using the default Visual Studio Development Server of VS2010 to test my MVC app.
Today I opened a request at Microsoft Developer support, and - I am almost ashamed to admit it - got my answer approximately 30 seconds into the callback from the technician:
All he said was: Please goto your obj folder and delete all contents. Then compile again.
And that really was all it took.
So after a lot of head-shaking about myself I wanted to share the results with you.
This problem occurs when there is web project output (templated web.config or temporary publish files) in the obj folder. The ASP.NET compiler used isn't smart enough to ignore stuff in the obj folder, so it throws errors instead.
Another fix is to nuke the publish output right before calling <AspNetCompiler>. Open your .csproj and change this:
<Target Name="MvcBuildViews" AfterTargets="AfterBuild" Condition="'$(MvcBuildViews)'=='true'">
<AspNetCompiler VirtualPath="temp" PhysicalPath="$(WebProjectOutputDir)" />
</Target>
to this:
<Target Name="MvcBuildViews" AfterTargets="AfterBuild" Condition="'$(MvcBuildViews)'=='true'">
<ItemGroup>
<ExtraWebConfigs Include="$(BaseIntermediateOutputPath)\**\web.config" />
<ExtraPackageTmp Include="$([System.IO.Directory]::GetDirectories("$(BaseIntermediateOutputPath)", "PackageTmp", System.IO.SearchOption.AllDirectories))" />
</ItemGroup>
<Delete Files="#(ExtraWebConfigs)" />
<RemoveDir Directories="#(ExtraPackageTmp)" />
<AspNetCompiler VirtualPath="temp" PhysicalPath="$(WebProjectOutputDir)" />
</Target>
That will delete all web.configs under \obj, as well as all PackageTmp folders under \obj.
Related
The scenario is this one:
We need to reduce the time of building a solution that contains several projects. We have the constraint that we cannot consolidate projects, thus we are having around 50 projects. The build time at this moment is around 3 minutes. A quick test by setting manually all project references property CopyLocal to False and changing the output directory to a central one improved the building performance by more than 50%. However, the problem is by doing so, when we deploy or run out test on CI, DLLs are missing (I suspect it builds by using the main project and not all projects of the solution).
I thought that I can have 2 sets of build directives. One when developing that will set CopyLocal to false and output into a single directory all DLL, and one when deploying in the CI and Azure website (which preserve the normal DLL location).
I have read in previous post and here that is it possible to the CopyLocal with MsBuild by using a target file (not sure yet about the output directory). Thus, I could have this one use the targets file on the local machine and not when deploying.
My question is how can I have Visual Studio's Build action to use a specific targets file when developing and not when deploying with the IDE to Azure or the CI environment?
You can use a itemgroup with a condition to optionally override the output directory. Or use it to remove the copy-local flag from your Reference items. The same trick works for ProjectReferences.
See:
https://stackoverflow.com/a/1684045/736079
Then make this group conditional using a number of flags:
IsDesktopBuild Is true for a build that's running outside of a build server
BuildingInsideVisualStudio Is true for a build that's running inside VS
See:
https://stackoverflow.com/a/20402204/736079
Putting it all together:
<Target Name="BeforeBuild" Condition="'$(IsDesktopBuild)' != 'true'">
<ItemGroup>
<ProjectReferenceNew Include="#(ProjectReference)">
<Private>False</Private>
</ProjectReferenceNew>
<ProjectReference Remove="#(ProjectReference)"/>
<ProjectReference Include="#(ProjectReferenceNew)"/>
</ItemGroup>
<ItemGroup>
<ReferenceNew Include="#(Reference)">
<Private>False</Private>
</ReferenceNew>
<Reference Remove="#(Reference)"/>
<Reference Include="#(ReferenceNew)"/>
</ItemGroup>
</Target>
To improve performance of this translation, you'll want to specify the Input and Output parameters of the Target:
<Target Name="BeforeBuild" Condition="'$(IsDesktopBuild)' != 'true'"
Inputs="#(Reference);#(ProjectReference)"
Outputs="#(Reference);#(ProjectReference)"
>
....
</Target>
I'm trying to write a code generation tool. For this tool it's important that the generated code is available prior to building (i.e., for IntelliSense). I know Visual Studio will at least partially evaluate the project build plan automatically to generate IntelliSense, but I can't find much information on the details.
As a simpler example, let's say I want to take all items with build action None and compile them. I have a project like this:
<Project [...]>
[...]
<Compile Include="Foo.cs" />
<None Include="Bar.cs" />
</Project>
One way to get Bar.cs to compile is to add the following to the project:
<PropertyGroup>
<CoreCompileDependsOn>
$(CoreCompileDependsOn);IndirectCompile
</CoreCompileDependsOn>
</PropertyGroup>
<Target Name="IndirectCompile">
<CreateItem Include="#(None)">
<Output ItemName="Compile" TaskParameter="Include" />
</CreateItem>
</Target>
If I do it this way, Visual Studio acts basically the same as if Bar.cs had the Compile action to begin with. IntelliSense is fully available; if I make a change in Bar.cs it's reflected immediately (well, as immediate as the background operation normally is) in IntelliSense when I'm editing Foo.cs, and so on.
However, say instead of directly compiling the None entry, I want to copy it to the obj directory and then compile it from there. I can do this by changing the IndirectCompile target to this:
<Target Name="IndirectCompile"
Inputs="#(None)"
Outputs="#(None->'$(IntermediateOutputPath)%(FileName).g.cs')"
>
<Copy SourceFiles="#(None)"
DestinationFiles="#(None->'$(IntermediateOutputPath)%(FileName).g.cs')"
>
<Output TaskParameter="DestinationFiles" ItemName="Compile" />
</Copy>
</Target>
Doing this causes IntelliSense to stop updating. The task works on build, dependency analysis and incremental building work, Visual Studio just stops automatically running it when an input file is saved.
So, that leads to the title question: How does Visual Studio choose to run targets or not for IntelliSense? The only official documentation I've found has been this, specifically the "Design-Time IntelliSense" section. I'm pretty sure my code meets all those criteria. What am I missing?
After a few days of experimenting and poking around in the debugger I think I have found the answer, and unfortunately that answer is that this is not possible (at least not in a clearly supported way -- I'm sure there are ways to trick the system).
When a project is loaded, and when the project itself changes (files added/removed, build actions changed, etc), the IntelliSense build is executed (csproj.dll!CLangCompiler::RunIntellisenseBuild). This build will run tasks up to and including the Csc task. Csc will not execute normally, but instead just feed its inputs back into its host (Visual Studio).
From this point on, Visual Studio keeps track of the files that were given as Sources to the Csc task. It will monitor those files for changes, and when they change, update IntelliSense. So in my example, if I manually edit Bar.g.cs those changes will be picked up. But the build tasks themselves will not be run again until the project changes or a build is explicitly requested.
So, that's disappointing, but not surprising, I guess. It also explains something else I had always wondered about -- XAML files with a code-behind tend to have a Custom Tool action of MSBuild:Compile, presumably for exactly this reason.
I'm going to mark this as the answer, but I'd love to be told I'm wrong and that I missed something.
I'm using vs 2010 and have a web application project.
I currently use the right-click "publish" option on my project using the "web deploy" option to publish the entire application to a server that is running msdeploy.axd.
I have to publish this project many times (100+), each time just changing the web.config.
I'm looking into what technology I should use to automate this process. I would prefer to use standard MS technology.
Should I be looking at MSBuild? The VS Command Prompt? (are these the same thing?)
What technology should I learn to best automate this scenario. I'm looking for the most standard way to do this...
In my head the script I'm going to write will:
change the web.config file
do the equivalent of right-click my project, click publish, use the web-deploy option, and deploy it to that server using the windows domain\username + password details i've saved in Visual Studio
Any help is appreciated.
I've done this exact thing just with MSBuild. The steps involved in my case were:
TFS performed a build using a custom MSBuild project, not a solution file. Any CI build system would work, nothing special about TFS in this instance.
In the custom build project, in addition to building all the projects, I copied a bunch of web.config "template" files to a special folder under the $(OutDir) folder. These would end up in the build drop from TFS. In my case, the built in configuration file transformations were nowhere close to being sophisticated enough, but if that can work for you it is simpler by far.
The web.config files actually contained references to other config files, one for each configurable feature. This used a custom configuration provider. This technique would also work if you just had a single web.config file though.
I enabled automated deployment (Publish) from the command line, as a new MSBuild target in the same custom MSBuild project that was driving the build.
It was then easy to automate the Publish step in the main build to a VM or QA machine, as well as make it possible to manually deploy to other servers (eventually the staging servers) from the command line.
The web.config templates had stuff like this:
In the connection string: "Data Source=${SQLINSTANCE};Initial Catalog=${SQLDATABASENAME}..."
It is significant that the delimiters for the replacable tokens is ${ } and not $( ), since MSBuild won't mess with the curly brackets.
In the Publish step, use an MSBuild property function to replace bits in the config files, the following is taken from MSDN's description of MSBuild inline tasks:
<UsingTask
TaskName="ReplaceToken"
TaskFactory="CodeTaskFactory"
AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
<ParameterGroup>
<File ParameterType="System.String" Required="true" />
<Token ParameterType="System.String" Required="true" />
<Replacement ParameterType="System.String" Required="true" />
</ParameterGroup>
<Task>
<Code Type="Fragment" Language="cs">
<![CDATA[
string content = File.ReadAllText(File);
content = content.Replace(Token, Replacement);
File.WriteAllText(File, content);
]]>
</Code>
</Task>
</UsingTask>
Then in your project, you can use this task with,
<ReplaceToken
File="PathTo\Web.config"
Token="${SQLINSTANCE}"
Replacement=".\SQLEXPRESS"
/>
This is really just a rough guide, all of the parameters to ReplaceToken were also configured in MSBuild item metadata, allowing options for which database, server, security, etc., each of which could be specified individually.
So, for each build/deployment, it would perform the build, copy the config templates, do string replacements on them, then automate the Package/Publish, which is the final bit to go over.
Your best bet is to start with this blog: http://vishaljoshi.blogspot.com/2009/02/web-packaging-creating-web-packages.html which explains a bit, and this answer, which contains likes to a bunch of other related StackOverflow posts MsBuild and MsDeploy with multiple environments, then search online with http://www.bing.com/search?q=msbuild+msdeploy+command+line&go=&form=QBLH&qs=n&sk= to dig deeper. I really hate to just dump you off to a search engine for this part of it, but I've found that there are so many different scenarios it is tough to single one out. About half of the top ten responses have insight on some valuable angle. Reply with more info to help narrow down my response at this point. For my implementation, I called MSDeploy.exe directly from MSBuild using an Exec task. Some things to consider:
How to deal with security on the various publish sites. I had to set up a mess of build service accounts, and always required passing the password on the msbuild command line. If you can get by with Windows auth like you suggest it will be a bit easier.
For services, I had to use PSExec to run installutil on the remote server
There were some additional configuration items that I automated using PSExec calling appcmd on the remote server.
It is easy to open up a remote share on the server and use a "net use" command to map and unmap it during the build, you may have some other preference.
Performance is tough. For larger sites it can run quite long doing it file by file. RoboCopy isn't any faster. I found using MSDeploy to package remotely (point to local drop as source, and remote share for the package source) was very fast to Rackspace. You may need to first package to a zip file using one MSDeploy call, then push the package remotely using a second.
Hope this gets you started. Please comment or supply more detail in your question if there is something I really missed or glossed over.
Response to comment:
The "Publish" target is something along these lines,
<Target Name="Publish">
<!-- token replacement in config files, as above -->
<!-- ...lots of custom setup, selection of various properties used below -->
<PropertyGroup>
<_MsDeployExe>$(PROGRAMFILES)\IIS\Microsoft Web Deploy\msdeploy</_MsDeployExe>
<_MsDeploySourceArg>-source:contentpath="$(_BuildDropFolder)"</_MsDeploySourceArg>
<_MsDeployDestArg>-dest:contentpath=\\$(_RemoteComputerName)\DropFolder</_MsDeployDestArg>
</PropertyGroup>
<Message
Text=""$(_MsDeployExe)" -verb:sync $(_MsDeploySourceArg) $(_MsDeployDestArg)"
/>
<Exec
Condition="'$(DryRun)' != 'true'"
Command=""$(_MsDeployExe)" -verb:sync $(_MsDeploySourceArg) $(_MsDeployDestArg)"
ContinueOnError="false"
WorkingDirectory="$(MSBuildThisFileDirectory)"
/>
</Target>
The Microsoft AJAX Minifier provides a build task which can be used in TFS or local build definitions.
I have succsfully used this in both a local project file (building to seperate files) and in TFS build definitions (overwriting the existing JS files).
I'd like to move to using Visual Studio 2010's 1-click publish feature rather than a TFS build definition, however adding the minification task as an AfterBuild target in the project file doesn't appear to effect the 1-click publish feature.
Using information found in this thread and these articles, I tried creating a file named '[ProjectName].wpp.targets in my WAP root directory, and used the following XML:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\Microsoft\MicrosoftAjax\ajaxmin.tasks" />
<Target Name="Minify" BeforeTargets="MSDeployPublish">
<ItemGroup>
<JS Include="**\*.js" Exclude="**\*.min.js;**\*vsddoc.js;**\*debug.js" />
</ItemGroup>
<ItemGroup>
<CSS Include="**\*.css" Exclude="**\*.min.css" />
</ItemGroup>
<AjaxMin JsSourceFiles="#(JS)" JsSourceExtensionPattern="\.js$" JsTargetExtension=".min.js" CssSourceFiles="#(CSS)" CssSourceExtensionPattern="\.css$" CssTargetExtension=".min.css" />
</Target>
</Project>
This doesn't appear to have any effect, and unfortunately Visual Studio doesn't give much in the way of feedback or debugging info for these tools.
Has anyone had any success minifying JavaScript / CSS using the Visual Studio 2010 1-click publish feature?
I just wrote a detailed blog entry on how to do this at
http://sedodream.com/2011/02/25/HowToCompressCSSJavaScriptBeforePublishpackage.aspx and http://blogs.msdn.com/b/webdevtools/archive/2011/02/24/how-to-compress-css-javascript-before-publish-package.aspx.
Here are the contents
Today I saw a post on stackoverflow.com asking Using Microsoft AJAX Minifier with Visual Studio 2010 1-click publish. This is a response to that question. The Web Publishing Pipeline is pretty extensive so it is easy for us to hook in to it in order to perform operation such as these. One of those extension points, as we’ve blogged about before, is creating a .wpp.targets file. If you create a file in the same directory of your project with the name {ProjectName}.wpp.targets then that file will automatically be imported and included in the build/publish process. This makes it easy to edit your build/publish process without always having to edit the project file itself. I will use this technique to demonstrate how to compress the CSS & JavaScript files a project contains before it is published/packaged.
Eventhough the question specifically states Microsoft AJAX Minifier I decided to use the compressor contained in Packer.NET (link in resources section). I did this because when I looked at the MSBuild task for the AJAX Minifier it didn’t look like I could control the output location of the compressed files. Instead it would simply write to the same folder with an extension like .min.cs or .min.js. In any case, when you publish/package your Web Application Project (WAP) the files are copied to a temporary location before the publish/package occurs. The default value for this location is obj{Configuration}\Package\PackageTmp\ where {Configuration} is the build configuration that you are currently using for your WAP. So what we need to do is to allow the WPP to copy all the files to that location and then after that we can compress the CSS and JavaScript that goes in that folder. The target which copies the files to that location is CopyAllFilesToSingleFolderForPackage. (To learn more about these targets take a look at the file %Program Files (x86)%\MSBuild\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.targets.) To make our target run after this target we can use the MSBuild AfterTargets attribute. The project that I created to demonstrate this is called CompressBeforePublish, because of that I create a new file named CompressBeforePublish.wpp.targets to contain my changes.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<UsingTask TaskName="SmallSharpTools.Packer.MSBuild.Packer"
AssemblyFile="$(MSBuildThisFileDirectory)..\Contrib\SmallSharpTools.Packer\SmallSharpTools.Packer.dll" />
<!-- This target will run after the files are copied to PackageTmp folder -->
<Target Name="CompressJsAndCss" AfterTargets="CopyAllFilesToSingleFolderForPackage">
<!-- Discover files to compress -->
<ItemGroup>
<_JavaScriptFiles Include="$(_PackageTempDir)\Scripts\**\*.js" />
<_CssFiles Include="$(_PackageTempDir)\Content\**\*.css" />
</ItemGroup>
<Message Text="Compressing JavaScript files" Importance="high" />
<!--
Compress the JavaScript files.
Not the usage of %(JavaScript.Identity which causes this task to run once per
.js file in the JavaScriptFiles item list.
For more info on batching: http://sedotech.com/resources#Batching
-->
<Packer InputFiles="%(_JavaScriptFiles.Identity)"
OutputFileName="#(_JavaScriptFiles->'$(_PackageTempDir)\Scripts\%(RecursiveDir)%(Filename)%(Extension)')"
Mode="JSMin"
Verbose="false"
Condition=" '#(_JavaScriptFiles)' != ''" />
<Message Text="Compressing CSS files" Importance="high" />
<Packer InputFiles="%(_CssFiles.Identity)"
OutputFileName="#(_CssFiles->'$(_PackageTempDir)\Content\%(RecursiveDir)%(Filename)%(Extension)')"
Mode="CSSMin"
Verbose="false"
Condition=" '#(_CssFiles)' != '' "/>
</Target>
</Project>
Here I’ve created one target, CompressJsAndCss, and I have included AfterTargets=”CopyAllFilesToSingleFolderForPackage” which causes it to be executed after CopyAllFilesToSingleFolderForPackage. Inside this target I do two things, gather the files which need to be compressed and then I compress them.
1. Gather files to be compressed
<ItemGroup>
<_JavaScriptFiles Include="$(_PackageTempDir)\Scripts\**\*.js" />
<_CssFiles Include="$(_PackageTempDir)\Content\**\*.css" />
</ItemGroup>
Here I use an item list for both JavaScript files as well as CSS files. Notice that I am using the _PackageTempDir property to pickup .js & .css files inside the temporary folder where the files are written to be packaged. The reason that I’m doing that instead of picking up source files is because my build may be outputting other .js & .css files and which are going to be published. Note: since the property _PackageTempDir starts with an underscore it is not guaranteed to behave (or even exist) in future versions.
2. Compress files
I use the Packer task to compress the .js and .css files. For both sets of files the usage is pretty similar so I will only look at the first usage.
<Packer InputFiles="%(_JavaScriptFiles.Identity)"
OutputFileName="#(_JavaScriptFiles->'$(_PackageTempDir)\Scripts\%(RecursiveDir)%(Filename)%(Extension)')"
Mode="JSMin"
Verbose="false"
Condition=" '#(_JavaScriptFiles)' != ''" />
Here the task is fed all the .js files for compression. Take a note how I passed the files into the task using, %(_JavaScriptFiles.Identity), in this case what that does is to cause this task to be executed once per .js file. The %(abc.def) syntax invokes batching, if you are not familiar with batching please see below. For the value of the output file I use the _PackageTempDir property again. In this case since the item already resides there I could have simplified that to be #(_JavaScriptFiles->’%(FullPath)’) but I thought you might find that expression helpful in the case that you are compressing files which do not already exist in the _PackageTempDir folder.
Now that we have added this target to the .wpp.targets file we can publish/package our web project and it the contained .js & .css files will be compressed. Note: Whenever you modify the .wpp.targets file you will have to unload/reload the web project so that the changes are picked up, Visual Studio caches your projects.
In the image below you can see the difference that compressing these files made.
You can download the entire project below, as well as take a look at some other resources that I have that you might be interested in.
Resources
http://sedotech.com/content/samples/CompressBeforePublish.zip
http://sedotech.com/resources#batching
MSBuild BeforeTargets/AfterTargets
WebDeploymentToolMSDeployHowToExcludeFilesFromPackageBasedOnConfiguration.aspx
Packer.NET
For this to work in visual studio 2015, we have to change the "AfterTarget" from
<Target Name="CompressJsAndCss" AfterTargets="CopyAllFilesToSingleFolderForPackage">
to the following
<Target Name="CompressJsAndCss" AfterTargets="PipelineCopyAllFilesToOneFolderForMsdeploy">
enjoy!!
I have some content files that I would like to share between a number of projects in Visual Studio.
I have put these files in their own project, set the build action to "Content", and the copy to output directory to "Copy if newer". I would like all these files to be copied to the bin/debug directory of the projects that reference them.
I can get it to work by including a reference to the "contents" project in each of the projects that need the files, but that requires that a minimal assembly be generated (3K). I assume there is a way, using MSBuild, to make this all work without creating the empty assembly?
Thanks to everone who took the time to make a suggestion about how to solve this problem.
It turns out that if I want my compiled content files to be treated like content files (in that they get copied to the output directory of any other project that references my project), I need to create a target which runs before GetCopyToOutputDirectoryItems, and add the full path of the compiled content files to the AllItemsFullPathWithTargetPath ItemGroup. MSBuild calls GetCopyToOutputDirectoryItems for projects on which the current project depends, and uses the resulting file list to determine the files that are copied along with the assembly.dll. Here is the XML from my .csproj, just in case someone else has a similar problem.
I have a custom task called "ZipDictionary", and I accumulate all the files that I am going to compile in an ItemGroup called DictionaryCompile. My target, "FixGetCopyToOutputDirectoryItems" is executed before "GetCopyToOutputDirectoryItems". I don't do the actual compilation there, since this target can be called multiple times by referencing projects, and it would hurt performance. The target does some transforms to get the post-compilation file names, and then returns the full paths to all the files, since relative paths will not work when copy is called from the referencing project.
<ItemGroup>
<DictionaryCompile Include="Dictionaries\it-IT.dic">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</DictionaryCompile>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<UsingTask TaskName="ZipDictionary" AssemblyFile="..\LogicTree.DictionaryCompiler\bin\Debug\LogicTree.DictionaryCompiler.dll"/>
<Target Name="BeforeCompile">
<Message Text="Files #(DictionaryCompile)" Importance="high" />
<ZipDictionary DictionaryFiles="#(DictionaryCompile)" OutputDirectory="$(OutputPath)">
<Output TaskParameter="OutputFiles" ItemName="DictionaryOutputFiles" />
</ZipDictionary>
</Target>
<Target Name="FixGetCopyToOutputDirectoryItems" BeforeTargets="GetCopyToOutputDirectoryItems">
<ItemGroup>
<_DictionaryCompile Include="#(DictionaryCompile->'$(OutputPath)Dictionaries\%(FileName).ltdic')" />
</ItemGroup>
<AssignTargetPath Files="#(_DictionaryCompile)" RootFolder="$(MSBuildProjectDirectory)\$(OutputPath)">
<Output TaskParameter="AssignedFiles" ItemName="_DictionaryCompileWithTargetPath" />
</AssignTargetPath>
<ItemGroup>
<AllItemsFullPathWithTargetPath Include="#(_DictionaryCompileWithTargetPath->'%(FullPath)')" Condition="'%(_DictionaryCompileWithTargetPath.CopyToOutputDirectory)'=='Always' or '%(_DictionaryCompileWithTargetPath.CopyToOutputDirectory)'=='PreserveNewest'" />
<_SourceItemsToCopyToOutputDirectoryAlways Include="#(_DictionaryCompileWithTargetPath->'%(FullPath)')" Condition="'%(_DictionaryCompileWithTargetPath.CopyToOutputDirectory)'=='Always'" />
<_SourceItemsToCopyToOutputDirectory Include="#(_DictionaryCompileWithTargetPath->'%(FullPath)')" Condition="'%(_DictionaryCompileWithTargetPath.CopyToOutputDirectory)'=='PreserveNewest'" />
</ItemGroup>
</Target>
A better possible solution would be to
place a common directory in the solution dir and place your common content files there.
in VS, in each project that should share this content, right-click add existing item, browse to the desired item(s), select, click the down-arrow on the add button and select add as link. In the project, you will notice the files are added with a 'shortcut' overlay.
In the project, select the newly added links and right-click->properties and select Build Action: content, Copy To Output Directory: Copy Always.
This is a simple solution to the problem given.
I use this technique for things like SQL scripts and partial config files (using configSource) with great success. This allows me to make changes to these files in a single location with the assurance that they will be propigated throughout the solution.
A more robust solution would be to create a project with embedded resources. This requires a bit more work to manage the content on the receiving end but may be worth it in the long run as having a bunch of loose artifacts flying about can become problematic.
Hope that helps.
A similar solution like the one Sky suggested can be found in my answer to "Is there a way to automatically include content files into asp.net project file?".
It allows to share your content but you must not touch the folder or its content inside VS because this breaks the recursive path.
This approach works best for auto-generated content - you don't have to bother about including new content files to your solution.
And of course you can reuse this in multiple solutions/projects.
We do something similar where we have "...ReleaseBuilds" that reference dlls and content we require for specific projects. Compiling copies everything to the bin debug folder and indeed creates the empty assembly.
Within Visual Studio we have a post-build event in the "...RealeaseBuild" (in project properties) that copies/deletes or run batch files to make sure we have all the files (configs, services etc etc) required and to delete the empty assembly.
HTH