Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Publish to IIS from withing Visual Studio using the GUI #21

Open
Kation opened this issue Sep 2, 2021 · 16 comments
Open

Support Publish to IIS from withing Visual Studio using the GUI #21

Kation opened this issue Sep 2, 2021 · 16 comments
Labels
enhancement New feature or request known limitation This issue is related to a known limitation and cannot currently be fixed.

Comments

@Kation
Copy link

Kation commented Sep 2, 2021

<Project>
  <Import Sdk="Microsoft.NET.Sdk.Publish" Project="Sdk.props" />

  <ItemGroup>
    <ProjectCapability Include="DotNetCoreWeb" />
    <ProjectCapability Include="Web" />
  </ItemGroup>
  <Import Sdk="Microsoft.NET.Sdk.Publish" Project="Sdk.targets" />
</Project>

Add this to enable publish to IIS feature

@CZEMacLeod
Copy link
Owner

@Kation Publish already works from the command line or build server. Is this to enable the publish command in visual studio?
I was aware of the Microsoft.NET.Sdk.Publish SDK type and it appears to include some of the logic and DLLs that are installed by visual studio and are currently pulled in by

<Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" />

I feel that adding the DotNetCoreWeb project capability is going to cause the razor editor and other ASP.NET Core features to enable and break working with ASP.NET 4 technologies.

Your example does not include the MSBuild.SDK.SystemWeb so will miss out a lot of the other features and requirements for ASPNET 4.

Have you tried the following?

<Project>
  <Import Sdk="MSBuild.SDK.SystemWeb/4.0.33" Project="Sdk.props" />
  <Import Sdk="Microsoft.NET.Sdk.Publish" Project="Sdk.props" />

  <ItemGroup>
    <ProjectCapability Include="DotNetCoreWeb" />
    <ProjectCapability Include="Web" />
  </ItemGroup>
  <Import Sdk="MSBuild.SDK.SystemWeb/4.0.33" Project="Sdk.targets" />
  <Import Sdk="Microsoft.NET.Sdk.Publish" Project="Sdk.targets" />
</Project>

This will add the MSBuild.SDK.SystemWeb but 'overwrite' the publish targets from Microsoft.NET.Sdk.Publish.
If you build an example repository/example which works fully and doesn't break any ASPNET 4 features, we can look at whether this could be added.

@Kation
Copy link
Author

Kation commented Sep 3, 2021

@CZEMacLeod Yes. This allow us publish to IIS in Visual Studio.
Of course I use MSBuild.SDK.SystemWeb at the top of Project.
I have been tested with asp.net mvc but not webform.
I found that IIS publish target appear if add project capability only.

@christianbumann
Copy link

@CZEMacLeod and @Kation
Thank you for the workaround. With the lines above I get the additional publish targets (e.g. IIS) back. But I currently have the issue that if I publish to a folder no files are published.
Even if I do a publish from your example projects https://github.com/CZEMacLeod/MSBuild.SDK.SystemWeb/tree/main/samples nothing is published to the publishing folder.
If I build from command line with arguments (DeployOnBuild, WebPublishMethod, PackageLocation) publishing is working.

@CZEMacLeod
Copy link
Owner

@christianbumann This was never added to the main SDK as it didn't feel like it worked as intended and caused side effects. The fact that it works from the command line means it is easy to integrate this with any CI/CD system, and other than for small/test projects, which wouldn't really benefit from this SDK, it seems like an unlikely use case to be publishing from VS directly.
I use the publish mechanism (without any additional settings beyond the SDK), from Azure DevOps for most of my main (ASP.NET4) projects now and it works very well. I'm sure it would also work from GitHub actions too.
You could easily set it to publish to a folder and then pick up the folder as artifacts for output, if you want to do it that way.
I use MSDeploy and then a release job to actually push the site to our servers.

@christianbumann
Copy link

