Azure Devops Release pipeline unable to take latest C# version - azure-devops

I have a console application which has async calls for e.g. the signature of the main method looks like this
static async Task MainAsync(string[] args)
{
}
I am able to compile the build in my local machine. But I have a VSTS (DevOps Azure) CI/CD pipeline where I am using a custom hosted agent in that machine, over there once the CI executes it gives the error:
##[error]CSC(0,0): Error CS5001: Program does not contain a static 'Main' method suitable for an entry point

I got it working by forcing the user agent to use VS2017.
Click phase 1 and then change it to the following:
HostedVS2017
This forces the user agent to use 2017 which has the latest version of C# instead of 2015 (which it was falling back to for me).

Can you try building your local code in release mode and see if you are getting the same issue.
Make sure to add C# 7.1 to any CPU and release property groups.
Right-click Your Project, click Properties
Click Build if it's not already selected
Change Configuration to All Configurations
Click Advanced...
Change the language version
Refer this issue in github for more details.
https://github.com/dotnet/roslyn/issues/21783

https://www.visualstudiogeeks.com/azure/devops/using-latest-version-of-csharp-with-dotnetcore
in pipeline
in visual studio build
add to MSBuild Arguments
/property:langversion=latest
or
Edit the c# Project and add
<LangVersion>latest</LangVersion>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PackageAction>BuildDefault</PackageAction>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PackageAction>BuildDefault</PackageAction>
<LangVersion>latest</LangVersion>
</PropertyGroup>

Related

How to tell dotnet watch to run a different build configuration? [duplicate]

