I have an ASP.NET project and I want to implement CI-CD using Azure pipelines, to deploy to custom server (IIS).
Currently, when using Visual Studio(2019) to publish web application manually, I am using these options for publish profile:
<PropertyGroup>
<WebPublishMethod>FileSystem</WebPublishMethod>
<PublishProvider>FileSystem</PublishProvider>
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<SiteUrlToLaunchAfterPublish />
<LaunchSiteAfterPublish>True</LaunchSiteAfterPublish>
<ExcludeApp_Data>True</ExcludeApp_Data>
<publishUrl>C:\Test</publishUrl>
<DeleteExistingFiles>True</DeleteExistingFiles>
<PrecompileBeforePublish>True</PrecompileBeforePublish>
<EnableUpdateable>False</EnableUpdateable>
<DebugSymbols>False</DebugSymbols>
<WDPMergeOption>MergeEachIndividualFolder</WDPMergeOption>
<UseMerge>True</UseMerge>
</PropertyGroup>
The main thing that I want to achieve, is implementing <WDPMergeOption>MergeEachIndividualFolder</WDPMergeOption> when deploying using build and release pipeline.
For release pipeline, I am using IIS Web Deployment.
For build pipeline agent sepcification, I am using vs2017-win2016
For build solution task, I am using latest version of visual stidio
Things I've tried:
1. Passing configuration arguments to msbuild, for Build Solution task in azure build pipeline:
/p:PackageAsSingleFile=true /p:PackageLocation="$(build.artifactstagingdirectory) /p:OutputPath=bin
/p:DeployOnBuild=true /p:WebPublishMethod=FileSystem /p:PrecompileBeforePublish=true
/p:EnableUpdateable=false /p:DebugSymbols=true /p:UseMerge=true /p:DeleteAppCodeCompiledFiles=True
/p:DeleteExistingFiles=True /p:WDPMergeOption=MergeEachIndividualFolder /p:UseFixedNames=true\\"
2. Uploading FolderProfile.pubxml , and passing arguments to msbuild to read from that file
It all builds and releases fine, but doesn't merge assemblies in release, as configured with merge options, it seems like msbuild ignores these additional merge arguments.
How can this be done, the main question is how can I use MergeEachIndividualFolder option when deploying with azure pipeline?
I've also searched a lot, but non of the questions seems to cover the solution.
Azure DevOps Build - publish doesn't create .compiled files in bin folder on publish
MSBuild commandline seems to ignore publish properties
The recommendation from Cece Dong - MSFT worked in my instance of using a publish profile.
Snippet below YML
- task: VSBuild#1
inputs:
solution: 'Path\MySolution.sln'
vsVersion: '16.0'
msbuildArgs: '/p:DeployOnBuild=true /p:PublishProfile=myProfile.pubxml'
configuration: 'Release'
Then in the output the build you can see it having the desired effect:
WebFileSystemPublish:
Creating directory "C:\MyPublishPath".
Copying obj\Release\Package\PackageTmp\File1.ext to C:\MyPublishPath\File1.ext.
Copying obj\Release\Package\PackageTmp\File2.ext to C:\MyPublishPath\File2.ext.
Copying obj\Release\Package\PackageTmp\bin\File3.ext to C:\MyPublishPath\bin\File3.ext.
Copying obj\Release\Package\PackageTmp\bin\File4.ext to C:\MyPublishPath\bin\File4.ext.
... all other files included in the publish
Related
NuGet restore fails 404 from feed on another project in same organization.
When using nuget restore from a pipeline the feed inside a different project is not found.
After searching for a long time, these are the steps necessary to make it work consistently:
Setup permissions
Make sure to add Build Service of the consuming project to the permissions of the feed
Make sure the consuming project has these two settings disabled
Project settings (bottom left) --> Pipelines --> Settings
Limit job authorization scope to current project for non-release pipelines
Limit job authorization scope to current project for release pipelines
Setup build pipeline
Use the .Net Core CLI Task
Ideally you would use a nuget.config file and make sure to check it in
Set the feedsToUse to 'config'
azure-pipelines.yml
- task: DotNetCoreCLI#2
displayName: DotNetCore-Restore
inputs:
command: 'restore'
projects: '$(PathToSolution)'
feedsToUse: 'config'
nugetConfigPath: '$(PathToNugetConfig)/nuget.config'
includeNuGetOrg: true
nuget.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="feed_name" value="feed_url" />
</packageSources>
</configuration>
There is no need to add an authenticate task to the pipeline as the dotnet command does this by itself... However:
Most dotnet commands, including build, publish, and test include an
implicit restore step. This will fail against authenticated feeds,
even if you ran a successful dotnet restore in an earlier step,
because the earlier step will have cleaned up the credentials it used.
Source (.NET Core CLI task docs)
You can refer to this doc to setup Azure Artifacts Credential Provider for usage across various tooling.
Im trying to pack a web api i made in .net core 3.1 with Azure Pipeline.
- task: DotNetCoreCLI#2
displayName: Package NuGet
inputs:
command: 'pack'
projects: '**/*.csproj'
arguments: '--configuration $(BuildConfiguration)'
outputDir: '$(Build.ArtifactStagingDirectory)/packages'
Thats the task i used, i found it from another post on stack overflow.
My only issue with that is that it gives a number of .nupkg files, instead of one, and that the web api packages doesn't have the dependencies dll.
Also i created a .nuspec file, but i don't seem to manage to use it correctly with Azure Pipeline
I've tried what's explained here : https://learn.microsoft.com/fr-fr/nuget/reference/msbuild-targets#packing-using-a-nuspec
or just by targeting the .nuspec file like it is explained on the tooltipe of pipeline
If anybody could put me on the right path that would be greatly appreciated :)
EDIT:
I want to pack everything in a nupkg to then deploy it for an IIS site.
This is my nuspec file :
<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>WebAPI</id>
<version>1.0.0</version>
<authors>Kevin Pinero</authors>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>WebAPI</description>
</metadata>
<files>
<file src=".\bin\Release\*\*.dll" target="lib" />
<file src=".\bin\Release\*\*.exe" target="lib" />
<file src=".\bin\Release\*\*.json" target="lib" />
<!-- <file src=".\bin\Release\*\Properties\*.json" target="lib" /> -->
<file src=".\bin\Release\*\*.pdb" target="lib" />
<file src=".\bin\Release\*\*.config" target="lib" />
</files>
</package>
And this the error i get on the pipeline :
error MSB4068: The element is unrecognized, or not supported
in this context.
Using this task :
- task: DotNetCoreCLI#2
inputs:
command: 'pack'
packagesToPack: '**/*API.nuspec'
nobuild: true
versioningScheme: 'off'
I know on microsoft website I could potentially use this command too
dotnet pack ~/projects/app1/project.csproj -p:NuspecFile=~/projects/app1/project.nuspec -p:NuspecBasePath=~/projects/app1/nuget
But i'm not sure how to translate it in AZ pipeline ...
EDIT Solution adopted:
I've decide to resolve my issues this way :
- task: DotNetCoreCLI#2
displayName: Build at solution level
inputs:
command: 'build'
projects: $(solution)
arguments: '--no-restore --configuration $(buildConfiguration)'
- task: DotNetCoreCLI#2
displayName: Execute tests
inputs:
command: 'test'
projects: $(testProjects)
arguments: '--no-build --configuration $(buildConfiguration)'
- task: DotNetCoreCLI#2
displayName: Pack project
inputs:
command: publish
projects: '**/projectName.csproj'
publishWebProjects: False
arguments: '--no-build --configuration $(BuildConfiguration) --output $(Build.ArtifactStagingDirectory)
zipAfterPublish: False
- task: PublishBuildArtifacts#1
displayName: Publish
inputs:
pathtoPublish: '$(Build.ArtifactStagingDirectory)'
artifactName: 'artefact name'
I would recommend to use the Azure DevOps online pipeline editor. It is great to use and get up to speed (auto-completion, syntaxic review, direct commit/push).
What you try to achieve can be done with the steps:
dotnet build
dotnet pack -> specify the right projects to be packed here
- task: DotNetCoreCLI#2
displayName: 'Create packed NuGet files'
inputs:
command: 'pack'
packagesToPack: '**/*Api.csproj;!**/*Tests.csproj'
versioningScheme: 'off'
nuget push
No need for a nuspec file as long as you add some fields in your csproj.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<AssemblyName>Withywoods.Selenium</AssemblyName>
<RootNamespace>Withywoods.Selenium</RootNamespace>
<ProjectGuid>{08D9DDB8-BF5B-4E45-8E0C-D9AC85ABF020}</ProjectGuid>
<Authors>devprofr</Authors>
<Description>Library to ease the use of Selenium web driver and provide testing best practices.</Description>
<RepositoryUrl>https://github.com/devpro/withywoods</RepositoryUrl>
<PackageProjectUrl>https://github.com/devpro/withywoods</PackageProjectUrl>
</PropertyGroup>
I have a short example here if you want: pkg.yml
.NET Core and Azure DevOps is a great combination, feel free to comment if you have any issues!
(On my side, I pack library projects but not Api, I do dotnet publish on Api to use them as artifact in release pipelines.)
My only issue with that is that it gives a number of .nupkg files,
instead of one, and that the web api packages doesn't have the
dependencies dll.
I assume you have more than one projects in same solution. Let's call the Web Api project A, other projects B, C and D...
1.So if you only want to pack A into nuget package, instead of using projects: '**/*.csproj', we can use something like projects: '**/A.csproj'. Then it won't pack a number of nuget packages any more.
2.For the dependencies dll, I think you mean the project references like Josh Gust said above. For this, it's still one open issue about dotnet pack command. You can track that issue there to get notifications if there's any update.
For now, we have to make changes to A.csproj to use msbuild magics as workaround. You can try Martin's or zvirja's workarounds there. In my opinion, they both helps for your issue.
Hope all above helps :)
Update1:
For your edit, if you want to translate it in AZ pipeline, you can use the custom command to call the pack. Something like this:
- task: DotNetCoreCLI#2
displayName: 'dotnet custom'
inputs:
command: custom
projects: '**/ProjectName.csproj'
custom: pack
arguments: '-p:NuspecFile=~/projects/app1/project.nuspec -p:NuspecBasePath=~/projects/app1/nuget'
You can check the log to confirm it actually ran the command: "C:\Program Files\dotnet\dotnet.exe" pack D:\a\1\s\xxx\xxx.csproj -p:NuspecFile=~/projects/app1/project.nuspec -p:NuspecBasePath=~/projects/app1/nuget. Hope that's what you need.
And I'm not certainly sure that we can use ~ in that command, but if it works locally, then you can translate it in Azure Devops Pipeline using my way...
UPDATE
Because you are trying to package a Web API project for delivery to IIS, you should stop trying to use nuget as that mechanism, and instead use the dotnet publish command. If you want to continue to use the DotNetCoreCLI#2 task (as opposed to using the script shortcut to call the dotnet cli directly), then I would point you to the documentation to Build, Test and Deploy .Net Core Apps.
This documentation is not written specifically for Web API projects, but is a set of generic guidelines for operating with .Net Core Apps is Azure DevOps Pipelines. An example is quoted below (emphasis mine):
After you've built and tested your app (not web api specifically), you can upload the build output to Azure Pipelines or TFS, create and publish a NuGet package, or package the build output into a .zip file to be deployed to a web application.
When you read in the Package and Deliver your Code section that publish to a NuGet feed is a valid option for delivering code, it is. However this method of delivery should be used for library type deliverables. The dotnet publish command is what is designed to package a web api project and all its dependencies into a .zip (or folder if you specify that option) in preparation for Web Deploy commands against an IIS instance.
Original Answer
Without getting into the details of why you want to create a .nupkg from your API project.
You mention:
My only issue with that is that it gives a number of .nupkg files, instead of one, and that the web api packages doesn't have the dependencies dll
This has been the MO of dotnet pack for a while now as regards project-to-project (P2P) references.
The documentation for dotnet pack states this behavior.
NuGet dependencies of the packed project are added to the .nuspec file, so they're properly resolved when the package is installed. Project-to-project references aren't packaged inside the project. Currently, you must have a package per project if you have project-to-project dependencies.
If you want to have more control over the files that are included in your .nupkg then you will want to author a .nuspec file manually and provide it to the dotnet pack command as indicated in the last Example on the documentation page.
Using the Azure DevOps task for the dotnet core cli DotNetCoreCLI#2 should allow you to simply put the path to the .nuspec file in the input. More information will be necessary in your question if this isn't working for you.
My setup is: I have a solution that had different dotnet4.6 applications (services) in it. Now we added a dotnet core project inside this solution. I can build and debug it, but this doesn't create an executable. In Visual Studio I can rightclick -> Publish... it. I created two profiles (x86 and x64) that should create nice binaries in /bin/Publish/x86 or /x64. In VS this works. The application is self-contained and works on different unprepared machines.
But now I Need to move that process to the buildserver. I messed around with dotnet publish but in the end i get stuck because other components of the solution are not clean dotnet core and so the build fails.
So I need to stick with MSBuild.
The current attempt is:
"C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\MSBuild\15.0\Bin\MSBuild.exe" NewProject\NewProject.csproj /p:DeployOnBuild=true /p:UsePublishProfile=true /p:PublishProfile=x64Profile.
This says it finished building successfully, but I don't see any results. Also it doesn't make any difference, if I remove all properties and just call msbuild and *.csproj. It just builds the new project in bin/Debug, as dll, not exe.
I also messed around with p:PublishProfile="NewProject\Properties\PublishProfiles\x64Profile.pubxml" and /p:PublishUrl="NewProject\bin\Publish\x64" but it doesn't change anything.
I read a few articles on SO, telling that VS doesn't just call msbuild with parameters but does internal API calls. Still, I need a solution. I need the build server to create an executable. Is there a way to trigger msbuild to create thath?
Oh man, I searched for 2-3 days now. And - as always on StackOverflow - shortly after asking I found a working answer myself.
tl;dr:
Project.csproj:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>netcoreapp2.1</TargetFrameworks>
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<RootNamespace>Company.Toolset.Exporter</RootNamespace>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
<RuntimeIdentifiers>win-x86;win-x64</RuntimeIdentifiers>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v15.0\WebApplications\Microsoft.WebApplication.targets" />
...
MSBuild command:
msbuild Project\Project.csproj -t:restore /t:Build;Publish /p:Configuration=Release /p:Platform=x86 /p:PublishProfile=x86Profile /p:OutputPath=bin/Publish/x86 (and the same for x64)
Explanation:
I think it was the dotnet build/publish command that wanted me to change TargetFrameworks to TargetFramework. But for MSBuild this is wrong. And dotnet wasn't working here, as the solution is mixing dotnet core and dotnet framework. So that had to be fixed.
The <RuntimeIdentifiers>win-x86;win-x64</RuntimeIdentifiers> was needed by the command. I added it to the *.csproj because I know that I build for windows only (at the moment) and that I need both versions.
I don't really know why I needed this line <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v15.0\WebApplications\Microsoft.WebApplication.targets" /> but without this publishing and using the PublishProfiles didn't work as expected.
Links that helped me to get here: (not sorted)
https://github.com/Microsoft/msbuild/issues/1901
https://github.com/aspnet/vsweb-publish/issues/22
How to Publish Web with msbuild?
ASP.NET Core Application (.NET Framework) for Windows x64 only error in project.assets.json
Configure MSBuild output path
I too had a nightmare with inconsistencies between builds from Visual Studio IDE and the dotnet publish command, that were only fixed by doing it using msbuild.exe instead. Also, using /p:PublishProfiles=theXMLthatVSgenerates.xml never worked, so I had to break out every option into the msbuild command line.
Here's what worked for me:
"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\msbuild.exe" C:\Users\xxxx\Source\Repos\netcore-agent1\CoreAgent1\CoreAgent1.csproj /t:Restore;Rebuild;Publish /p:PublishSingleFile=True /p:SelfContained=True /p:PublishProtocol=FileSystem /p:Configuration=Release /p:Platform=x64 /p:TargetFrameworks=netcoreapp3.1 /p:PublishDir=bin\Release\netcoreapp3.1\publish\win-x64 /p:RuntimeIdentifier=win-x64 /p:PublishReadyToRun=False /p:PublishTrimmed=False
I want the application to be deployed to a local folder when I build the project. This should produce a zip file that I can use to import in IIS. How can I achieve this?
Command line
msbuild yoursolutionfile.sln /p:DeployOnBuild=true
/p:WebPublishMethod=Package
/p:PackageAsSingleFile=true
/p:PackageLocation="yourpath\yourfilename.zip"
DeployOnBuild tells msbuild to deploy (to package location)
WebPublishMethod Creates a deployment package. You can choose other options for web publish like file copy.
PackageAsSingleFile zips the output
Above is all ran at the command line and while not in VS to do it, does build and deploy in one step. You could have a command window open where you run this command whenever you want to.
IN VS
You can use the Web Deployment Publish Wizard in VS. It's in the Build Menu. It will walk you through the steps for this as well.
However, this is only after the build occurs and is a second step.
To do it all at once, well, web publish on build via VS is not "supported". As in, not an easy way to do it. You could run the cmd I showed in the post-build but that literally means a second recompile and I think that's a horrible idea, so don't unless this is a really small project and even then, no, ok maybe.
In VS in one step
Back to MSBUILD but with changing the project file's xml (msbuild commands).
First create your publish profile (the file created by the publish wizard). This essentially creates the settings for msbuild from my first example but saves it to a file.
Then edit your project file (csproj) as described by #richardSzalay or #chief7
The csproj file is the msbuild commands that VS uses. In those examples, you create some properties (propertygroup) to setup the deployment and an AfterBuild target to run the publish.
Find the below property groups from the csproj:
<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>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
First one is for debug and the second for release.
Add the following inside both property groups (If you want the auto build to happen in both debug and release mode).
<DeployOnBuild>true</DeployOnBuild>
<PublishProfile>Server</PublishProfile>
It will now auto publish for both Visual studio build and MSBuild.
I'm trying to create a release definition inside VSTS to deploy my ASP.NET Core 2.0 app on my production server.
I'm using the MSDeployAllTheThings extension: https://marketplace.visualstudio.com/items?itemName=rschiefer.MSDeployAllTheThings
I'm able to deploy inside Visual Studio using the same configuration...
VSTS Config (not working)
VSTS Error
Visual Studio Config (working)
Do you guys have any ideas how to do that?
I had the same problem with deployment to smarterasp.net and was able to setup things for Web Deploy:
Your Dotnet Build task could create deployment package with necessary files like [YourProject].deploy.cmd, [YourProject].zip and etc. For this you could use next Arguments in your Build Task:
--configuration $(BuildConfiguration) /p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:PackageLocation="$(build.artifactstagingdirectory)\"
Add "Batch script" task and set path to your [YourProject].deploy.cmd in Path field and also in your Arguments:
/y /m:$(SmarterAspNet.PublishUrl) -AllowUntrusted /u:$(SmarterAspNet.UserName) /p:$(SmarterAspNet.Password) /a:Basic "-setParam:name='IIS Web Application Name',value='$(SmarterAspNet.SiteName)'" -enableRule:AppOffline
With this two main DevOps tasks I was able to deploy my app to smarterasp.net
About MSDeployAllTheThings task: I removed it because it is not needed for me anymore
Not familiar with smarterasp.net. But this should be an issue with that site.
If you run the same msdeploy command from your local machine manually, you will get the same error message. We didn't see this error when use the same command to deploy to some other host instead of smarterasp.net. And if you add "-verbose" in the command, you will get a more detailed information which indicates that the command failed to adding the virtual path:
When you deploy your project from VS, it use the manifest file and source folder directly rather than "package" method. So you'd either contact smarterasp.net for help or use the same deploy method as Visual Studio or some other deploy method like FTP.