using msdeploy.exe to deploy folder to remote site - msdeploy

I am trying to find the right parameters for msdeploy.
I have a folder with my web content that I want to deploy.
"C:\Program Files (x86)\IIS\Microsoft Web Deploy V3"\msdeploy.exe -verb:sync -source:contentPath="c:\work\WebPackage" -dest:contentPath="Default Web Site",computername="http://10.7.5.93",username='\localuser',password=aPassword
I am getting this error:
Error Code: ERROR_DESTINATION_NOT_REACHABLE
More Information: Could not connect to the remote computer ("10.7.5.93"). On the remote computer, make sure that Web Deploy is installed and that the required process ("Web Deployment Agent Service") is started. Learn more at: http://go.microsoft.com/fwlink/?LinkId=221672#ERROR_DESTINATION_NOT_REACHABLE.
Error: Unable to connect to the remote server
Error: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond 10.7.5.93:80
Error count: 1.
Unable to figure out the right syntax. I can deploy from VS with this publish file:
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<WebPublishMethod>MSDeploy</WebPublishMethod>
<ADUsesOwinOrOpenIdConnect>False</ADUsesOwinOrOpenIdConnect>
<LastUsedBuildConfiguration>Debug</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<SiteUrlToLaunchAfterPublish>https://kitostest.miracle.dk</SiteUrlToLaunchAfterPublish>
<LaunchSiteAfterPublish>True</LaunchSiteAfterPublish>
<ExcludeApp_Data>False</ExcludeApp_Data>
<MSDeployServiceURL>http://10.7.4.93</MSDeployServiceURL>
<DeployIisAppPath>Default Web Site</DeployIisAppPath>
<RemoteSitePhysicalPath />
<SkipExtraFilesOnServer>False</SkipExtraFilesOnServer>
<MSDeployPublishMethod>RemoteAgent</MSDeployPublishMethod>
<EnableMSDeployBackup>True</EnableMSDeployBackup>
<UserName>\deploy</UserName>
<_SavePWD>True</_SavePWD>
<PrecompileBeforePublish>True</PrecompileBeforePublish>
<EnableUpdateable>True</EnableUpdateable>
<DebugSymbols>False</DebugSymbols>
<WDPMergeOption>DonotMerge</WDPMergeOption>
<PublishDatabaseSettings>
<Objects xmlns="">
<ObjectGroup Name="KitosContext" Order="1" Enabled="False">
<Destination Path="" />
<Object Type="DbCodeFirst">
<Source Path="DBMigration" DbContext="Infrastructure.DataAccess.KitosContext, Infrastructure.DataAccess" MigrationConfiguration="Infrastructure.DataAccess.Migrations.Configuration, Infrastructure.DataAccess" Origin="Configuration" />
</Object>
</ObjectGroup>
</Objects>
</PublishDatabaseSettings>
</PropertyGroup>
<ItemGroup>
<MSDeployParameterValue Include="$(DeployParameterPrefix)KitosContext-Web.config Connection String" />
</ItemGroup>
</Project>
And a screen shoot off the deploy parameters:
So I need to find a way to map the parameters to msdeploy.
This is from my last attempt:
"C:\Program Files (x86)\IIS\Microsoft Web Deploy V3"\msdeploy.exe -whatif -verb:sync -source:contentPath="C:\work\WebPackage" -dest:contentPath='M:\Website',ComputerName="http://10.7.5.93/msdeploy.axd?site=Default Web Site",UserName='\ALocalUser',Password='MyPassWord',AuthType='Basic'
Syntak is taken form the article How to publish the contents of a folder with msdeploy.exe
Syntax for contentPath
I got it to work!!! I used fiddler to spy on visual studio when doing a web deploy. it was calling my site as site/MSDEPLOYAGENTSERVICE instead of site/msdeploy.axd. I was not the one installing msdeploy on the web server but if I read the manual then I could have saved myself 5 hours of frustrations.