This question already has answers here:
How to use "dotnet watch run" with .Net Core 3, Visual Studio 2019 and docker
(3 answers)
Closed 2 years ago.
Today I have a container running dotnet watch -v --project ".\\MyProject" run --no-launch-profile and the "MyProject" folder is mapped transparently to a .NET Core project of my solution. So whenever I alter a file in my Visual Studio it's picked up immediately inside the container and recompiled to allow quick alteration and testing. However I've noticed that this causes conflict issues when I build on my host machine causing a conflict over the bin\Debug\netcoreapp3.1\MyProject.exe
To solve this situation I wanted to see if I can pass an argument/parameter/configuration/... anything to dotnet watch that would tell it to use a different build configuration (copy of Debug really but called Container so that it'd create a separate folder and not conflict with the host Visual Studio)
Sadly I have not been able to locate an example or documentation on how to do this with dotnet watch. Is this possible? Is there a better solution?
Rather than target a different build configuration with dotnet watch, you can solve this by changing the output directory based on a built-in dotnet environment variable, DOTNET_RUNNING_IN_CONTAINER.
<Project>
<PropertyGroup Condition="'$(UsingMicrosoftNETSdk)' == 'true'">
<DefaultItemExcludes>$(DefaultItemExcludes);$(MSBuildProjectDirectory)/obj/**/*</DefaultItemExcludes>
<DefaultItemExcludes>$(DefaultItemExcludes);$(MSBuildProjectDirectory)/bin/**/*</DefaultItemExcludes>
</PropertyGroup>
<PropertyGroup Condition="'$(UsingMicrosoftNETSdk)' == 'true' AND '$(DOTNET_RUNNING_IN_CONTAINER)' == 'true'">
<BaseIntermediateOutputPath>$(MSBuildProjectDirectory)/obj/container/</BaseIntermediateOutputPath>
<BaseOutputPath>$(MSBuildProjectDirectory)/bin/container/</BaseOutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(UsingMicrosoftNETSdk)' == 'true' AND '$(DOTNET_RUNNING_IN_CONTAINER)' != 'true'">
<BaseIntermediateOutputPath>$(MSBuildProjectDirectory)/obj/local/</BaseIntermediateOutputPath>
<BaseOutputPath>$(MSBuildProjectDirectory)/bin/local/</BaseOutputPath>
</PropertyGroup>
</Project>

Prevent post build event in VSTS

For development purposes my team has a post build event defined to pack and publish nuget packages locally. This step is not necessary during the build in VSTS because we have a step defined for that during the building to pack and ship the nuget packages to a different server, whithout symbols. Right now this step is executed in any build we run. How to prevent that only in the build server?
You're going to have to dig into MSBuild for this. You need to add a condition to check for one of the environment variables that's set when running in the context of a build, and only run if that environment variable is blank.
For example,
<PropertyGroup>
<PostBuildEvent Condition=" '$(BUILD_SOURCESDIRECTORY)' == '' ">echo Hello World</PostBuildEvent>
</PropertyGroup>
BUILD_SOURCESDIRECTORY is an environment variable that's populated when running in the context of a build, but isn't populated normally on a developer's desktop. Thus, echo Hello World will only run when that value is blank.

VS 2015 MSDeployPublish not executing

I am using VS 2015 and trying to execute a PowerShell after publishing the web application. I have created a publish profile, compiling in release mode and publish method is a file system, then in my project XML I have added a target
<Target Name="Mytarget2" AfterTargets="MSDeployPublish">
<Error Text="he name of the publish profile is $(DestinationAppRoot)">
</Error>
</Target>
so I am expecting an error message after publishing through visual studio but not getting anything and how can I call PowerShell script if I get it working?
VS 2015 MSDeployPublish not executing
That because you are publishing your project from File System. The target "MSDeployPublish" is not supported by the File System.
"We currently do not support executing custom targets after publish from VS for the file system protocol. If you publish from the command line the target will be executed however."
So, you could use MSBuild command line to execute this custom target by specify the target, /t:Mytarget2:
msbuild "YourSolutionFile" /t:Build,Mytarget2 /p:DeployOnBuild=true /p:PublishProfile=YourPublishFile.pubxml
Or you can change settings in VS to build with high verbosity and see whichis the last target to be executed, then you can use it instead of target MSDeployPublish, for example, PipelineTransformPhase, so the custom target looks like:
<Target Name="Mytarget2" AfterTargets="PipelineTransformPhase">
<Error Text="he name of the publish profile is $(DestinationAppRoot)">
</Error>
</Target>
Hope this helps.

TFS - Run Powershell script against package before Deployment

I currently have a CI Setup in TFS 2013 which does the following
Pulls code down from Git on every commit to a branch
Builds the Solution
Runs N-Unit Tests Against the solution
Runs Jasmine Front-end Tests against the javascript
Deploys on success via WebDeploy to chosen server.
I have now managed to install Grunt and NodeJS on the server to do some manipulation of the Javascript between steps 5-6. Does anyone have any advice on how this might be done?
I've tried post-tests scripts to minify the javascript successfully on both the src and bin/_PublishedWebsites directory but this does not seem to persist over to the deployment server. And infact, the _PublishedWebsites route puts the build folder in an undeletable state due to maxmimum character limits on Windows files (argh).
You should switch over to using Release Management for Visual Studio 2013 (works with 2012 as well). This allows you to parameterize your release and push the same output through multiple environments. Very configurable and even makes sure that the tools you need end up on the server that you are deploying to. Supports Puppet, Chef, DSC, and create your own.
http://nakedalm.com/installing-release-management-server-tfs-2013/
And for an overview: http://nakedalm.com/building-release-pipeline-release-management-visual-studio-2013/
I managed to get this working with the addition of two extra steps to the pubxml file used for the deployment.
First, i added a dependency powershell script which ran NPM install and grunt tasks.
<PipelineDependsOn>
CustomBeforePublish;
$(PipelineDependsOn);
</PipelineDependsOn>
<Target Name="CustomBeforePublish">
<Exec Command="powershell.exe -ExecutionPolicy Unrestricted -file Pre_Deploy_Javascript_Build.ps1 $(ProjectDir)"/>
</Target>
Following this. I had now created additional files which did not exist in the project. I had to now ensure that these were published. To do this, i added another step.
<CopyAllFilesToSingleFolderForMsdeployDependsOn>
CopyMinJSFiles;
$(CopyAllFilesToSingleFolderForMsdeployDependsOn);
</CopyAllFilesToSingleFolderForMsdeployDependsOn >
<Target Name="CopyMinJSFiles">
<ItemGroup>
<_MinJSFiles Include="$(ProjectDir)\App\*.js" />
<FilesForPackagingFromProject Include="%(_MinJSFiles.Identity)">
<DestinationRelativePath>App\%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>

TFS2010 Build Definition to Deploy to multiple servers?

I've been looking into TFS2010 new build and deployment features with MSDeploy. So far everything is going well (although its been hard to find information about specific scenarios).
Can I modify my Build Definition to specify 2 or more servers to deploy to? What I need to do is deploy to multiple servers (as I have two in my testing environment which uses a NLB).
What I have now is a Build definition which Builds, runs my tests, and then Deploys to ONE of my testing servers (which has the MsDeployAgentService running on it). It works fine, and each web project is deployed as configured in its project file. The MSBuild Arguments I use are:
* /p:DeployOnBuild=True
* /p:DeployTarget=MsDeployPublish
* /p:MSDeployServiceURL=http://oawww.testserver1.com.au/MsDeployAgentService
* /p:CreatePackageOnPublish=True
* /p:MsDeployPublishMethod=RemoteAgent
* /p:AllowUntrustedCertificated=True
* /p:UserName=myusername
* /p:Password=mypassword
NB: I dont use /p:DeployIISAppPath="xyz" as it doesnt deploy all my projects and overrides my project config.
Can I add another build argument to get it to call more than one MSDeployServiceURL? Like something like a second /p:MSDeployServiceURL argument that specifies another server?
Or do I have to look for another solution, such as editing the WF?
I saw an almost exact same question here posted 2 months ago: TFS 2010 - Deploy to Multiple Servers After Build , so it doesn't look like I'm the only one trying to solve this.
I also posted on the IIS.NET forums where MSDeploy is discussed: http://forums.iis.net/t/1170741.aspx . It's had quite a lot of views, but again, no answers.
You don't have to build the project twice to deploy to two servers. The build process will build a set of deployment files. You can then use the InvokeProcess to deploy to multiple servers.
First create a variable named ProjectName. Then add an Assign activity to the "Compile the Project" sequence. This is located in the "Try to Compile the Project" sequence. Here are the properties of the Assign:
To: ProjectName
Value: System.IO.Path.GetFileNameWithoutExtension(localProject)
Here are the properties of our InvokeProcess activity that deploys to the test server:
Arguments: "/y /M:<server> /u:<domain>\<user> /p:<password>"
FileName: String.Format("{0}\{1}.deploy.cmd", BuildDetail.DropLocation, ProjectName)
You will need to change <server>, <domain>, <user>, and <password> to the values that reflect your environment.
If you need to manually deploy to a server you can run the command below from your build folder:
deploy.cmd /y /M:<server> /u:<domain>\<user> /p:<password>
I couldn't find the solution I was looking for, but here's what I came up with in the end.
I wanted to keep the solution simple and configurable within the TFS arguments while at the same time staying in line with the already provided MSBuildArguments method which has been promoted a lot. So I created a new Build Template, and added a new TFS WorkFlow Argument called MSBuildArguments2 in the Arguments tab of the WorkFlow.
I searched through the BuildTemplate WorkFlow for all occurances of the MSBuildArguments (there were two occurances).
The two tasks that use MSBuildArguments are called Run MSBuild for Project. Directly below this task, I added a new "If" block with the condition:
Not String.IsNullOrEmpty(MSBuildArguments2)
I then copied the "Run MSBuild for Project" task and pasted it into the new If's "Then" block, updating its title accordingly. You'll also need to update the new Task's ConmmandLineArguments property to use your new Argument.
CommandLineArguments = String.Format("/p:SkipInvalidConfigurations=true {0}", MSBuildArguments2)
After these modifications, the WorkFlow looks like this:
Save and Check In the new WorkFlow. Update your Build Definition to use this new WorkFlow, then in the build definition's Process tab you will find a new section called Misc with the new argument ready to be used. Because I'm simply using this new argument for deployment, I copied the exact same arguments I used for MSBuild Arguments and updated the MSDeployServiceURL to my second deployment server.
And that's that. I suppose a more elegant method would be to convert MSBuildArguments into an array of strings and then loop through them during the WorkFlow process. But this suits our 2 server requirements.
Hope this helps!
My solution to this is a new Target that runs after Package. Each project that needs to produce a package includes this targets file, and I chose to make the Include conditional on an externally-set "DoDeployment" property. Additionally each project defines the DeploymentServerGroup property so that the destination server(s) are properly filtered depending on what kind of project it is.
As you can see towards the bottom I'm simply executing the command file with the server list, pretty simple.
<!--
This targets file allows a project to deploy its package
As it is used by all project typesconditionally included from the project file
-->
<UsingTask TaskName="Microsoft.TeamFoundation.Build.Tasks.BuildStep" AssemblyFile="$(TeamBuildRefPath)\Microsoft.TeamFoundation.Build.ProcessComponents.dll" />
<!-- Each Server needs the Group metadatum, either Webservers, Appservers, or Batch. -->
<Choose>
<When Condition="'$(Configuration)' == 'DEV'">
<ItemGroup>
<Servers Include="DevWebServer">
<Group>Webservers</Group>
</Servers>
<Servers Include="DevAppServer">
<Group>Appservers</Group>
</Servers>
</ItemGroup>
</When>
<When Condition="'$(Configuration)' == 'QA'">
<ItemGroup>
<Servers Include="QAWebServer1">
<Group>Webservers</Group>
</Servers>
<Servers Include="QAWebServer2">
<Group>Webservers</Group>
</Servers>
<Servers Include="QAAppServer1">
<Group>Appservers</Group>
</Servers>
<Servers Include="QAAppServer2">
<Group>Appservers</Group>
</Servers>
</ItemGroup>
</When>
</Choose>
<!-- DoDeploy can be set in the build defintion -->
<Target Name="StartDeployment" AfterTargets="Package">
<PropertyGroup>
<!-- The _PublishedWebsites area -->
<PackageLocation>$(WebProjectOutputDir)_Package</PackageLocation>
<!-- Override for local testing -->
<PackageLocation Condition="$(WebProjectOutputDirInsideProject)">$(IntermediateOutputPath)Package\</PackageLocation>
</PropertyGroup>
<Message Text="Tier servers are #(Servers)" />
<!-- A filtered list of the servers. DeploymentServerGroup is defined in each project that does deployment -->
<ItemGroup>
<DestinationServers Include="#(Servers)" Condition="'%(Servers.Group)' == '$(DeploymentServerGroup)'" />
</ItemGroup>
<Message Text="Dest servers are #(DestinationServers)" />
</Target>
<!-- Only perform the deployment if any servers fit the filters -->
<Target Name="PerformDeployment" AfterTargets="StartDeployment" Condition="'#(DestinationServers)' != ''">
<Message Text="Deploying $(AssemblyName) to #(DestinationServers)" />
<!-- Fancy build steps so that they better appear in the build explorer -->
<BuildStep
TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
BuildUri="$(BuildUri)"
Message="Deploying $(AssemblyName) to #(DestinationServers)...">
<Output TaskParameter="Id" PropertyName="StepId" />
</BuildStep>
<!-- The deployment command will be run for each item in the DestinationServers collection. -->
<Exec Command="$(AssemblyName).deploy.cmd /Y /M:%(DestinationServers.Identity)" WorkingDirectory="$(PackageLocation)" />
<BuildStep
TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
BuildUri="$(BuildUri)"
Id="$(StepId)"
Status="Succeeded"
Message="Deployed $(AssemblyName) to #(DestinationServers)"/>
<OnError ExecuteTargets="MarkDeployStepAsFailed" />
</Target>
<Target Name="MarkDeployStepAsFailed">
<BuildStep
TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
BuildUri="$(BuildUri)"
Id="$(StepId)"
Status="Failed" />
</Target>
I am the author of the other similar post. I have yet to find a solution. I believe it is going to be modifying the workflow to add a postprocessing MSBUILD -sync task. That seems to be the most elegant, but was still hoping to find something a bit less intrusive.
I'm not sure if that could help you with TFS 2010, but I have a blog post for TFS 2012: Multiple web projects deployment from TFS 2012 to NLB enabled environment.