"IIS Web Application Name' has already been defined" when using msdeploy from TFS Build - msbuild

So here's the deal: I have a Visual Studio solution that is made up of numerous projects. Two of these projects are web application projects. Of these two, I want to have TFS build deploy one of them to our dev server after a successful build/test run.
To get the web app to deploy, I updated the deploy target of my .csproj so it looks like the following:
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DeployOnBuild>true</DeployOnBuild>
<DeployTarget>MsDeployPublish</DeployTarget>
<CreatePackageOnPublish>true</CreatePackageOnPublish>
<MSDeployPublishMethod>WMSVC</MSDeployPublishMethod>
<MSDeployServiceUrl>https://192.168.21.79</MSDeployServiceUrl>
<DeployIisAppPath>DeploymentTest</DeployIisAppPath>
<UserName>deploy</UserName>
<Password>sosecure</Password>
<AllowUntrustedCertificate>true</AllowUntrustedCertificate>
<SkipExtraFilesOnServer>true</SkipExtraFilesOnServer>
</PropertyGroup>
With this configuration, my web app was getting deployed to the server successfully. Unfortunately there was one minor problem. For reasons that are too frustrating to go into here (and at the end of the day, can't likely be changed), when the deploy runs and pushes the app to our server, there's one CSS file in the project that I need skipped. That is to say, I want the server copy of the file to be left alone, even if it's different from what's in the project.
To support this requirement, I added the following to my .csproj:
<PropertyGroup>
<OnBeforePackageUsingManifest>AddSkipRules</OnBeforePackageUsingManifest>
</PropertyGroup>
<Target Name="AddSkipRules">
<ItemGroup>
<MsDeploySkipRules Include="SkipCss">
<SkipAction>Delete</SkipAction>
<ObjectName>filePath</ObjectName>
<AbsolutePath>site\.css$</AbsolutePath>
<XPath>
</XPath>
</MsDeploySkipRules>
<MsDeploySkipRules Include="SkipCss2">
<SkipAction>Update</SkipAction>
<ObjectName>filePath</ObjectName>
<AbsolutePath>site\.css$</AbsolutePath>
<XPath>
</XPath>
</MsDeploySkipRules>
</ItemGroup>
</Target>
With this added, my expectation was that the build would skip processing of my site.css file. Alas, after trying a number of different things, the file always got updated on the server. After a bit more digging, I found something (here on SO or on a blog, don't recall at this point) that mentioned the .csproj needs a directive to ensure msdeploy.exe is used to handle the deployment. With that in mind, I added the following:
<PropertyGroup>
<UseMsDeployExe>true</UseMsDeployExe>
</PropertyGroup>
Now when I run the build, it fails with the following error:
MSDEPLOY: The parameter 'IIS Web Application Name' has already been defined.
So, I tried removing the <DeployIssAppPath> element from the .csproj but that just led to the following error:
C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0\Web\Microsoft.Web.Publishing.targets (4220): The "ConcatFullServiceUrlWithSiteName" task was not given a value for the required parameter "SiteAppName".
At this point I'm pretty much out of ideas and really need to get this thing working. Any suggestions or insight as to what I'm missing to get around the error about 'IIS Web Application Name' already being defined or the last error about 'SiteAppName' not having a value would be appreciated.

Have you tried stopping the app pool for the target before deploying? I use something like this in PowerShell, which is called from MSBuild in my deployment processes:
echo ""
echo "Stopping $($args[0]) App Pool..."
echo ""
#Stop App Pool
MsDeployAppPoolSwitch $args[0] $args[1] $args[2] $args[3] "StopAppPool"
echo ""
echo "Deploying to $($args[0])..."
echo ""
#Deploy Site
WebsiteDeploy $args[0] $args[1] $args[2] $args[3] $DropFolder
echo ""
echo "Starting $($args[0]) App Pool..."
echo ""
#Start App Pool
MsDeployAppPoolSwitch $args[0] $args[1] $args[2] $args[3] "StartAppPool"

Related

net Core 2.0 precompile views in library project fails with strange error

I have a library that is loaded by a web app at runtime. The library dll and views are copied to a special Modules folder, in the web app, at compile time. The web app locates and registers the library OK and the views work as expected. I used parts of a number of sites to set this up, mainly https://www.codeproject.com/Articles/1109475/Modular-Web-Application-with-ASP-NET-Core amongst others.
When deploying to Azure the issue is that the various views under the Modules folder are being precompiled which fails as the main web app knows nothing of the various classes and services that the view needs. Note, the web app does not reference the library project.
One quick solution was to turn off view compilation for the whole project which did allow the web app to be deployed but suffers from speed issues as the views are no longer compiled.
OK, I then thought to precompile the views in the library and deploy that along with the web app.
This is where the trouble starts. Much googling later I discover that this is not simple and the csproj needs to be manually modified by inserting the following:
<Target Name="SetMVCRazorOutputPath">
<PropertyGroup>
<MvcRazorOutputPath>$(OutputPath)</MvcRazorOutputPath>
</PropertyGroup>
</Target>
<Target Name="_MvcRazorPrecompileOnBuild" DependsOnTargets="SetMvcRazorOutputPath;MvcRazorPrecompile" AfterTargets="Build" Condition=" '$(IsCrossTargetingBuild)' != 'true' " />
<Target Name="IncludePrecompiledViewsInPublishOutput" DependsOnTargets="_MvcRazorPrecompileOnBuild" BeforeTargets="PrepareForPublish" Condition=" '$(IsCrossTargetingBuild)' != 'true' ">
<ItemGroup>
<_PrecompiledViewsOutput Include="$(MvcRazorOutputPath)$(MSBuildProjectName).PrecompiledViews.DLL" />
<_PrecompiledViewsOutput Include="$(MvcRazorOutputPath)$(MSBuildProjectName).PrecompiledViews.pdb" />
<ContentWithTargetPath Include="#(_PrecompiledViewsOutput->'%(FullPath)')" RelativePath="%(_PrecompiledViewsOutput.Identity)" TargetPath="%(_PrecompiledViewsOutput.Filename)%(_PrecompiledViewsOutput.Extension)" CopyToPublishDirectory="PreserveNewest" />
</ItemGroup>
</Target>
Sort of makes sense except that I get an error when building the library project where the precompiling fails. The error is:
Error MSB3073 The command ""dotnet" exec --runtimeconfig "C:\Code\MyProject\LibraryProject\bin\Debug\netcoreapp2.0\LibraryProject.runtimeconfig.json" --depsfile "C:\Code\MyProject\LibraryProject\bin\Debug\netcoreapp2.0\LibraryProject.deps.json" "C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.aspnetcore.mvc.razor.viewcompilation\2.0.1\build\netstandard2.0\Microsoft.AspNetCore.Mvc.Razor.ViewCompilation.dll" #"obj\Debug\netcoreapp2.0\microsoft.aspnetcore.mvc.razor.viewcompilation.rsp"" exited with code -2147450733.
Not much help in the error code sadly.
This is generated and look OK to me:
microsoft.aspnetcore.mvc.razor.viewcompilation.rsp:
C:\CodeMyProject\LibraryProject
--output-path=bin\Debug\netcoreapp2.0\
--application-name=LibraryProject
--content-root=C:\CodeMyProject\LibraryProject
--file=C:\CodeMyProject\LibraryProject\Views\UnitPeriodImporter\Index.cshtml
--file=C:\Code\MyProject\LibraryProject\Views\UnitPeriodImporter\_CreateImportBatch.cshtml
--file=C:\CodeMyProject\LibraryProject\Views\_ViewImports.cshtml
Any ideas? I would very much like to turn on precompiling again.
Please note the file and project names have been adjusted for security reasons.
Gordon
Seems that the "LibraryProject.runtimeconfig.json" and "LibraryProject.deps.json" files are missing.
Try adding the following in your csproj.
<Target Name="AddRuntimeConfigFileToBuiltProjectOutputGroupOutput" Condition="'$(GenerateRuntimeConfigurationFiles)' == 'true' And '$(Configuration)|$(Platform)' == 'Release|AnyCPU'" BeforeTargets="BuiltProjectOutputGroup">
<ItemGroup>
<BuiltProjectOutputGroupOutput Include="$(ProjectRuntimeConfigFilePath)" FinalOutputPath="$(ProjectRuntimeConfigFilePath)" />
</ItemGroup>
</Target>

.NET-Core: Running the built application in PostBuildEvent

I have an Exe project that I would like to run in the PostBuildEvent block. I have tried adding a command to do this several ways but nothing seems to work.
dotnet run -- -i
dotnet run TestConsole.csproj -- -i
dotnet run ../../../TestConsole.csproj -- -i
../../../init.bat (which contains a cd to the project directory and "dotnet run...")
The first two fail being unable to find anything to run. The last two fail by hanging. Apparently, dotnet build recursively calling dotnet run doesn't work very well.
Is there a way of doing this?
The easiest way to do this is to re-use the built-in targets that already calculate the command. dotnet run also builds the project, so calling dotnet run could cause an infinite recursion - instead it should be dotnet path/to/the.dll. Also, PostBuildEvent is considered deprecated and has problems in SDK-based projects (an upcoming VS update will add targets instead when adding post build commands).
To execute the program on build, you can add the following to the csproj file:
<Project Sdk="Microsoft.NET.Sdk">
<!-- other project content -->
<Target Name="RunAfterBuild" AfterTargets="Build">
<Exec Command="$(RunCommand) $(RunArguments)" WorkingDirectory="$(RunWorkingDirectory)" />
</Target>
</Project>
The AfterTargets="Build" will cause to to run after ever build, even if it is invoked through VS. If it should not be run when working on the project in VS, you could add
Condition=" '$(BuildingInsideVisualStudio)' != 'true' "
as an attribute to the <Target> element.
The values for $(RunCommand), $(RunArguments) and $(RunWorkingDirectory) are defaulted by the SDK and contain the right paths to the host / exe file etc. involved. You can add any custom parameters to the Command="..." attribute and they will be passed to the application (no -- needed).
In order to add global arguments that would also be respected when the project was built/run through dotnet run, the StartArguments property in the project can be set. it will be added to RunArguments automatically:
<Project …>
<PropertyGroup>
<StartArguments>--sample-option</StartArguments>
</PropertyGroup>
<!-- other content -->
</Project>

.NET Core console application is not creating an EXE file

I'm trying to publish a .NET Core console application following this tutorial, but when I publish, I don't get an executable file in the PublishOutput folder (I get a DLL file). I've also read this article.
My project file looks like this:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp1.1</TargetFramework>
</PropertyGroup>
</Project>
It seems pretty easy and straightforward, but what am I doing wrong?
Yeah, this is a weird one. I am still trying to work through it. I did find there seems to be a delay in getting the functionality from the CLI to Visual Studio 2017: This Stack Overflow article talks about that.
Also, there is ongoing confusion around exactly what Output type means since it is not what we all think. This GitHub issue talks about it.
I tried this on the Hello, World! template that Visual Studio provides. Change your .csproj file to the following:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!--<OutputType>Exe</OutputType>-->
<TargetFramework>netcoreapp1.1</TargetFramework>
<RuntimeIdentifiers>win10-x64</RuntimeIdentifiers>
</PropertyGroup>
</Project>
I don't think the OutputType matters more than the RuntimeIdentifiers property.
Then using the console, run dotnet restore followed by dotnet publish -c release -r win10-x64
This should generate an EXE file under \bin\Release\netcoreapp1.1\win10-x64\publish
View this article from the same person in your first link.

How to transform config files with slow cheetah on build in a web project

So what I want to accomplish is transform all config files on the build.
Web.config
App.config
....config.xml
In the project files they all look like this:
<None Include="FooBar.config.xml">
<TransformOnBuild>true</TransformOnBuild>
</None>
<None Include="FooBar.config.Release.xml">
<DependentUpon>FooBar.config.xml</DependentUpon>
<IsTransformFile>True</IsTransformFile>
</None>
And everything works fine for windows services and windows applications. But for web projects slow cheetah is not doing the transforms. After some research I found this :
"For web projects the files are transformed when you publish or package your application." From the slow cheetah extension page. And indeed when I publish the web project the transforms are done correctly.
So how can I change slow cheetah default behavior and execute all transforms on the build server?
Environment:
TFS 2010
Slow cheetah version on build server: 1.0.10727.0
So how I fixed this.
I've edited the targets file of SlowCheetah
This can be found C:\Users\BuildUser\AppData\Local\Microsoft\MSBuild\SlowCheetah\v1
On your build server. Open the file and locate the following lines:
<BuildDependsOn Condition=" '$(IsWap)'!='true' ">
<BuildDependsOn>
$(BuildDependsOn);
TransformAllFiles
</BuildDependsOn>
And i've removed the condition.
Result:
<BuildDependsOn>
$(BuildDependsOn);
TransformAllFiles
</BuildDependsOn>
There is a better solution these days. Just use the transformxml msbuild task. I don't think slow cheetah will continue to be maintained now that this functionality is native to msbuild. More at https://msdn.microsoft.com/en-us/library/dd465326(v=vs.110).aspx

Overriding MSBuildExtensionsPath in the MSBuild task is flaky

This is already cross-posted at MS Connect:
https://connect.microsoft.com/VisualStudio/feedback/details/560451
I am attempting to override the property $(MSBuildExtensionsPath) when building a solution containing a C# web application project via msbuild. I am doing this because a web application csproj file imports the file "$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v9.0\WebApplications\Microsoft.WebApplication.targets". This file is installed by Visual Studio to the standard $(MSBuildExtensionsPath) location (C:\Program Files\MSBuild). I would like to eliminate the dependency on this file being installed on the machine (I would like to keep my build servers as "clean" as possible). In order to do this, I would like to include the Microsoft.WebApplication.targets in source control with my project, and then override $(MSBuildExtensionsPath) so that the csproj will import this included version of Microsoft.WebApplication.targets. This approach allows me to remove the dependency without requiring me to manually modify the web application csproj file.
This scheme works fine when I build my solution file from the command line, supplying the custom value of $(MSBuildExtensionsPath) at the command line to msbuild via the /p flag. However, if I attempt to build the solution using the MSBuild task in a custom msbuild project file (overriding MSBuildExtensionsPath using the "Properties" attribute), it fails because the web app csproj file is attempting to import the Microsoft.WebApplication.targets from the "standard" Microsoft.WebApplication.targets location (C:\Program Files\MSBuild). Notably, if I run msbuild using the "Exec" task in my custom project file, it works. Even more notably, the FIRST time I run the build using the "MSBuild" task AFTER I have run the build using the "EXEC" task (or directly from the command line), the build works.
Has anyone seen behavior like this before? Am I crazy? Is anyone aware of the root cause of this problem, a possible workaround, or whether this is a legitimate bug in MSBuild?
Steps to Reproduce:
1) Create a new empty solution in MSVS 2008 (Fake.sln)
2) Add a new C# web application to the solution (WebApplication1.csproj)
3) Close MSVS
4) Copy the contents of "C:\Program Files\MSBuild\" to a directory called "MSBuildExtensions" in the directory containing your solution.
5) rename the directory "C:\Program Files\MSBuild\Microsoft\VisualStudio\v9.0\WebApplications" so that WebApplication1.csproj will not be able to import Microsoft.WebApplication.targets from that location.
6) Create a custom MSBuild project file called "TestBuild.proj" in the same directory as the solution. It should have the following content:
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="BuildMSBuild">
<PropertyGroup>
<MSBuildExtensionsPath>$(MSBuildProjectDirectory)\MSBuildExtensions\</MSBuildExtensionsPath>
<BuildThis>Fake.sln</BuildThis>
</PropertyGroup>
<Target Name="BuildMSBuild">
<MSBuild Projects="$(BuildThis)" Properties="MSBuildExtensionsPath=$(MSBuildExtensionsPath);" Targets="Clean" />
<MSBuild Projects="$(BuildThis)" Properties="MSBuildExtensionsPath=$(MSBuildExtensionsPath);"/>
</Target>
</Project>
7) execute "msbuild TestBuild.proj" from a MSVS command prompt (note: the build may succeed the first time, but will fail if you run more than once)
Did you try setting the environment variable MSBuildExtensionPath in the CMD prompt and then running your build?
For example:
C:\> SET MSBuildExtensionsPath=C:\My\MSBuild\Extensons
Then on this project file:
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Build">
<Message Text='MSBuildExtensionsPath="$(MSBuildExtensionsPath)"' />
</Target>
</Project>
you will get the following output:
c:\Users\chuckeng\Desktop\ConsoleApplication1>"C:\Windows\Microsoft.NET\Framework\v3.5\MSBuild.exe" my.proj
Microsoft (R) Build Engine Version 3.5.30729.4926
[Microsoft .NET Framework, Version 2.0.50727.4927]
Copyright (C) Microsoft Corporation 2007. All rights reserved.
Build started 6/25/2010 1:04:05 PM.
Project "c:\my.proj" on node 0 (default targets).
MSBuildExtensionsPath="C:\My\MSBuild\Extensons"
Done Building Project "c:\my.proj" (default targets).
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:00.03
This works from v4.0 as well. Although, support is generally better in v4.0 for things like this. And, v4.0 is 100% backward compatible (bugs not withstanding). So, you can build your v3.5 and prior projects with v4.0. Just select ToolsVersion 3.5.
msbuild my.proj /tv:3.5
Hope this helps...
Chuck England
Visual Studio
Program Manager - MSBuild
This is a bug in MSBuild 3.5 but it is fixed in MSBuild 4.
If you can, switch to MSBuild 4 (you still can compile your 3.5 projects), otherwise you'll have to override the property in the project file.
It works fine if you override MSBuildExtensionsPath directly in the web app .csproj file.
<PropertyGroup>
<MSBuildExtensionsPath>C:\Users\madgnome\Desktop\msbuild</MSBuildExtensionsPath>
<!-- It works too with relative path -->
<!--<MSBuildExtensionsPath>..\msbuild</MSBuildExtensionsPath>-->
</PropertyGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
Don't know if this might help anyone in the future, but I was able to use the following at the top of my file and it works as I would expect in both 32 and 64 bit build environments.
<PropertyGroup>
<MSBuildExtensionsPath Condition=" '$(MSBuildExtensionsPath64)' != '' ">$(MSBuildExtensionsPath64)</MSBuildExtensionsPath>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\ExtensionPack\4.0\MSBuild.ExtensionPack.tasks"/>