Looks like there is no "Default web site"? Try adding the site name you publishing to:
msdeploy.exe -verb:sync -source:contentPath="..\WebPackage" -dest:auto,computername="http://10.7.5.93/msdeploy.axd?site=name_of_your_site",username=aUserName,password=aPassword
Depends how the contents have been created you might need another changes in your msdeploy line but I would try that first.

Related

Wix Installer Heat.exe error Parameter "exePath" is invalid

I am building a self-contained .Net Core worker service which I run as a windows service. Now I want to create an installe using Wix, however when I try to harvest all the needed DLL's for installation I get the following error:
An error occurred loading a configuration file: The parameter 'exePath' is invalid.
I've read this post which states the heat.exe might be broken. But I downloaded the tools via NuGet (3.11.2) which should theoretically be fine. My Beforebuild target looks as following:
<Exec Command="dotnet publish ..\Parlando.PVS.PackingSlipService\Parlando.PVS.PackingSlipService.csproj -c $(Configuration) -r win10-x86" />
<ItemGroup>
<LinkerBindInputPaths Include="%(ProjectReference.RootDir)%(ProjectReference.Directory)bin\$(Configuration)\%(ProjectReference.TargetFrameworkIdentifier)\win10-x86\publish" />
</ItemGroup>
<HeatDirectory
DirectoryRefId="INSTALLFOLDER"
OutputFile="$(ProjectDir)\HeatGeneratedFileList.wxs"
Directory="..\Parlando.PVS.PackingSlipService\bin\Release\netcoreapp3.1\win10-x86\publish"
ComponentGroupName="HeatGenerated"
ToolPath="$(WixToolPath)"
AutogenerateGuids="True"
SuppressCom="True"
SuppressRegistry="True"
SuppressFragments="True"
SuppressRootDirectory="True"
NoLogo="true" />
<ItemGroup>
<Compile Include="$(ProjectDir)\HeatGeneratedFileList.wxs" Condition="'%(ProjectReference.IsDotnetSDKProject)' == 'True'" />
</ItemGroup>
This should generate a .wxs file that I reference in the Product.wxs file when installing the service. My product.wxs does so as followed:
<ServiceInstall
Id="ServiceInstaller"
Type="ownProcess"
Name="Parlando.PVS.PackingSlipService"
DisplayName="Parlando.PVS.PackingSlipService"
Description="Service installed by Parlando to create packingslips and invoices."
Start="auto"
Account="LocalSystem"
ErrorControl="normal" />
<ServiceControl
Id="ServiceInstaller"
Start="install"
Stop="both"
Remove="uninstall"
Name="Parlando.PVS.PackingSlipService" />
</Component>
<ComponentRef Id="HeatGenerated" />
How can i use the heat.exe in such a way that I can access the DLL list in my Product.wxs and install my service via MSI?
Apperantly this error has nothing to do with the provided settings for the Wix installer, but rather the machine that Wix is installed on.
After testing my program on a different machine, all worked fine.

VSTS build with aspnet_merge causes error "The element 'buildProviders' cannot be defined below the application level"