@CZEMacLeod Thank you for your quick answer. Publishing local from Visual Studio would get a faster feedback how the final package content looks like. Deploying from the pipeline is in plan as the build artefact (deployment package) itself already exists.... Our developers can take the build artefact and extract it if required - or build the solution locally through our Cake-scripts and then the package is also available local....
So we don't really need the local publishing in Visual Studio - I just wanted to ask if there is a quick and easy solution to get this working. But anyway, your answer was helpful for me - and your SDK is great. Have a nice time, Christian

@CZEMacLeod
Copy link
Owner

@christianbumann Ah I see. The only thing I can suggest here is to create a batch file in the solution directory and add it to the solution. That way you can execute the batch file from within VS and do the publish command and then investigate the output files etc.

@leusbj
Copy link
Contributor

leusbj commented Nov 2, 2022

@christianbumann Maybe try one of the following

  • Set <MvcBuildViews>false</MvcBuildViews> in your project and see if the folder now contains what you expect
  • Set the Publish location to a path outside the project directory and see if the folder now contains what you expect

@CZEMacLeod I think there might be a conflict between the "order of operations" in terms of how Visual Studio runs the publish vs running a build. It was something I was investigating but never finished looking into.

I was trying to document the differences between (and the interactions around) the "MvcBuildViews" and the "PreCompileBeforePublish" and how this changed order a little bit when in a ".net core build" as opposed to the original "build", and this as far as I made it when I stopped.

