TFS2008 recursively copying files not always works (compiling vs2003) (AfterCompile target) - tfs

I'm having some strange problems copying files in a custom script in TFS2008 without SP1, I have to run the build several times to get the files copied (most of the times its in the second build that i get the files), let me give you the details:
This is happening with ASP sites and VS2003 Web solutions, (vs2008 solutions are OK)
In ASP I have a dummy 2008 solution, the build compiles this dummy, I override AfterCompile and in there I copy all the files to the drop location
In VS 2003 i have also a dummy 2008 solution, the build first compiles the dummy, I override AfterCompile, use "Exec" and "Command" to compile the 2003 solution and then copy the files to the drop location.
As you can see both approaches are similar, I'm not having problems with the builds per se, my problem is reproducible in two ways (and yes, i do check out, update, check in and then test the build):
Create a new build, configure the script, run the build the first time, some DLL's in the bin folder are not copied, run the build for the second time and i get all the files.
Build already configured and running OK, add some file to the project (this mostly happens with the ASP sites), run the build, don't get this new file, run the build again and i get this new file.
Here is my build script for a VS2003 Web solution as an example
<PropertyGroup>
<TasksPath>D:\BuildTools\</TasksPath>
<VS2003Devenv>D:\Archivos de programa\Microsoft Visual Studio .NET 2003\Common7\IDE\devenv.com</VS2003Devenv>
<VS2003VirtualFolder>CnbvPifWeb</VS2003VirtualFolder>
<VS2003Suba>Cnbv.Pif.Web</VS2003Suba>
<VS2003Project>Cnbv.Pif.Web</VS2003Project>
<VS2003WebSiteName>Sitio Web predeterminado</VS2003WebSiteName>
<VS2003Configuration>Release</VS2003Configuration>
<VS2003Branch>Desarrollo</VS2003Branch>
<VS2003RelativePath>$(SolutionRoot)\$(VS2003Branch)\$(VS2003Suba)\</VS2003RelativePath>
<VS2003SolutionPath>$(VS2003RelativePath)Cnbv.Pif.Web.sln</VS2003SolutionPath>
<VS2003LocalFolder>$(VS2003RelativePath)Sources\$(VS2003Project)\</VS2003LocalFolder>
<VS2003Output>$(BinariesRoot)\$(VS2003Project)\</VS2003Output>
<VS2003CachePath>C:\Documents and Settings\srvfoundation\VSWebCache\230-2555-CPU015\</VS2003CachePath>
<VS2003ProjectExtension>vbproj</VS2003ProjectExtension>
<VS2003CacheFile>$(VS2003CachePath)$(VS2003VirtualFolder)\_vti_pvt\$(VS2003Project).$(VS2003ProjectExtension).cache</VS2003CacheFile>
</PropertyGroup>
<Import Project="$(TasksPath)Microsoft.Sdc.Common.tasks"/>
<UsingTask TaskName="Microsoft.Sdc.Tasks.Web.WebSite.CreateVirtualDirectory" AssemblyFile="Microsoft.Sdc.Tasks.dll" />
<UsingTask TaskName="Microsoft.Sdc.Tasks.Web.WebSite.DeleteVirtualDirectory" AssemblyFile="Microsoft.Sdc.Tasks.dll" />
<ItemGroup>
<!--list of ouput files, excluding .DLL outside bin and some other files-->
<VS2003OutputFiles
Include="$(VS2003LocalFolder)**\*.*"
Exclude="$(VS2003LocalFolder)**\*.vb;$(VS2003LocalFolder)**\*.cs;$(VS2003LocalFolder)**\*.resx;$(VS2003LocalFolder)**\*.vspscc;$(VS2003LocalFolder)**\*.csproj;$(VS2003LocalFolder)**\*.vbproj;$(VS2003LocalFolder)**\*.scc;$(VS2003LocalFolder)**\*.webinfo;$(VS2003LocalFolder)**\*.snk;$(VS2003LocalFolder)**\*.dll;$(VS2003LocalFolder)**\*.exe;" />
<!-- copy dll to bin folder -->
<VS2003OutputBinFiles
Include="$(VS2003LocalFolder)bin\*.dll"/>
</ItemGroup>
<Target Name="AfterCompile">
<Message Text="Deleting cache file" />
<Microsoft.Build.Tasks.Delete
Condition="Exists('$(VS2003CacheFile)')"
Files="$(VS2003CacheFile)" />
<Message Text="Creating virtual folder $(VS2003VirtualFolder) in IIS in local path $(VS2003LocalFolder)" />
<Web.WebSite.CreateVirtualDirectory
VirtualDirectoryName="$(VS2003VirtualFolder)"
Path="$(VS2003LocalFolder)"
WebSiteName="$(VS2003WebSiteName)" />
<Message Text="Compiling $(VS2003Project) in $(VS2003Branch)" />
<Exec
Command=""$(VS2003Devenv)" "$(VS2003SolutionPath)" /build $(VS2003Configuration) /out "$(VS2003LocalFolder)$(VS2003Project).log" "/>
<Message Text="Eliminando la carpeta virtual $(VS2003VirtualFolder) en IIS" />
<Web.WebSite.DeleteVirtualDirectory
WebSiteName="$(VS2003WebSiteName)"
VirtualDirectoryName="$(VS2003VirtualFolder)" />
<MakeDir Condition="!Exists('$(VS2003Output)')" Directories="$(VS2003Output)" />
<Message Text="Copying output files #(VS2003OutputFiles)" />
<Copy
SourceFiles="#(VS2003OutputFiles)"
DestinationFiles="#(VS2003OutputFiles->'$(VS2003Output)%(RecursiveDir)%(Filename)%(Extension)')"
/>
<MakeDir Condition="!Exists('$(VS2003Output)bin\')" Directories="$(VS2003Output)bin\" />
<Message Text="Copying DLL to bin folder #(VS2003OutputBinFiles)" />
<Copy
SourceFiles="#(VS2003OutputBinFiles)"
DestinationFiles="#(VS2003OutputBinFiles->'$(VS2003Output)bin\%(Filename)%(Extension)')"
/>
<OnError ExecuteTargets="VS2003Fail" />
</Target>
<Target Name="VS2003Fail">
<Message Text="Copying log file $(VS2003RelativePath)$(VS2003Project).log" />
<Copy Condition="Exists('$(VS2003RelativePath)$(VS2003Project).log')" SourceFiles="$(VS2003RelativePath)$(VS2003Project).log" DestinationFolder="$(DropLocation)\$(BuildNumber)" />
<CallTarget ContinueOnError ="true" Targets ="CreateWorkItemWhenPartialSucceed" />
</Target>
<Target
Name="CreateWorkItemWhenPartialSucceed"
Condition=" '$(SkipWorkItemCreation)'!='true' and '$(IsDesktopBuild)'!='true' ">
<Message Text="ejecutando work" />
<PropertyGroup>
<WorkItemTitle>$(WorkItemTitle) $(BuildNumber)</WorkItemTitle>
<BuildLogText>$(BuildlogText) <ahref='file:///$(DropLocation)\$(BuildNumber)\BuildLog.txt'>$(DropLocation)\$(BuildNumber)\BuildLog.txt</a >.</BuildLogText>
<ErrorWarningLogText Condition="!Exists('$(MSBuildProjectDirectory)\ErrorsWarningsLog.txt')"></ErrorWarningLogText>
<ErrorWarningLogText Condition="Exists('$(MSBuildProjectDirectory)\ErrorsWarningsLog.txt')">$(ErrorWarningLogText) <a href='file:///$(DropLocation)\$(BuildNumber)\ErrorsWarningsLog.txt'>$(DropLocation)\$(BuildNumber)\ErrorsWarningsLog.txt</a >.</ErrorWarningLogText>
<WorkItemDescription>$(DescriptionText) %3CBR%2F%3E $(BuildlogText) %3CBR%2F%3E $(ErrorWarningLogText)</WorkItemDescription>
</PropertyGroup>
<CreateNewWorkItem
TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
BuildUri="$(BuildUri)"
BuildNumber="$(BuildNumber)"
Description="$(WorkItemDescription)"
TeamProject="$(TeamProject)"
Title="$(WorkItemTitle)"
WorkItemFieldValues="$(WorkItemFieldValues)"
WorkItemType="$(WorkItemType)"
ContinueOnError="true" />
</Target>
When I see the ouput of this message in the log
<Message Text="Copying DLL to bin folder #(VS2003OutputBinFiles)" />
the first time i see just the name of one file, the second time it prints all the correct files, and the same happens with the ASP sites, if I add a file i see the file in the output in the second build.
I hope you can help me out figuring this out, thanks a lot.
Juan Zamudio