When I build my asp.net application in VSTS with aspnetcompilemerge either in an msbuild argument or a publish profile, I get the following error:
MyProject\obj\release\aspnetcompilemerge\source\web.config(129,0): Error ASPCONFIG: The element 'buildProviders' cannot be defined below the application level.
Process 'msbuild.exe' exited with code '1'.
I believe this is in reference to this section of the web.config:
<buildProviders>
<add extension=".rdlc" type="Microsoft.Reporting.RdlBuildProvider, Microsoft.ReportViewer.WebForms, Version=14.0.0.0, Culture=neutral, PublicKeyToken=89845DCD8080CC91" />
</buildProviders>
But two things are odd about this -
1) My internet research on that error message shows issues with deploying or running a website, but I'm not deploying, only building.
2) The build does seem to succeed. I'm able to download the artifact and deploy it to an on prem web server, and the output appears to have been merged as defined in my publish profile.
Any ideas how to resolve this?
EDIT - I was able to reproduce this situation in a new MVC project.
Publish profile:
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<WebPublishMethod>FileSystem</WebPublishMethod>
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<SiteUrlToLaunchAfterPublish />
<LaunchSiteAfterPublish>True</LaunchSiteAfterPublish>
<PrecompileBeforePublish>True</PrecompileBeforePublish>
<EnableUpdateable>False</EnableUpdateable>
<DebugSymbols>False</DebugSymbols>
<WDPMergeOption>MergeAllOutputsToASingleAssembly</WDPMergeOption>
<UseMerge>True</UseMerge>
<SingleAssemblyName>buildprovidertest.PublishedOutput</SingleAssemblyName>
<DeleteAppCodeCompiledFiles>True</DeleteAppCodeCompiledFiles>
<ExcludeApp_Data>False</ExcludeApp_Data>
<publishUrl>C:\Publish\buildprovidertest</publishUrl>
<DeleteExistingFiles>True</DeleteExistingFiles>
</PropertyGroup>
</Project>
I was able to narrow it down to the <MvcBuildViews> node in the csproj file. When that is true, I get this error message. If I set it to false, the build succeeds.
Posting the entire build log exceeds the character limit for stackoverflow, but here's the end:
2017-07-31T13:43:32.4134567Z Adding file (d:\a\1\s\buildprovidertest\obj\Release\Package\PackageTmp\Web.config).
2017-07-31T13:43:32.4134567Z Adding ACL's for path (d:\a\1\s\buildprovidertest\obj\Release\Package\PackageTmp)
2017-07-31T13:43:32.4134567Z Adding ACL's for path (d:\a\1\s\buildprovidertest\obj\Release\Package\PackageTmp)
2017-07-31T13:43:32.4204577Z Adding declared parameter 'IIS Web Application Name'.
2017-07-31T13:43:32.4224576Z Adding declared parameter 'DefaultConnection-Web.config Connection String'.
2017-07-31T13:43:32.4904577Z Successfully executed Web deployment task.
2017-07-31T13:43:32.4984583Z Package "buildprovidertest.zip" is successfully created as single file at the following location:
2017-07-31T13:43:32.4984583Z file:///d:/a/1/a
2017-07-31T13:43:32.4984583Z To get the instructions on how to deploy the web package please visit the following link:
2017-07-31T13:43:32.4984583Z http://go.microsoft.com/fwlink/?LinkId=124618
2017-07-31T13:43:32.5184584Z GenerateSampleDeployScript:
2017-07-31T13:43:32.5184584Z Sample script for deploying this package is generated at the following location:
2017-07-31T13:43:32.5184584Z d:\a\1\a\buildprovidertest.deploy.cmd
2017-07-31T13:43:32.5184584Z For this sample script, you can change the deploy parameters by changing the following file:
2017-07-31T13:43:32.5184584Z d:\a\1\a\buildprovidertest.SetParameters.xml
2017-07-31T13:43:32.5184584Z PipelineDeployPhase:
2017-07-31T13:43:32.5184584Z Publish Pipeline Deploy Phase
2017-07-31T13:43:32.6134809Z CleanupForBuildMvcViews:
2017-07-31T13:43:32.6134809Z Deleting file "obj\Release\TransformWebConfig\assist\Web.config".
snip
2017-07-31T13:43:32.6384579Z Deleting file "obj\Release\Package\PackageTmp\Views\Shared\_LoginPartial.cshtml".
2017-07-31T13:43:32.6384579Z MvcBuildViews:
2017-07-31T13:43:32.6384579Z C:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_compiler.exe -v temp -p d:\a\1\s\buildprovidertest
2017-07-31T13:43:37.9922053Z ##[error]buildprovidertest\obj\release\aspnetcompilemerge\source\web.config(21,0): Error ASPCONFIG: 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.
2017-07-31T13:43:37.9922053Z d:\a\1\s\buildprovidertest\obj\release\aspnetcompilemerge\source\web.config(21): error ASPCONFIG: 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. [d:\a\1\s\buildprovidertest\buildprovidertest.csproj]
2017-07-31T13:43:37.9922053Z Done Building Project "d:\a\1\s\buildprovidertest\buildprovidertest.csproj" (default targets) -- FAILED.
2017-07-31T13:43:37.9932061Z Done Building Project "d:\a\1\s\buildprovidertest.sln" (buildprovidertest target(s)) -- FAILED.
2017-07-31T13:43:37.9932061Z
2017-07-31T13:43:37.9932061Z Build FAILED.
2017-07-31T13:43:38.0012046Z
2017-07-31T13:43:38.0012046Z "d:\a\1\s\buildprovidertest.sln" (buildprovidertest target) (1) ->
2017-07-31T13:43:38.0012046Z "d:\a\1\s\buildprovidertest\buildprovidertest.csproj" (default target) (2) ->
2017-07-31T13:43:38.0012046Z (MvcBuildViews target) ->
2017-07-31T13:43:38.0012046Z d:\a\1\s\buildprovidertest\obj\release\aspnetcompilemerge\source\web.config(21): error ASPCONFIG: 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. [d:\a\1\s\buildprovidertest\buildprovidertest.csproj]
2017-07-31T13:43:38.0012046Z
2017-07-31T13:43:38.0012046Z 0 Warning(s)
2017-07-31T13:43:38.0012046Z 1 Error(s)
2017-07-31T13:43:38.0012046Z
2017-07-31T13:43:38.0012046Z Time Elapsed 00:00:55.07
2017-07-31T13:43:38.1372049Z ##[error]Process 'msbuild.exe' exited with code '1'.
2017-07-31T13:43:38.1882046Z ##[section]Finishing: Build solution
With that setting, you can’t publish it through VS 2015 too.
Add this code to project file (xx.csproj):
<Target Name="MvcBuildViews" AfterTargets="AfterBuild" Condition="'$(MvcBuildViews)'=='true'">
<AspNetCompiler VirtualPath="temp" PhysicalPath="$(WebProjectOutputDir)" />
</Target>
<Target Name="AfterBuild">
<RemoveDir Directories="$(BaseIntermediateOutputPath)" />
</Target>
Related thread: TeamCity Build Failure

