I need to be able to generically and separately build and publish C# ASP.NET Web Applications. Ideally, I would like to use MSBuild to build the application, and if that succeeds, I would like to simply publish the site preferably solely with file copy.
Currently, I am able to build web application quite easily with MSBuild, but it is the publishing that is causing confusion. After the build, the binaries sit in the bin folder, but I am not sure what files to copy. What would be a good way to mimic the operations that VS's publish feature does, and still keeping everything generic?
You can invoke the Visual Studio web publish pipeline using the command line, check out this tutorial it shows you step by step how to do it:
Specifying the publish profile
You can specify the publish profile by name or by the full path to the .pubxml file, as shown in the following example:
msbuild C:\ContosoUniversity\ContosoUniversity.sln /p:DeployOnBuild=true /p:PublishProfile=C:\ContosoUniversity\ContosoUniversity\Properties\PublishProfiles\Test.pubxml
Web publish methods supported for command-line publishing
Three publish methods are supported for command line publishing:
MSDeploy - Publish by using Web Deploy.
Package - Publish by creating a Web Deploy Package. You have to install the package separately from the MSBuild command that creates it.
FileSystem - Publish by copying files to a specified folder.
http://www.asp.net/mvc/tutorials/deployment/visual-studio-web-deployment/command-line-deployment
The latest projects can be built by:
dotnet build MyWebsite.sln
For more info please refer the microsoft docs: https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-build
Note: Old ASP.NET projects are not supported. Please use MsBuild instead https://stackoverflow.com/a/24063993/1143349.
Related
We have two build servers and a newly created project has decided that it only wants to build successfully on one of them. It gives this error on the build server on which it fails:
MyLovelyNewProject.csproj(380,11): error MSB4226: The imported project "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\MSBuild\Microsoft\VisualStudio\v15.0\WebApplications\Microsoft.WebApplication.targets" was not found. Also, tried to find "WebApplications\Microsoft.WebApplication.targets" in the fallback search path(s) for $(VSToolsPath) - "C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v15.0" . These search paths are defined in "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\MSBuild\15.0\Bin\amd64\MSBuild.exe.Config". Confirm that the path in the declaration is correct, and that the file exists on disk in one of the search paths.
Our DevOps guy investigated and determined that one server has the v15.0 build tools and one of them has the v15.9 build tools. The new project fails to build on the server that has the v15.9 build tools, since it's specifically looking for the v15.0 build tools.
All of our other projects build just fine on both build servers, but I wasn't able to find anything in their .sln or .csproj files that looked different from the new project. How can I retarget/reconfigure the new project so that it will build successfully regardless of which version of the build tools a given server has?
(If you want to suggest that DevOps synchronize the build servers to have the same version of the build tools, I agree! Alas, they're busy with a major server migration, and I would like the new project to not have a 50% chance of failing in CI while they're getting around to it.)
I think the issue is related to the Build Tool v15.9 rather than your projects. On that Server, you did not install the build workload for web projects on V15.9 Build Tool so that it cannot specify the web projects and lack the ability to build web projects. Or, the build tool is broken due to some reasons.
You could try the following steps:
1) try to open the vs_installer, click Modify
And select Web development build tools workload to install, also, if you have a asp net core web projects, do not forget to install .Net Core build tools workload.
To ensure this, I remove the web development build tools workload, and get the same issue for web project.
2) If it does not help, please click Repair for Build Tool V15.9 to repair it.
We are in the process of implementing a DevOps strategy for our client deployed desktop app (winforms). Until now, we used SlowCheetah to do our config transforms (ex: select QA from config manager, app.QA.config is automatically swapped in, do the build, deploy MSI to QA machines with SCCM).
We are trying to leverage Azure DevOps to automate this process and I have run into a roadblock. I want to do 1 build, and a release pipeline of Dev --> QA --> UA --> Prod, but since the config transform is only run on build Im not sure how to do this.
The MSI would only be generated for the current selected config, so the drop in the release step would only have 1 MSI (with the config already packaged and no way to change it).
I know having the build step build the solution 4 times (one for each config) would work - the drop would contain all 4 MSIs, but that seems silly.
I can't just build the setup project on the release pipeline either as only the DLLs are available in the Drop, not the project files. How can I accomplish this?
Thanks!
We had exactly the same problem building MSIs from a Visual Studio solution that contained a WiX Installer project, using config transforms on the app.config to replace the configuration.
As you suggested, we originally went down the route of running an Azure DevOps build pipeline with multiple builds for every configuration in the solution, but this quickly became inelegant and wasteful as not only did we require builds for (dev/stage/qa/live) but also had configurations that applied to multiple customers, which ended up in 12 + configurations in the solution and really long build times.
Replace config within the MSI
The solution we ended up with, as alluded to in a previous answer, was to build the MSI only once in a build pipeline, copy the MSI along with all our replacement app.config files to the drop folder, and then run a custom application within the release pipelines to forcibly replace the Application.exe.config inside the MSI. Unfortunately, this isn't as simple as just 'unzipping the MSI', replacing the config and then 're-zipping' within a release task because the MSI uses a custom file format and maintains an internal database that needs to be modified properly.
We ended up creating a custom C# .NET console application using the method posted in this stack overflow answer, which we then hosted on our on-premises build agent so that we could run a simple powershell task within our release pipeline that called our custom console application with some relevant parameters:
"C:\BuildTools\msi_replace_file.exe" -workingfolder "$(System.DefaultWorkingDirectory)/_BuildOutput/drop/Application.Installer/bin/Release/" -msi "Application.Installer.msi" -config "Application.exe.config"
We then had a release pipeline stage for each 'configuration' that performed these basic steps:
There are various other methods for replacing a file in an MSI, as described in this question, but we chose to create a C# application using the utilities within the Microsoft.Deployment.* namespace that are provided as part of the WiX Toolset. This would guarantee compatibility with the version of WiX we were using to build our installer in the first place and gave us full control of the process. However, I appreciate that this approach is quite brittle (which I'm not happy about) and not especially scalable as its relying on a custom tool to be hosted on our on-premises build agent. I intend to improve this in the future.
You should also be aware that hacking the MSI in this way could cause problems in the future, especially if you change your tool-chain or upgrade to a later version of WiX.
Building the MSI from the release pipeline
I do not personally like the idea of copying the required dlls/assets to the drop location and then 'building' the MSIs within the release pipeline, because for us the act of building the WiX project was very much part of our 'build process' and was integrated into our visual studio solution, so it felt like moving the creation of the MSI to the release pipelines was counter intuitive and would also potentially require us to create custom tasks on the build agents to run the WiX CLI tools (heat.exe, light.exe, candle.exe) against a version of our WXS file or have build steps that just built the wixproj file instead of the whole solution. However, I can see how this alternative approach may be suitable for others and I think is equally valid depending on your circumstances.
What we did a few years back is maintaining a sub-folder that contains all the environment config files. Using a Custom Action at install time and supplying that particular environment on the command line the custom action would extracts the config file from the environment matching folder in the configFils.zip.
Folder structure similar to this in the ConfigFiles.zip file.
/Dev1/app.config
/Dev2/app.config
/Prod/app.config
MsiExec.exe /i YourMSI.msi /TargetDir=C:\Yourfolder /Config=Prod
Custom action would extract and place the app.config from the Prod folder.
To do this in the release pipeline you've really only got a couple of choices:
Break the MSI apart and re-import the right config and repackage (don't know how easy this would be as I don't know MSI, but have taken this approach with other packages which are effectively .zip)
Build the package in the release pipeline. You say the files aren't available in the drop but you are in control of this from your build pipeline (assuming this was done with Azure Pipelines also). You can either change your pipeline therefore to copy the needed files (with a copy task) into the place you create your drop from which is usually $(build.artifactstagingdirectory). Alternatively if you don't want to mix these files into your drop you can create a second artifact drop (just put in another publish artifact task in for this). If I took this route I would copy the files that are in $(build.artifactstagingdirectory) today into $(build.artifactstagingdirectory)/packagefiles and the project files needed to package up the MSI into $(build.artifactstagingdirectory)/projectfiles and point the two publish artifacts tasks to either one of these directories.
Once you have the drops including the files to build your MSI you'll need tasks to replace in the right config and then an MSI packaging task and you should be done.
Another way of doing this:
Instead of placing environment dependent settings in the App.config or any of its transforms, you could configure your app dynamically at runtime.
This would however require your app to get some clue from the target system so that it knows in which environment or on which host it is running.
Example:
ASP.NET Core applications assume the existence of a „ASPNETCORE_ENVIRONMENT“ environment variable. If it is not present, the applications assumes it runs in production.
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/environments?view=aspnetcore-5.0
Providing such an environment variable should‘t pose a problem when you have access to the hosts anyway.
Simply add a step at the beginning of your release pipeline to set up the environment variable and set its value to the name of the stage you’re trying to deploy to (development/testing/etc).
That way you can build your MSI once in the build pipeline and deploy on as much environments as you like.
Of course, this requires you to prepare your app for that target environment ahead of time.
I already know about the .NET Core 'publish' command and how to publish for different platforms. E.g.:
dotnet publish -c Release -f netcoreapp2.0 -r win10-x64
However, I was wondering is there a way to specify those parameters directly in a .csproj file ?
(I am aware of <RuntimeIdentifier>property, but using this, a published app is not standalone, and more importantly, any native libraries residing in the 'runtimes/(OS)/native/' are not copied.)
Am I missing something ?
----------------------
Edit:
How can I deploy an standalone .NET Core app using VS IDE (to produce the same output as the command I wrote before (dotnet publish ...), preferably by modifying csproj file ?
The question seems to be a clone of: Publish .net core app from VS 2017 (apologize, have not seen that earlier).
No, publish details can't be stored in csproj. If you create a publishing profile in Visual Studio, the details are saved in pubxml and pubxml.user files stored in the Properties\PublishProfiles folder inside the project folder.
The contents of pubxml vary depending on the publish target (for example, Azure versus local folder), and they aren't documented. It seems Microsoft really just wants you to create them through Visual Studio. The most recent docs I can find here even carry the following warning:
The .pubxml file shouldn't be checked into source control because it depends on the .user file. The .user file should never be checked into source control because it can contain sensitive information and it's only valid for one user and machine.
That doesn't strike me as very enterprise- or teamwork-friendly, where you'd probably want to standardize publish settings, but it's what we have today. The other reason this seems odd to me is that the profiles contain a lot of settings that can only be modified by hand (for example, the Azure website profiles have <LaunchSiteAfterPublish> set to true, which is a pretty annoying default if your site runs under a different URL).
The github repo for all of this stuff is aspnet/websdk.
If you really want to stick to the command line (as someone who grew up with no alternatives, I really don't understand that trend), you can reference an existing publishing profile this way:
dotnet publish WebApplication.csproj /p:PublishProfile=<FolderProfileName>
Does anyone have any insight as to why Visual Studio 2017 has a check box that enables Docker support for ASP.NET Core for Empty, Web API, Web Application and Web Application (MVC) templates, but not for the SPA templates Angular, React.js, or React.js and Redux?
Are there any resources showing how to add Docker support to these SPA templates? My google-fu is strong, but I can't find any.
I'm not sure why that checkbox is disabled when selecting the template during project setup. However, you can still add Docker support by doing the following:
Setup project
Right click project in the solution explorer
Hover over add
Click Docker support
What this will do is create some docker-compose files and a single Dockerfile that basically just uses dotnet CLI to run the publish command on the solution. There's nothing specific about the frontend code. By default, when using those templates, the webpack build information is put into the .csproj file. You can learn more about the Add Docker Support feature here.
Below is how to add docker support on Visual Studio for Mac 2017, but it works the same on Windows.
The reason you are seeing that error is that for SPA projects, the csproj contains commands to run steps defined in the package.json to do packaging (ng build, webpack, etc.). And that requires Node to be INSIDE the build container that needs to be added explicitly. You will have to ensure that the Node version you use in the container will work with the build image that you have chosen. Most times it should not be an issue, but in case it is at least you are now aware.
You will need to add the following to the Dockerfile after the dotnet build and before the dotnet publish steps as below. My example uses Node 10.13 since that is what is supported by the build image that we pull for Azure Container deployments.
RUN dotnet build ...
# **** Adding Node - Start
ADD https://nodejs.org/dist/v10.13.0/node-v10.13.0-win-x64.zip "C:\build\node-v10.13.0-win-x64.zip"
RUN PowerShell Expand-Archive C:\build\node-v10.13.0-win-x64.zip C:/
RUN PowerShell Rename-Item C:\node-v10.13.0-win-x64 node
RUN SETX PATH C:\node
ENTRYPOINT C:\node\node.exe
# **** Adding Node - End
FROM build AS publish
RUN dotnet publish ...
I changed jobs this year, so due to that i switched from Java to C#.In both jobs I work/worked on a large application that is deployed to a server and exposes various webservices.
With the Java job, an ant build process created a .ear file that contained a .war file and other objects. This .ear file was deployed by copying it into a directory within a JBoss/tomcat server. I understood the process fairly well.
With the C# job, I press a green triangle "play" button in Visual Studio and the application is compiled and somehow deployed to IIS, and Visual Studio then starts up a web browser pointing to the application's URL. I don't completely understand what is happening under the hood during this process. We have a build server that creates production builds that go out to production servers, but I don't understand a) what artifacts are produced by the build process, and b) how are those build artifacts deployed to IIS.
I would like to understand the process well enough to manually drive builds and deployments, re-automate the process, and also troubleshoot and modify our existing build and deploy process. I can drive a build with msbuild, but what does that produce, and how would I get it deployed onto another machine's IIS installation?
What happens when you hit Run (the green triangle) is probably not the best example, because it is using a specialized form of IIS (sometimes called Cassini) hosted within Visual Studio with a debugger attached.
To get a clearer picture of what happens when deploying, use the Publish tool to deploy to a folder on your desktop. In that folder you will see what is essentially the web root. Your project, minus any code files, and a bin directory with the compiled binaries.
Typically only static files such as html, css, and png, etc. will be deployed, while any code files won't. By default Visual Studio "knows" which files to build into the binary, and which to simply copy to the output folder (and which to ignore). But you can change this in cases where you need to override that behavior, or you have a file type VS doesn't know about. In your solution explorer, right click on a file, select properties. In the properties window for that file you'll see "build action", which shows what VS will do with that file.
Hope that helps.
Just add a note.
So,
If you are working with ASP.NET Website, it should enough to manually copy it to publish folder
If you are working with ASP.NET Web Application, so before publish it should be compiled. All compile operations is performed by MSBuild - command line utility to buld .net projects. But how MSBuild can understand, what it should build and in what way? Easy - there special files with instructions for MSBuild - is solution files (example howto build project from command line "C:\...\MSBuild.exe" /maxcpucount:10 MyAwesomeSolution.sln). Solution file contains references to project files (and build order for projects, etc), project files contains references to files, which included in project (and type of project - library/console/web app/etc, and framework version, and action for each file - build/content/resource, etc). If some file does not included to project, it will be ignored.
So, when you press green button, firstly VS will run MSBuild to build your solution. Inside solution should be written, which project will be used as starting point and what should be done before/after build. Inside project there information, howto debug project (via IIS, IIS express or smthg else).
So, when we working with some CI server, to compile our solution is enough to run MSBuild on CI server with path to solution. Ofcource, to publish compiled solution via CI, additional scripts should be written (to cpy files, etc).
Also, if you want to publish you website to some location, you can create "publish profile". It allows you to publis your website to IIS, FTP, etc, but you have to press "publish" button manually (right click on web project => publish)