MvcBuildViews target

  • Introduced in VS2010 (slightly altered in VS2012)
  • Enabled to run when Condition="'$(MvcBuildViews)'=='true'"
  • Timed to run with AfterTargets="AfterBuild" note that the meaning of AfterBuild has changed somewhat between older builds and ".net core build" (which now has an "inner" and an "outer" build)
  • Executes task that calls the AspNetCompiler on the current folder structure (and outputs it's content to an ASPNET temp folder... AspNetCompiler was really geared to run against inplace web applications)
  • In VS2013 (I think update 3) a new target <Target Name="CleanupForBuildMvcViews" Condition=" '$(_EnableCleanOnBuildForMvcViews)'=='true' and '$(MVCBuildViews)'=='true' " BeforeTargets="MvcBuildViews"> target was added to the "Microsoft.Web.Publishing.targets"
    • Runs before MvcBuildViews target
    • deletes the contents of several project sub folders, including any folder named "package"... even if that folder is under the "/obj" path, which the default package location usually is.

PreCompileBeforePublish

  • Been available since at least VS2012 (not sure how far back it goes)
  • A property that governs if the "publish" process should run compile aspnet and razorMvc content before packaging
  • Triggers an advanced call to the AspNetCompiler (logic is inside Microsoft.Web.Publishing.AspNetCompileMerge.targets") placing the output of the precompiled files and dlls inside the specified output/packagelocation

I think the conflict comes into play because of when CleanupForBuildMvcViews deletes files and when the "Publish" creates the files (or potentially goes looking for the files to bundle them up)

The oldest VS I currently have installed is 2017, so I can't tell for sure, but by VS 2017 it seems like web project templates

  • moved away from the <MvcBuildViews>true</MvcBuildViews> having the build process call AspNetCompile but rather defaulting to <MvcBuildViews>false</MvcBuildViews>
  • towards having allowing the publish configuration to set <PreCompileBeforePublish>true</PreCompileBeforePublish> letting the publish step call AspNetCompile

@christianbumann
Copy link

christianbumann commented Nov 3, 2022

@leusbj Thank you for your suggestions. I tried it but without success. I also combined <MvcBuildViews>false</MvcBuildViews> with <PreCompileBeforePublish>true</PreCompileBeforePublish> and I tried each possible true-false combination without success. Don't investigate extra time for this, as we have a workaround with a *.cmd file building the project with the required arguments, or using the artefact from the build server...

@MalcolmEllis
Copy link

@CZEMacLeod Is there any chance you could add a 'For Dummies' sample showing how to get publish to work from the command line? So far if I call msbuild using a simple build script with a VS 2022 cmd prompt I get the website bin directory contents copied to the specified PublishDir path, but not the expected Asp.Net folder structure with a web.config, global.asax, Views, bin dir etc. that I get doing the same kind of build with the old csproj style (output created in a _PublishedWebsites folder). I also tried using 'dotnet build' but that fails due to your Sdk.targets getting the wrong MSBuildExtensionsPath32. I'm just trying this with the basic site from the template here, should it work with the dotnet CLI, I used that to install the template?

@chucker
Copy link

chucker commented Mar 21, 2023

if I call msbuild using a simple build script with a VS 2022 cmd prompt I get the website bin directory contents copied to the specified PublishDir path, but not the expected Asp.Net folder structure with a web.config, global.asax, Views, bin dir etc.

Hm, that should work. Your deployment command should look something like:

    msbuild /t:Restore,Rebuild /p:DeployOnBuild=true /p:PublishProfile=Dev.pubxml `
    /p:Password=$pass /p:Configuration=MyBuildConfig .\MyProject.csproj

This assumes you've created a Dev.pubxml publish profile in VS, that it already sets the username, and that it resides in the default location Properties/PublishProfiles/. That, in turn, looks something like:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <AllowUntrustedCertificate>True</AllowUntrustedCertificate>
    <WebPublishMethod>MSDeploy</WebPublishMethod>
    <LaunchSiteAfterPublish>True</LaunchSiteAfterPublish>
    <LastUsedBuildConfiguration>Beta</LastUsedBuildConfiguration>
    <LastUsedPlatform>Any CPU</LastUsedPlatform>
    <SiteUrlToLaunchAfterPublish />
    <ExcludeApp_Data>False</ExcludeApp_Data>
    <MSDeployServiceURL>(some host name)</MSDeployServiceURL>
    <DeployIisAppPath>(the web site in IIS)</DeployIisAppPath>
    <RemoteSitePhysicalPath />
    <SkipExtraFilesOnServer>True</SkipExtraFilesOnServer>
    <MSDeployPublishMethod>WMSVC</MSDeployPublishMethod>
    <EnableMSDeployBackup>True</EnableMSDeployBackup>
    <UserName>(your username, on the server)</UserName>
  </PropertyGroup>
</Project>

Maybe it's something about your csproj?

@CZEMacLeod
Copy link
Owner

@MalcolmEllis This has been covered somewhat in issues #12 and #20
@chucker Thanks for the suggestion on using an existing publish profile.

You cannot use dotnet as, not only does it not pick up the Web.Application build tasks which are only available from MSBuild included in VS - those tasks are not compatible is netcore so cannot run under dotnet.

msbuild /t:Publish /p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingeFile=true /p:PackageLocation="MyPublishDir"
msbuild "path\to\your\solution.sln" /t:rebuild ^
				    /p:Configuration=Release ^
				    /p:DeployOnBuild=True ^
				    /p:DeployDefaultTarget=WebPublish ^
				    /p:WebPublishMethod=FileSystem ^
				    /p:DeleteExistingFiles=True ^
				    /p:publishUrl="path\to\your\output\folder"

should both work.

Note that you should do a nuget.exe restore before the build. I think @chucker's example of doing /t:restore,rebuild should work too, but that is not the way I do it.

If you are using azure pipelines you can use something like (taken from a working commercial implementation)

- task: NuGetToolInstaller@1
  displayName: 'Use NuGet 6.2.1'
  inputs:
    versionSpec: 6.2.1

- task: NuGetCommand@2
  displayName: 'NuGet restore'
  inputs:
    restoreSolution: '$(Parameters.solution)'
    feedsToUse: config
    nugetConfigPath: NuGet.Config

- task: VSBuild@1
  displayName: 'Build solution'
  inputs:
    solution: '$(Parameters.solution)'
    msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:PackageLocation="$(build.artifactstagingdirectory)\\"'
    platform: '$(BuildPlatform)'
    configuration: '$(BuildConfiguration)'

- task: PublishSymbols@1
  displayName: 'Publish symbols path'
  inputs:
    SearchPattern: '**\bin\**\*.pdb'
  continueOnError: true

- task: PublishBuildArtifacts@1
  displayName: 'Publish Artifact'
  inputs:
    PathtoPublish: '$(build.artifactstagingdirectory)'
    ArtifactName: '$(Parameters.ArtifactName)'

I'm open to PRs adding to the documentation - especially with tested snippets.
I am considering adding an optional .cmd or .bat file to the template projects with a publish command script if that would help.
My understanding of the main use case for this SDK is normally that you transfer an existing project to the new format, and that the existing build scripts/publish profiles should pretty much work as is.
This issue is specifically about getting it to work from within Visual Studio itself, and I think that is generally not possible (at least not without some side-effects) at the moment.

@John0King
Copy link

@CZEMacLeod why not the Sdk.props and Sdk.targets only import what the "WebProject" import ?

@CZEMacLeod
Copy link
Owner

@John0King What exactly do you mean by that? The SDK handles a lot of functionality that was provided by Visual Studio explicitly for Web Application Projects, such as binding redirects, handling launching IIS/IISExpress and so on. The SDK does import the same built in targets as a legacy WAP file in SDK.props line 31

<Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" />

This specific issue is that VS has custom handling for Publish for legacy projects, which isn't triggered in SDK projects, and trying to reuse the dotnetcore/aspnetcore publish targets doesn't exactly work, due to the differences between dotnetcore/aspnetcore and asp.net 4.x
See the last 2 paragraphs of my previous reply.

My understanding of the main use case for this SDK is normally that you transfer an existing project to the new format, and that the existing build scripts/publish profiles should pretty much work as is.
This issue is specifically about getting it to work from within Visual Studio itself, and I think that is generally not possible (at least not without some side-effects) at the moment.

@John0King
Copy link

@CZEMacLeod

I don't know is there any other issue on Sdk.props and Sdk.targets

here is a project with old format
image

and this is in the Sdk.props
image

it seems that you replace the Microsoft.Common.props with Microsoft.Net.Sdk .

I'm new to the msbuild and the Sdk ralated concept, I'm just curious about why not just use the old vs props

@CZEMacLeod
Copy link
Owner

@John0King If you want to continue this - we should move it to a discussion as this issue doesn't really relate to what you are talking about.
Microsoft.Net.Sdk imports Microsoft.Common.props as basically the first thing it does.
It also imports the appropriate language targets and all the newer style PackageReference and so on handing.
This is what gives you all the good features of the new style SDK - e.g. your original project file will probably not need any of the content in your original file, except for any additional packages.

The basic new project file is as simple as

<Project Sdk="MSBuild.SDK.SystemWeb/4.0.88">
  <PropertyGroup>
    <TargetFramework>net48</TargetFramework>
  </PropertyGroup>
  <ItemGroup>
    <None Include="Properties\launchSettings.json" />
  </ItemGroup>
</Project>

I'm pretty sure there is a lot of information on the new style SDK projects out there, including on the MS Learn website.
If you have any queries or problems, either create a new discussion, or raise a new issue about your exact problem.

@julealgon
Copy link

Can this issue be renamed to make it explicit we are talking about publishing to IIS through Visual Studio specifically?

I was browsing the issues on the repo to see if there was anything I considered major and this issue here immediately jumped to me. After finding out it works just fine via cmdline the criticality of this drops massively for me.

Renaming it to be more precise would potentially save other people from similar confusion.

@CZEMacLeod CZEMacLeod changed the title Add IIS publish support Support Publish to IIS from withing Visual Studio using the GUI Jul 5, 2023
@CZEMacLeod CZEMacLeod added enhancement New feature or request known limitation This issue is related to a known limitation and cannot currently be fixed. labels Jul 5, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request known limitation This issue is related to a known limitation and cannot currently be fixed.
Projects
None yet
Development

No branches or pull requests

8 participants