Database not being created in Visual Studio Web Deploy with code first architecture on shared hosting

I'm trying to use one-click web deploy to a shared host. The website loads properly, however links that go to pages looking for the database gives
[Win32Exception (0x80004005): The system cannot find the file specified]
[SqlException (0x80131904): A network-related or instance-specific
error occurred while establishing a connection to SQL Server. The
server was not found or was not accessible. Verify that the instance
name is correct and that SQL Server is configured to allow remote
connections. (provider: SQL Network Interfaces, error: 52 - Unable to
locate a Local Database Runtime installation. Verify that SQL Server
Express is properly installed and that the Local Database Runtime
feature is enabled.)]
This SO answer says that:
...the host will need to setup web deploy and provide you
with non-admin deploy credentials.
There's a full guide on iis.net. The process will output a
.publishsettings file to the desktop, which you can import into Visual
Studio's publish dialog.
I'm with MyASP.net, and they are running WS 2012. I just want to make sure the solution is not on my end before I send them on a wild goose chase.
My publish profile is:
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<WebPublishMethod>MSDeploy</WebPublishMethod>
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<SiteUrlToLaunchAfterPublish>http://abalter-001-site1.myasp.net/</SiteUrlToLaunchAfterPublish>
<LaunchSiteAfterPublish>True</LaunchSiteAfterPublish>
<ExcludeApp_Data>False</ExcludeApp_Data>
<MSDeployServiceURL>https://abalter-001-site1.myasp.net:8172/MsDeploy.axd</MSDeployServiceURL>
<DeployIisAppPath>abalter-001-site1</DeployIisAppPath>
<RemoteSitePhysicalPath />
<SkipExtraFilesOnServer>True</SkipExtraFilesOnServer>
<MSDeployPublishMethod>WMSVC</MSDeployPublishMethod>
<EnableMSDeployBackup>True</EnableMSDeployBackup>
<UserName>ifc\abalter-001</UserName>
<_SavePWD>True</_SavePWD>
<PublishDatabaseSettings>
<Objects xmlns="">
<ObjectGroup Name="GatorsContext" Order="1" Enabled="False">
<Destination Path="" />
<Object Type="DbCodeFirst">
<Source Path="DBContext" DbContext="Gators3.Models.GatorsContext, Gators3" Origin="Configuration" />
</Object>
</ObjectGroup>
<ObjectGroup Name="DefaultConnection" Order="2" Enabled="False">
<Destination Path="" />
<Object Type="DbCodeFirst">
<Source Path="DBContext" DbContext="Gators3.Models.ApplicationDbContext, Gators3" Origin="Configuration" />
</Object>
</ObjectGroup>
</Objects>
</PublishDatabaseSettings>
</PropertyGroup>
<ItemGroup>
<MSDeployParameterValue Include="$(DeployParameterPrefix)DefaultConnection-Web.config Connection String" />
<MSDeployParameterValue Include="$(DeployParameterPrefix)GatorsContext-Web.config Connection String" />
</ItemGroup>
</Project>
Web deploy settings from host:
UPDATE
I got it working. I wasn't actually entering the connection string for the database server on the host. This information was given to me by the host. When I put it in the web-deploy settings, all was well.