this was the answer in the tfs forum by OsirisJakob
The problem is that you define your item groups at the root level. This means that they are evaluated immediately when the project file loaded. What you want is for them to be evaluated when the AfterCompile target is executed.
Since you are running TFS 2008, you can solve this problem by moving the item groups into the AfterCompile target (a.k.a. Dynamic item groups). This will cause the item group to be evaluated by the time the AfterCompile target is executed, and will give you the correct result.

Related

TFS Continuous Integration and Deployment

I have an web project Project A and a library Project B.
Project B is being built into Project A\Plugins.
The Problem is when Project A is being built via CI Project B isn't deployed with Project A. MSBuild params in CI are:
/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:PackageLocation="$(build.artifactstagingdirectory)\\" /t:ProjectA
I added the following piece of code into Project A.csproj to deploy Project B with A:
<ItemGroup>
<ProjectsToBuild Include="..\..\Plugins\**\*ProjectB*proj" />
</ItemGroup>
<Target Name="Plugin" AfterTargets="Build">
<Message Text="Building Plugins" Importance="High" />
<MSBuild Projects="#(ProjectsToBuild)" ContinueOnError="false" Properties="Configuration=$(Configuration)">
<Output ItemName="OutputFiles" TaskParameter="TargetOutputs" />
</MSBuild>
<CallTarget Targets="CopyPlugins"/>
</Target>
<PropertyGroup>
<PluginDirectory>Plugins</PluginDirectory>
</PropertyGroup>
<Target Name="CopyPlugins">
<Message Text="Copying plugins to $(_PackageTempDir)\Plugins\ ($(ProjectDir)$(PluginDirectory))" Importance="high" />
<CreateItem Include="$(ProjectDir)$(PluginDirectory)\**\*.*">
<Output TaskParameter="Include" ItemName="PluginFiles" />
</CreateItem>
<Copy DestinationFolder="$(_PackageTempDir)\Plugins\" SourceFiles="#(PluginFiles)" SkipUnchangedFiles="true" />
</Target>
In the log executing order seems fine (Copy after Build), but after being deployed the Plugin folder doesn't exist on the target server.
Am I missing anything?
The files need to be included in the project. Since the files are generated dynamically, you can add this code to project file (e.g. XX.csproj)
<Content Include="plugin\**\*.*" />
From your description, you would need to check in Project A\Plugins folder into TFS. But it's not suggested.
We suggest you make a project reference in the same solution or create NuGet for package management. It's recommended to build a nuget package for Project B, and publish this Nuget package, then restore the library to Project A when you build it.