Set ACLs during Web Deployment via MSBuild

I have a mostly working web build-and-deploy configuration running in TeamCity, that basically uses MSBuild to automatically deploy the site to a web server. MSDeploy sets everything to Readonly on the target server by default, and I need the AppPool identity to have write access to just one folder.
I found an article by Kevin leetham that gets me 90% of the way there. Kevin describes how it is possible to hook into the MSBuild Web Publish Pipeline by creating a file called ProjectName.wpp.targets, along these lines:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<!--Extends the AfterAddIisSettingAndFileContentsToSourceManifest action do also set ACLs -->
<IncludeCustomACLs>TRUE</IncludeCustomACLs>
<AfterAddIisSettingAndFileContentsToSourceManifest Condition="'$(AfterAddIisSettingAndFileContentsToSourceManifest)'==''">
$(AfterAddIisSettingAndFileContentsToSourceManifest);
SetCustomACLs;
</AfterAddIisSettingAndFileContentsToSourceManifest>
</PropertyGroup>
<Target Name="SetCustomACLs" Condition="'$(IncludeCustomACLs)'=='TRUE'">
<Message Text="Adding Custom ACls" />
<ItemGroup>
<!-- Ensure the AppPool identity has write access to the Files directory -->
<MsDeploySourceManifest Include="setAcl" Condition="$(IncludeSetAclProviderOnDestination)">
<Path>$(_MSDeployDirPath_FullPath)\files</Path>
<setAclAccess>Read,Write,Modify</setAclAccess>
<setAclResourceType>Directory</setAclResourceType>
<AdditionalProviderSettings>setAclResourceType;setAclAccess</AdditionalProviderSettings>
</MsDeploySourceManifest>
</ItemGroup>
</Target>
</Project>
This is so nearly working that it is driving me crazy. The ACL gets added to the manifest, but the problem is that it generates an absolute path based on the build location, rather than being relative to the IIS web app on the target server. the generated manifest comes out like this (some names have been changed to protect the innocent):
<?xml version="1.0" encoding="utf-8"?>
<sitemanifest>
<IisApp path="C:\SolutionPath\IisWebAppName\src\MyProjectName\obj\Release_Deploy\Package\PackageTmp" managedRuntimeVersion="v4.0" />
<setAcl path="C:\SolutionPath\IisWebAppName\src\MyProjectName\obj\Release_Deploy\Package\PackageTmp" setAclResourceType="Directory" />
<setAcl path="C:\SolutionPath\IisWebAppName\src\MyProjectName\obj\Release_Deploy\Package\PackageTmp" setAclUser="anonymousAuthenticationUser" setAclResourceType="Directory" />
<setAcl path="C:\SolutionPath\IisWebAppName\src\MyProjectName\obj\Release_Deploy\Package\PackageTmp\files" setAclResourceType="Directory" setAclAccess="Read,Write,Modify" />
</sitemanifest>
This actually looks correct, the last line is my custom ACL from teh wpp.targets file. However, when MSDeploy sends this to the target server, here's what happens:
2>Start Web Deploy Publish the Application/package to https://webhostingprovider.biz:8172/msdeploy.axd?site=IisWebAppName ...
2>Adding sitemanifest (sitemanifest).
2>Adding ACL's for path (IisWebAppName)
2>Adding ACL's for path (IisWebAppName)
2>Adding ACL's for path (C:\SolutionPath\IisWebAppname\src\MyProjectName\obj\Release_Deploy\Package\PackageTmp\files)
2>C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0\Web\Microsoft.Web.Publishing.targets(4377,5): Error ERROR_USER_NOT_AUTHORIZED_FOR_SETACL: Web deployment task failed. (Could not complete an operation with the specified provider ("setAcl") when connecting using the Web Management Service. This can occur if the server administrator has not authorized the user for this operation. setAcl http://go.microsoft.com/fwlink/?LinkId=178034
The whole thing falls over on my custom ACL path, which comes out using an absolute path name instead of being relative to IisWebAppName. I cannot figure out why!!
Help please :)
You need to create a ProviderPath parameter with a DefaultValue that takes it's value of another parameter using the {param name} syntax.
Here's a helper I included on another question that performs all the actions:
<ItemDefinitionGroup>
<AdditionalAcls>
<AclAccess>Write</AclAccess>
<ResourceType>Directory</ResourceType>
</AdditionalAcls>
</ItemDefinitionGroup>
<PropertyGroup>
<AfterAddIisSettingAndFileContentsToSourceManifest>
$(AfterAddIisSettingAndFileContentsToSourceManifest);
AddAdditionalAclsToSourceManifest;
</AfterAddIisSettingAndFileContentsToSourceManifest>
<AfterAddIisAndContentDeclareParametersItems>
$(AfterAddIisAndContentDeclareParametersItems);
AddAdditionalAclsDeclareParameterItems
</AfterAddIisAndContentDeclareParametersItems>
</PropertyGroup>
<Target Name="AddAdditionalAclsToSourceManifest">
<ItemGroup Condition="'#(AdditionalAcls)' != ''">
<MsDeploySourceManifest Include="setAcl">
<Path>$(_MSDeployDirPath_FullPath)\%(AdditionalAcls.Identity)</Path>
<setAclResourceType Condition="'%(AdditionalAcls.ResourceType)' != ''">%(AdditionalAcls.ResourceType)</setAclResourceType>
<setAclAccess>%(AdditionalAcls.AclAccess)</setAclAccess>
<AdditionalProviderSettings>setAclResourceType;setAclAccess</AdditionalProviderSettings>
</MsDeploySourceManifest>
</ItemGroup>
</Target>
<Target Name="AddAdditionalAclsDeclareParameterItems">
<ItemGroup Condition="'#(AdditionalAcls)' != ''">
<MsDeployDeclareParameters Include="Add %(AdditionalAcls.AclAccess) permission to %(AdditionalAcls.Identity) Folder">
<Kind>ProviderPath</Kind>
<Scope>setAcl</Scope>
<Match>^$(_EscapeRegEx_MSDeployDirPath)\\#(AdditionalAcls)$</Match>
<Description>Add %(AdditionalAcls.AclAccess) permission to %(AdditionalAcls.Identity) Folder</Description>
<DefaultValue>{$(_MsDeployParameterNameForContentPath)}/#(AdditionalAcls)</DefaultValue>
<DestinationContentPath>$(_DestinationContentPath)/#(AdditionalAcls)</DestinationContentPath>
<Tags>Hidden</Tags>
<ExcludeFromSetParameter>True</ExcludeFromSetParameter>
<Priority>$(VsSetAclPriority)</Priority>
</MsDeployDeclareParameters>
</ItemGroup>
</Target>
You can use it by declaring:
<ItemGroup>
<AdditionalAcls Include="MyRelativeWritableDirectory" />
</ItemGroup>
Please note that this solution only currently works if you don't need a backslash in the path (ie. if it's a root directory only). If you need a sub-directory, you'll need to steal the trick I use for "SkipDeleteItems" (later in that answer) to add regex-escaped path metadata to each item.

How to get aspnet_compiler invoked from Visual Studio during build?

I want Visual Studio to precompile my ASP.NET application which is used as an Azure web role payload. So I've found this post that explains how to call aspnet_compiler to validate views.
I tried to add the following to "post-build event" of my ASP.NET application:
call "%VS100COMNTOOLS%\vsvars32.bat"
aspnet_compiler -v / -p $(ProjectDir)
or alternatively this (application name specified explicitly):
call "%VS100COMNTOOLS%\vsvars32.bat"
aspnet_compiler -v /ASP.NET-Application-ProjectNameHere -p $(ProjectDir)
In both cases when the build runs I see the following in the build output:
Setting environment for using Microsoft Visual Studio 2010 x86 tools.
Utility to precompile an ASP.NET application
Copyright (C) Microsoft Corporation. All rights reserved.
and clearly no precompilation happens because if I change any .aspx or .cshtml file "Build Action" to "None" it doesn't get to the Azure service package and the view no longer opens once the package is deployed to Azure.
How do I setup aspnet_compiler for precompiling from within Visual Studio?
If you want to use Asp.NET Compiler within your Visual Studio / msbuild then you can add
AspNetCompiler Task to your project file (.csproj/.vbproj) and set MvcBuildViews to true.
Example:
<Project>
<PropertyGroup>
<MvcBuildViews>true</MvcBuildViews>
</PropertyGroup>
<!-- ... -->
<Target Name="PrecompileWeb" AfterTargets="build" Condition="'$(MvcBuildViews)'=='true'">
<Message Text="Starting AspNetCompiler for $(ProjectDir)" Importance="high" />
<AspNetCompiler
VirtualPath="temp"
PhysicalPath="$(WebProjectOutputDir)"
Force="true"
/>
</Target>
<!-- ... -->
</Project>
You may also set TargetPath attribute to specify destination directory.
AfterTargets="build" is similar to "post-build event". See Target Build Order for more.
Integrate ASPX compilation into Visual Studio
One of the principles I insist on is to always try my build on a clean environment and simulate installation as if it was done by QA. Lately I've noticed that I keep falling on errors hidden deep in the aspx files. So, why not using the old and familiar aspnet_compiler.exe tool? It is located at C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727 and it is quite easy to use.
As a VS add-ins freak I've started thinking on an amazing add-in that will integrate to the VS and will listen to build events and display the results at the output pane. Heck, why not add some coffee serving capabilities?
It took me about 10 minutes of googling to stumble on this blog. Mike Hadlow had a genius in its simplicity idea. Use the POST BUILD EVENT!
All I need to do is put the following line in the post build event: C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_compiler.exe -v / -p "$(ProjectDir)\"
Now, All that is left is to make the process of adding this line to each and every web project in our team to be automatic.
I have just the add-in for that :)
enter link description here
The answer from Matej was helpful for me, but I was not able to use it as-is and still get it to work for both local builds within Visual Studio and automated builds via TFS.
I had to add some extra msbuild settings. Actually, there were 2 different scenarios that I had. One project was an Web App that built into the _PublishedWebsites folder and one was an MVC Web App that did not build into the _PublishedWebsites folder.
First, add the following if it is not already in your project file:
<PropertyGroup>
<MvcBuildViews>true</MvcBuildViews>
</PropertyGroup>
For the one WITH _PublishedWebsites:
<Choose>
<When Condition="'$(BuildingInsideVisualStudio)' == true">
<PropertyGroup>
<AspNetCompilerPhysicalPath>$(ProjectDir)</AspNetCompilerPhysicalPath>
</PropertyGroup>
</When>
<Otherwise>
<PropertyGroup>
<AspNetCompilerPhysicalPath>$(WebProjectOutputDir)</AspNetCompilerPhysicalPath>
</PropertyGroup>
</Otherwise>
</Choose>
<Target Name="PrecompileWeb" AfterTargets="build" Condition="'$(MvcBuildViews)'=='true'">
<!-- aspnet_compiler.exe needs to be run on the folder that has the aspx files and the "bin" subfolder.
When running locally, the value needs to be the project directory, which is $(ProjectDir).
When running the TFS build, the value needs to be (BuildFolder)\(ProjectName)\_PublishedWebsites\(ProjectName).
The $(AspNetCompilerPhysicalPath) will hold the correct value for both types of builds.
-->
<Message Text="Starting AspNetCompiler for $(ProjectName) at $(AspNetCompilerPhysicalPath)" Importance="high" />
<AspNetCompiler
VirtualPath="/"
PhysicalPath="$(AspNetCompilerPhysicalPath)"
TargetPath="$(AspNetCompilerPhysicalPath)\bin_precompile"
Force="true"
/>
</Target>
For the one WITHOUT _PublishedWebsites:
<Choose>
<When Condition="'$(BuildingInsideVisualStudio)' == true">
<PropertyGroup>
<AspNetCompiler_CopyFilesFirst>false</AspNetCompiler_CopyFilesFirst>
</PropertyGroup>
</When>
<Otherwise>
<PropertyGroup>
<AspNetCompiler_CopyFilesFirst>true</AspNetCompiler_CopyFilesFirst>
</PropertyGroup>
<ItemGroup>
<AllOutputFiles Include="$(OutDir)\\**\*.*" />
</ItemGroup>
</Otherwise>
</Choose>
<Target Name="PrecompileWeb" AfterTargets="build" Condition="'$(MvcBuildViews)'=='true'">
<!-- aspnet_compiler.exe needs to be run on the folder that has the cshtml files and the "bin" subfolder. I could not find a setting that was appropriate for both.
When running locally, the value needs to be the project directory, which is $(ProjectDir).
When running the TFS build, there is no folder that matches both of those criteria.
So first we will copy the output into the source code folder's "bin" subfolder,
then run it against the source $(ProjectDir), the same as if we were building locally.
-->
<Message Text="Before running AspNetCompiler, copy files from $(OutDir) to $(ProjectDir)\bin" Importance="high" />
<Exec Command="( robocopy.exe /mir $(OutDir) $(ProjectDir)\bin ) ^& IF %25ERRORLEVEL%25 LEQ 1 exit 0" Condition="'$(AspNetCompiler_CopyFilesFirst)'=='true'" />
<Message Text="Starting AspNetCompiler for $(ProjectName) at $(ProjectDir)" Importance="high" />
<AspNetCompiler
VirtualPath="/"
PhysicalPath="$(ProjectDir)"
TargetPath="$(ProjectDir)\bin_precompile"
Force="true"
/>
</Target>

Resources