Multiple Delphi versions using Jenkins: library paths

We are looking at migrating our build machine from FinalBuilder to Jenkins to fit in with the rest of our extended company.
One issue that I have noticed is that whereas Finalbuilder is able to extract the current library path from your current Delphi installs on the build machine, Jenkins relies on the information contained within the .dproj files.
Owing to known problems of the paths within the .dproj files being very specific to a users machine, we don't currently commit them to our repository, relying on Delphi to re-create them as required. This obviously doesn't play nice when the build machine is reliant on a full MSBUILD script being there in the first place.
We use a fair few third-party components (DevExpress suite alone having over 100 units), so including and maintaining all the .pas files with full paths in the .dpr isn't really an option for this.
Does anyone have a tried-and-tested solution for this?
My thoughts on options were:
setting the %PATH% for each build - adding the current Delphi library
for the relevant version (will this run into %PATH% length restrictions?)
Using a command-line parameter to pass the correct library path to MSBUILD (is this possible?)
Including the search path somehow in the source files with compiler directives (is this possible?)
Using a pre-compile step to create new .dproj files (something like http://delphi-divining.blogspot.co.uk/2012/10/dprojmaker-tool-to-create-delphi.html but it'll need to be command-line)
Edit: 5th idea:
Could we use dproj.local files for each project, stored in a separate repository (or in a separate path) and copied to the build machine pre-build? This would allow build machine paths to be stored safely away from clutzy commits.
You need to submit your .dproj file to source control.
You have a problem which is that your configuration is not complete. Any build system should be able to build your project using nothing but files in your source control, that is the ONLY way to ensure you are building the correct binary.
You have a number of options to make this work
You can use Environment variables in the Delphi IDE eg %ROOTFOLDER% could be set to C:\Development\MyDelphiProjects on one machine and C:\Dev on another and as long as everything is the same from that route it should be ok. Each dev and your build machine can set the required path. You may need vars for bpl paths also.
Enforce identical structures on client machines. Really how difficult is it to make all devs us C:\Development\Delphi as their root?
Make sure all search paths are relative. This can work, but there are always exceptions that cause problems so I have never managed to get this to work.
We used option 1 in a previous company and it worked very successfully, its a bit of a pain to set up but once setup you can be sure your build is correct.
I had the same problem when i choose Jenkins as a "build" environment. The solution is to use a MSBuild script with a build task inside. So in Jenkins instead of building the project directly, just build this script which gives you a lot more options, including the option to specify the paths for the project (you can to override the default IDE paths).
I'll post such a script tomorrow.
So in Jenkins when you configure MSBuild you have to specify the msbuild file, which will be Build.xml. For command line arguments i use only /v - verbosity and /t - target name.
The build script looks like this:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<Target Name="Compile" DependsOnTargets="CompileApp" />
<PropertyGroup>
<ExeOutputName>App.exe</ExeOutputName>
<ExeOutputPath>x:\exe</ExeOutputPath>
<DcuOutputPath>x:\dcu</DcuOutputPath>
<ForConfig>Release</ForConfig>
<ForPlatform>Win32</ForPlatform>
</PropertyGroup>
<Target Name="ResolveOutputPath">
<MakeDir Directories="$(ExeOutputPath)" />
<MakeDir Directories="$(DcuOutputPath)" />
<Delete Files="$(ExeOutputPath)\$(ExeOutputName)" />
<Delete Files="$(DcuOutputPath)\*.*" />
</Target>
<ItemGroup>
<AppUnitSearchPathItem Include="$(BDS)\lib\$(ForPlatform)\$(ForConfig)" />
<AppUnitSearchPathItem Include="C:\Users\builder\Documents\tmssoftware\TMS Component Pack" />
<AppUnitSearchPathItem Include="C:\Program Files (x86)\RemObjects Software\RemObjects SDK for Delphi\Dcu\$(ForPlatform)" />
<AppUnitSearchPathItem Include="C:\Program Files (x86)\RemObjects Software\RemObjects SDK for Delphi\Source" />
<AppUnitSearchPathItem Include="C:\Program Files (x86)\RemObjects Software\RemObjects SDK for Delphi\Source\CodeGen" />
<AppUnitSearchPathItem Include="C:\Program Files (x86)\RemObjects Software\RemObjects SDK for Delphi\Source\DataSnap" />
<AppUnitSearchPathItem Include="C:\Program Files (x86)\RemObjects Software\RemObjects SDK for Delphi\Source\ZLib" />
<AppUnitSearchPathItem Include="C:\Program Files (x86)\RemObjects Software\RemObjects SDK for Delphi\Source\Synapse" />
<AppUnitSearchPathItem Include="C:\Program Files (x86)\Embarcadero\RAD Studio\12.0\Components\EhLib\Lib\$(ForPlatform)\$(ForConfig)" />
...
</ItemGroup>
<ItemGroup>
<AppDefinesItem Include="App" />
<!-- AppDefinesItem Include="CompilerDirective" -->
</ItemGroup>
<ItemGroup>
<AppPropertiesItem Include="DCC_ExeOutput=$(ExeOutputPath)" />
<AppPropertiesItem Include="DCC_DcuOutput=$(DcuOutputPath)" />
<AppPropertiesItem Include="DCC_BuildAllUnits=true" />
<AppPropertiesItem Include="DCC_Optimize=true" />
<AppPropertiesItem Include="DCC_DebugInformation=0" />
<AppPropertiesItem Include="DCC_PentiumSafeDivide=true" />
<AppPropertiesItem Include="DCC_RangeChecking=true" />
<AppPropertiesItem Include="DCC_IntegerOverflowCheck=true" />
<AppPropertiesItem Include="DCC_WriteableConstants=true" />
<AppPropertiesItem Include="DCC_IOChecking=true" />
<AppPropertiesItem Include="DCC_AssertionsAtRuntime=false" />
<AppPropertiesItem Include="DCC_Warnings=true" />
<AppPropertiesItem Include="DCC_MapFile=3" />
<AppPropertiesItem Include="DCC_ConsoleTarget=false" />
</ItemGroup>
<Target Name="CompileApp" DependsOnTargets="ResolveOutputPath">
<PropertyGroup>
<AppUnitSearchPath>#(AppUnitSearchPathItem)</AppUnitSearchPath>
<AppDefines>#(AppDefinesItem)</AppDefines>
</PropertyGroup>
<ItemGroup>
<AppProperties Include="Config=$(ForConfig)" />
<AppProperties Include="Platform=$(ForPlatform)" />
<!-- AppProperties Include="LibraryPath=$(AppUnitSearchPath)" -->
<AppProperties Include="DelphiLibraryPath=$(AppUnitSearchPath)" />
<AppProperties Include="UnitSearchPath=$(AppUnitSearchPath)" />
<AppProperties Include="ResourcePath=$(AppUnitSearchPath)" />
<AppProperties Include="IncludePath=$(AppUnitSearchPath)" />
<AppProperties Include="ObjPath=$(AppUnitSearchPath)" />
<AppProperties Include="DCC_Define=$(AppDefines)" />
<AppProperties Include="#(AppPropertiesItem)" />
</ItemGroup>
<MSBuild Projects="App.dproj" Properties="#(AppProperties)" />
</Target>
</Project>
What is missing here is the versioning part which can be done from this script using a resource template...

Can I use views in folders linked from other projects?

I have several MVC projects in one solution.
Following this accepted answer: "Add as Link" for folders in Visual Studio projects, I am attempting to reuse .cshtml views across these proejcts by placing reusable views in a base project. So far, I have set up location formats in the "consuming" projects for the view-engine like this:
var locationFormats = new string[]
{
"~/Views/{1}/{0}.cshtml",
"~/Views/Shared/{0}.cshtml",
"~/Views/Common/{1}/{0}.cshtml",
"~/Views/Common/Shared/{0}.cshtml"
};
I have set up a recursive, linked directory in consuming projects' .csproj files to include common views like this:
<ItemGroup>
<Content Include="..\..\..\common.cms\CommonViews\**\*.*">
<Link>\Views\Common\%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
...and all the views are appearing in the consuming projects with the linked-file/cshtml(#) icon, so the paths are correct. For example, the following file is very clearly present in my test consuming project:
\Views\Common\Home\Index.cshtml
But when I run the project, I'm getting:
The view 'Index' or its master was not found or no view engine supports the searched locations. The following locations were searched:
~/Views/Home/Index.cshtml
~/Views/Shared/Index.cshtml
~/Views/Common/Home/Index.cshtml
~/Views/Common/Shared/Index.cshtml
Question
So I am wondering: is it even possible to link views in this way? What is missing, or what could be inhibiting this from working?
More generally, what about any non-compiled files I'd like to share? Is this technique never going to work?
I've found that this as a known bug in visual studio: Linked files in Web Application projects are not deployed properly. This goes back to VS-2008 but still affects VS-2010 and 2012 (not sure about 2013).
A workaround is detailed in this blog-post:
Using Linked Files with Web Application Projects.
If you just want the fix wihtout the explanation, you just need to paste the code below at the end of the .csproj file for your project (just before the closeing </project> tag). This will fix the problem for any linked, un-compiled files:
<!--
============================================================
_CopyWebApplication
MODIFIED: Ignores linked files as part of normal deployment logic.
This target will copy the build outputs along with the
content files into a _PublishedWebsites folder.
This Task is only necessary when $(OutDir) has been redirected
to a folder other than ~\bin such as is the case with Team Build.
============================================================
-->
<Target Name="_CopyWebApplication" Condition="'$(OutDir)' != '$(OutputPath)'">
<!-- Log tasks -->
<Message Text="Copying Web Application Project Files for $(MSBuildProjectName)" />
<!-- Create the _PublishedWebsites\app\bin folder -->
<MakeDir Directories="$(WebProjectOutputDir)\bin" />
<!-- Copy build outputs to _PublishedWebsites\app\bin folder -->
<Copy SourceFiles="#(IntermediateAssembly)"
DestinationFolder="$(WebProjectOutputDir)\bin"
SkipUnchangedFiles="true" />
<Copy SourceFiles="#(AddModules)"
DestinationFolder="$(WebProjectOutputDir)\bin"
SkipUnchangedFiles="true" />
<Copy SourceFiles="$(IntermediateOutputPath)$(_SGenDllName)"
DestinationFolder="$(WebProjectOutputDir)\%(Content.SubFolder)%(Content.RecursiveDir)"
SkipUnchangedFiles="true"
Condition="'$(_SGenDllCreated)'=='true'" />
<Copy SourceFiles="$(IntermediateOutputPath)$(TargetName).pdb"
DestinationFolder="$(WebProjectOutputDir)\bin"
SkipUnchangedFiles="true"
Condition="'$(_DebugSymbolsProduced)'=='true'" />
<Copy SourceFiles="#(DocFileItem)"
DestinationFolder="$(WebProjectOutputDir)\bin"
SkipUnchangedFiles="true"
Condition="'$(_DocumentationFileProduced)'=='true'" />
<Copy SourceFiles="#(IntermediateSatelliteAssembliesWithTargetPath)"
DestinationFiles="#(IntermediateSatelliteAssembliesWithTargetPath->'$(WebProjectOutputDir)\bin\%(Culture)\$(TargetName).resources.dll')"
SkipUnchangedFiles="true" />
<Copy SourceFiles="#(ReferenceComWrappersToCopyLocal); #(ResolvedIsolatedComModules); #(_DeploymentLooseManifestFile); #(NativeReferenceFile)"
DestinationFolder="$(WebProjectOutputDir)\bin"
SkipUnchangedFiles="true" />
<!-- copy any referenced assemblies to _PublishedWebsites\app\bin folder -->
<Copy SourceFiles="#(ReferenceCopyLocalPaths)"
DestinationFolder="$(WebProjectOutputDir)\bin"
SkipUnchangedFiles="true" />
<!-- MODIFICATION HERE: Copy local content files (i.e. non-linked files) recursively to _PublishedWebsites\app\ folder -->
<Copy Condition=" '%(Content.Link)' == '' "
SourceFiles="%(Content.Identity)"
DestinationFolder="$(WebProjectOutputDir)\%(Content.RelativeDir)" />
</Target>
<!--
============================================================
CopyLinkedContentFiles
A new target to copy any linked content files into the
web application output folder.
NOTE: This is necessary even when '$(OutDir)' has not been redirected.
============================================================
-->
<Target Name="CopyLinkedContentFiles">
<!-- Remove any old copies of the files -->
<Delete Condition=" '%(Content.Link)' != '' AND Exists('$(WebProjectOutputDir)\%(Content.Link)') "
Files="$(WebProjectOutputDir)\%(Content.Link)" />
<!-- Copy linked content files recursively to the project folder -->
<Copy Condition=" '%(Content.Link)' != '' "
SourceFiles="%(Content.Identity)"
DestinationFiles="$(WebProjectOutputDir)\%(Content.Link)" />
</Target>
<!-- Override the default target dependencies to -->
<!-- include the new _CopyLinkedContentFiles target. -->
<PropertyGroup>
<PrepareForRunDependsOn>
$(PrepareForRunDependsOn);
_CopyWebApplication;
CopyLinkedContentFiles;
_BuiltWebOutputGroupOutput
</PrepareForRunDependsOn>
</PropertyGroup>

allowDefinition='MachineToApplication' error setting <MvcBuildViews>true</MvcBuildViews>

In my Asp.Net MVC 4 project, I've set in the .csproj file to build the view <MvcBuildViews>true</MvcBuildViews>. The problem is that building the project I got the error:
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 tried to delete the obj folder but the error keep raising. The error specify that the problem is in the authentication tag row:
<system.web>
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="2880" />
</authentication>
Often, I'm able to run the application by running the application (I got the error), building the app and after that running again.
Doing what #matrixugly suggests will fix the issue, but will also cause the compile-time view checking to stop working as well. I am assuming you still want to error check your views at compile time? If that is the case, better fixes below.
In order to understand why these solutions work, we have to first know how the problem is created:
The developer wants compile-time checking on views, so they set MvcBuildViews=true.
The application builds fine, UNTIL they publish the project.
Subsequent attempts to build the project result in a compile-time error: 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.
So what causes this issue? When the project is published the compiler, by default it uses <project-dir>\obj\ to place copies of the source files that it will work with. Unfortunately, these files are not automatically deleted when publishing is complete. The next time the developer compiles the project with MvcBuildViews=true, it will error out because the aspnet compiler includes the obj\ folder during compilation, since it is underneath the <project-dir> folder.
So how do we fix this? Well, you have four options:
Set MvcBuildViews=false. I don't really consider this a solution, so let's move on.
Delete the files in <project-dir>\obj\. Works, but can be a hassle since it has to be done after every publish.
Change the path that publishing uses as an intermediate directory through the use of the <BaseIntermediateOutputPath> property in your project config file.Example (Ref: this link):
<BaseIntermediateOutputPath>
[SomeKnownLocationIHaveAccessTo]
</BaseIntermediateOutputPath>
Add a new section in your project config file that deletes the offending files for you on build (reference Microsoft Connect). I've even made it easy for you, just copy and paste:
<PropertyGroup>
<_EnableCleanOnBuildForMvcViews Condition=" '$(_EnableCleanOnBuildForMvcViews)'=='' ">true</_EnableCleanOnBuildForMvcViews>
</PropertyGroup>
<Target Name="CleanupForBuildMvcViews" Condition=" '$(_EnableCleanOnBuildForMvcViews)'=='true' and '$(MVCBuildViews)'=='true' " BeforeTargets="MvcBuildViews">
<ItemGroup>
<_TempWebConfigToDelete Include="$(BaseIntermediateOutputPath)**\Package\**\*" />
<_TempWebConfigToDelete Include="$(BaseIntermediateOutputPath)**\TransformWebConfig\**\*" />
<_TempWebConfigToDelete Include="$(BaseIntermediateOutputPath)**\CSAutoParameterize\**\*" />
<_TempWebConfigToDelete Include="$(BaseIntermediateOutputPath)**\TempPE\**\*" />
</ItemGroup>
<Delete Files="#(_TempWebConfigToDelete)"/>
</Target>
My recommendation would be to use either option 3 or 4.
N.B. For those that have never edited their project file, you can't edit it while loaded. It must first be unloaded by right clicking it and selecting Unload Project. You can then right-click the project and edit the project file. Alternatively, you can edit the file outside of Visual Studio.
I had the exact same problem when trying to publish my web application after enabling MvcBuildViews to validate my Razor syntax
I found this code in my web config
<Target Name="MvcBuildViews" AfterTargets="AfterBuild" Condition="'$(MvcBuildViews)'=='true'">
<AspNetCompiler VirtualPath="temp" PhysicalPath="$(WebProjectOutputDir)" />
</Target>
Try commenting it out, so that the compiler behavior is not changed
<!--<Target Name="MvcBuildViews" AfterTargets="AfterBuild" Condition="'$(MvcBuildViews)'=='true'">
<AspNetCompiler VirtualPath="temp" PhysicalPath="$(WebProjectOutputDir)" />
</Target>-->
#newmanth answer is excellent, but outdated. Year 2022 and let me tell you - this CleanupForBuildMvcViews is actually oficially included within C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Microsoft\VisualStudio\v16.0\Web\Microsoft.Web.Publishing.targets! :)
It even features the link to (now broken) Microsoft Connect as #newmanth references.
Here is the snippet:
<!--Deal with http://connect.microsoft.com/VisualStudio/feedback/details/779737/error-allowdefinition-machinetoapplication-beyond-application-level,
we will need to clean up our temp folder before MVC project starts the pre-compile-->
<PropertyGroup>
<_EnableCleanOnBuildForMvcViews Condition=" '$(_EnableCleanOnBuildForMvcViews)'=='' ">true</_EnableCleanOnBuildForMvcViews>
</PropertyGroup>
<Target Name="CleanupForBuildMvcViews" Condition=" '$(_EnableCleanOnBuildForMvcViews)'=='true' and '$(MVCBuildViews)'=='true' " BeforeTargets="MvcBuildViews">
<ItemGroup>
<_PublishTempFolderNamesToCleanup Include="Database;TransformWebConfig;CSAutoParameterize;InsertAdditionalCS;ProfileTransformWebConfig;Package" />
</ItemGroup>
<!--Force msbuild to expand all the wildcard characters so to get real file paths-->
<CreateItem Include="#(_PublishTempFolderNamesToCleanup->'$(BaseIntermediateOutputPath)**\%(identity)\**\*')">
<Output TaskParameter="Include" ItemName="_EvaluatedPublishTempFolderNamesToCleanup" />
</CreateItem>
<Delete Files="#(_EvaluatedPublishTempFolderNamesToCleanup)" />
</Target>
However I still get the said exception. In my Case I had to delete AspnetCompileMerge folder too. And name Target in another name, not to overwrite it:
<PropertyGroup>
<_EnableCleanOnBuildForMvcViews Condition=" '$(_EnableCleanOnBuildForMvcViews)'=='' ">true</_EnableCleanOnBuildForMvcViews>
</PropertyGroup>
<Target Name="CleanupForBuildMvcViews2" Condition=" '$(_EnableCleanOnBuildForMvcViews)'=='true' and '$(MVCBuildViews)'=='true' " BeforeTargets="MvcBuildViews">
<ItemGroup>
<_TempWebConfigToDelete Include="$(BaseIntermediateOutputPath)**\AspnetCompileMerge\**\*" />
</ItemGroup>
<Delete Files="#(_TempWebConfigToDelete)"/>
</Target>

MSBuild & TFS2010 Find Dlls

I am trying to create a custom MSBuild task that will run my nUnit tests either locally or during a TFS2010 build. The script works great locally but I can't seem to find the test dlls on the TFS build server. I'm using a task in the MSBuild.ExtensionPack to run the unit tests (again this works fine locally).
The Assemblies list is always empty. TargetDir shows the path is "C:\Builds\2\Product1\ci.product1.acme.com\Binaries\" which looks right to me. I also tried to kick off my target after the CoreCompile target instead within the AfterBuild target with no change.
I've probably made some stupid mistake but I'm in kill me mode at this point. Please help.
<PropertyGroup>
<RunTFSBuild>false</RunTFSBuild>
<SolutionDirectory>$(MSBuildProjectDirectory)\..</SolutionDirectory>
<ExtensionTasksPath>$(SolutionDirectory)\_shared\MSBuild\</ExtensionTasksPath>
<TPath>$(ExtensionTasksPath)MSBuild.ExtensionPack.tasks</TPath>
<NUnitOutputFile>$(SolutionDirectory)\nUnitResults.xml</NUnitOutputFile>
<NUnitOutputFileAsMsTest>$(SolutionDirectory)\nUnitResultsAsMsTestResults.xml</NUnitOutputFileAsMsTest>
<ToolPath>$(SolutionDirectory)\_shared\MSBuild\nUnit_2.5.7</ToolPath>
</PropertyGroup>
<Import Project="$(TPath)" />
<Target Name="AfterBuild">
<CallTarget Condition="$(RunTFSBuild)!='true'" Targets="NUnitTestRunner" />
<CallTarget Condition="$(RunTFSBuild)=='true'" Targets="NUnitTestRunner;TFSNUnitTestRunner" />
</Target>
<Target Name="NUnitTestRunner">
<ItemGroup >
<Assemblies Include="$(SolutionDirectory)\**\bin\$(Configuration)\*.nUnit.Tests.dll" />
</ItemGroup>
<ItemGroup Condition="$(RunTFSBuild)=='true'">
<Assemblies Include="$(TargetDir)\**\*.nUnit.Tests.dll" />
</ItemGroup>
<Message Text="SolutionDirectory=$(SolutionDirectory)" />
<Message Text="ExtensionTasksPath=$(ExtensionTasksPath)" />
<Message Text="TargetDir=$(TargetDir)" />
<Message Text="TPath=$(TPath)" />
<Message Text="NUnitOutputFile=$(NUnitOutputFile)" />
<Message Text="Running nUnit tests from: $(Assemblies)" />
1) Try to change property RunTFSBuild
<RunTFSBuild Condition="'$(RunTFSBuild)'==''">false</RunTFSBuild>
2) Replace sections (it may be just cleaning of project, but it may be very important due to some limitations of CallTarget):
<Target Name="AfterBuild" DependsOnTargets="NUnitTestRunner;TFSNUnitTestRunner" />
<Target Name="TFSNUnitTestRunner"
Condition="$(RunTFSBuild)=='true'">
<!-- TFSNUnitTestRunner Body -->
</Target>
3) If 1) and 2) willn't be helpful try to set verbose of the build to diagnostic (msbuld key /v:diag). Find all calls of TFSNUnitTestRunner in the log and you will see what is actually happened on TFS.
EDIT: *Assemblies* is declared as ItemGroup. Use #(Assemblies) to access items:
<Message Text="Running nUnit tests from: #(Assemblies)" />
Property $(Assemblies) will always be empty in your case.

Resources