projectkudu / kudu

Kudu is the engine behind git/hg deployments, WebJobs, and various other features in Azure Web Sites. It can also run outside of Azure.
Apache License 2.0
3.12k stars 653 forks source link

Both Nuget and Npm package restore for ASP.NET Webapi project #2203

Closed ghost closed 6 months ago

ghost commented 7 years ago

I have an ASP.NET Webapi project with Nuget pacakges for C# and Npm packages for Angular2. Kudu can't deploy them both by default, only Nuget for ASP.NET projects and Nmp for Node.js projects from what I understand.

I created a custom deployment script to do both, but I wonder if this configuration will eventually be supported by kudu "out of the box" so I don't have to do a customization for deployment.

I thought this is becoming a common pattern for ASP.NET projects as scripting packages (including Typescript) are shifting towards using Npm. If that is not the case, what are best practice for dealing with this kind of projects?

davidebbo commented 7 years ago

Could you share a sample repo that does this, per these steps? Also, I'd like to better understand the user steps that lead to this situation, to help determine how common vs custom the scenario is.

ghost commented 7 years ago

Hi @davidebbo I can create a custom public repo to exemplify this, the one we use is private. But I can give a little background, maybe it helps. We currently have about 9 Azure sites with ASP.NET MVC/Web APi and Kudu out of the box deployment and they work fine.

We recently introduced Angular 2 in one of the projects and had to use NPM packages for that.

Here is some of the content of the package index files in that project. Let me know if the repo sample is still needed, I will create one. Thanks

Packages.config

<packages>
  <package id="AspNetBundling" version="2.0.3.0" targetFramework="net451" />
  <package id="EntityFramework" version="6.1.3" targetFramework="net451" />
  <package id="Microsoft.AspNet.Web.Optimization" version="1.1.3" targetFramework="net45" />
  <package id="Microsoft.AspNet.WebApi" version="5.2.3" targetFramework="net451" />
  <package id="Microsoft.AspNet.WebApi.Client" version="5.2.3" targetFramework="net451" />
  <package id="Microsoft.AspNet.WebApi.Core" version="5.2.3" targetFramework="net451" />
  <package id="Microsoft.AspNet.WebApi.Cors" version="5.2.3" targetFramework="net451" />
  <package id="Microsoft.AspNet.WebApi.OData" version="5.7.0" targetFramework="net451" />
  <package id="Microsoft.AspNet.WebApi.WebHost" version="5.2.3" targetFramework="net451" />
  <package id="Microsoft.AspNet.WebPages" version="3.2.3" targetFramework="net451" />
  <package id="Microsoft.Data.Edm" version="5.7.0" targetFramework="net451" />
  <package id="Microsoft.Data.OData" version="5.7.0" targetFramework="net451" />
  <package id="Microsoft.Net.Compilers" version="1.3.2" targetFramework="net451" developmentDependency="true" />
  <package id="Microsoft.Net.Http" version="2.2.29" targetFramework="net451" />
  <package id="Microsoft.Owin" version="3.0.1" targetFramework="net451" />
  <package id="Microsoft.Owin.Host.SystemWeb" version="3.0.1" targetFramework="net451" />
  <package id="Microsoft.Owin.Security" version="3.0.1" targetFramework="net451" />
  <package id="Newtonsoft.Json" version="9.0.1" targetFramework="net451" />
  <package id="Unity" version="4.0.1" targetFramework="net451" />
  <package id="Unity.WebAPI" version="5.2.3" targetFramework="net451" />
  <package id="WebGrease" version="1.6.0" targetFramework="net45" />
</packages>

package.json

{
  "name": "angular-tmlc",
  "version": "1.0.0",
  "description": "package.json for angular components in tmlc",
  "scripts": {
  ...
  ...
  ...
    ],
  "dependencies": {
    "@angular/common": "~2.1.0",
    "@angular/compiler": "~2.1.0",
    "@angular/core": "~2.1.0",
    "@angular/forms": "~2.1.0",
    "@angular/http": "~2.1.0",
    "@angular/platform-browser": "~2.1.0",
    "@angular/platform-browser-dynamic": "~2.1.0",
    "@angular/router": "~3.1.0",
    "@angular/upgrade": "~2.1.0",
    "angular-in-memory-web-api": "~0.1.5",
    "bootstrap": "^3.3.7",
    "systemjs": "0.19.39",
    "core-js": "^2.4.1",
    "reflect-metadata": "^0.1.8",
    "rxjs": "5.0.0-beta.12",
    "zone.js": "^0.6.25",
    "typescript": "^2.0.3"
  },
...
}
skendrot commented 7 years ago

Same issue. Sample repo includes a deploy.cmd that I pieced together from a custom node deploy and custom aspWAP deploy.

skendrot commented 7 years ago

@davidebbo Any thoughts on this?

davidebbo commented 7 years ago

@watashiSHUN can you take a look at this one?

skendrot commented 7 years ago

In my sample repo I ultimately want to allow for AOT compilation for my angular application within kudu

watashiSHUN commented 7 years ago

The deployment logic in Azure is straight forward:

if it's a dotnet core project:
      run "dotnet restore"
      run "dotnet publish"
else if it's a node project,
      run "npm install --production"

Although your project needs to run both commands, this can still be accomplished in Azure (without using a custom deployment script....that's just too much work):

Both node and dotnet provide event hooks that let you run scripts at different building stages, so in theory you have two options:

  1. deploy as node project, then run dotnet commands as post-install scripts (in "package.json")
  2. deploy as dotnet project, then run npm commands as prepublish scripts(in "project.json"/".csproj")

But since if else statement gives dotnet core project precedence in Azure, you need to use the second option:

  1. if you are using dotnet cli preview2 toolings ("project.json" + ".xproj"), you can add the following code to your "project.json" file
    "scripts": {
    "prepublish": [ "npm install",... ]
    }
  2. if you are using dotnet cli preview3 toolings or later (".csproj"), you can add the following code to your ".csproj" file
    <Target Name="manageNodePackages" BeforeTargets="BeforePublish">
        <Exec Command="npm install" />
    </Target>
skendrot commented 7 years ago

Does this apply to projects that are not dotnet core?

watashiSHUN commented 7 years ago

Yes, if its a ASP.NET web app, once you created it in VS, you can navigate to its ".csproj" file and you will see the following:

  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
       Other similar extension points exist, see Microsoft.Common.targets.
  <Target Name="BeforeBuild">
  </Target>
  <Target Name="AfterBuild">
  </Target>
  -->
skendrot commented 7 years ago

Won't that slow down the dev builds of the project?

watashiSHUN commented 7 years ago

when you say "dev build" do you mean project build speed during development cycles? Of cause, you don't want to run npm every time you build your project locally, you need something other than <Target Name="BeforeBuild">

if you look at this line in your deploy.cmd, you can see that msbuild is running two targets subsequently: /t:Build /t:pipelinePreDeployCopyAllFilesToOneFolder

adding the following lines to your ".csproj" will ensure commands are ran only when you deploy to Azure:

  <Target Name="MyTarget" BeforeTargets="pipelinePreDeployCopyAllFilesToOneFolder">
    <Exec Command="npm install" />
  </Target>
skendrot commented 7 years ago

Added the target (and removed the deploy.cmd in favor of default and get the following errors:

Command: deploy.cmd Handling .NET Web Application deployment. MSBuild auto-detection: using msbuild version '14.0' from 'D:\Program Files (x86)\MSBuild\14.0\bin'. All packages listed in packages.config are already installed. D:\Program Files (x86)\Microsoft SDKs\TypeScript\2.0\lib.es2015.core.d.ts(17,14): error TS2300: Build:Duplicate identifier 'PropertyKey'. [D:\home\site\repository\angularmvc\angularmvc.csproj] D:\home\site\repository\angularmvc\app\components\todolist\todolist.component.ts(1,25): error TS2307: Build:Cannot find module '@angular/core'. [D:\home\site\repository\angularmvc\angularmvc.csproj] D:\home\site\repository\angularmvc\app\components\todolist\todolist.component.ts(2,25): error TS2307: Build:Cannot find module '@angular/forms'. [D:\home\site\repository\angularmvc\angularmvc.csproj] ... ... D:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v14.0\TypeScript\Microsoft.TypeScript.targets(214,5): warning : No compiler log specified, 'Clean' won't work. [D:\home\site\repository\angularmvc\angularmvc.csproj] Failed exitCode=1, command="D:\Program Files (x86)\MSBuild\14.0\Bin\MSBuild.exe" "D:\home\site\repository\angularmvc\angularmvc.csproj" /nologo /verbosity:m /t:Build /t:pipelinePreDeployCopyAllFilesToOneFolder /p:_PackageTempDir="D:\local\Temp\8d435ed00169d42";AutoParameterizationWebConfigConnectionStrings=false;Configuration=Release;UseSharedCompilation=false /p:SolutionDir="D:\home\site\repository.\" An error has occurred during web site deployment. \r\nD:\Program Files (x86)\SiteExtensions\Kudu\59.51212.2600\bin\Scripts\starter.cmd deploy.cmd

It does not appear to be running the install command

watashiSHUN commented 7 years ago
  <Target Name="BeforeBuild" Condition=" $(Configuration) == 'Release'" >
    <Exec Command="npm install" />
  </Target>

should work for you (see pull request)

  <Target Name="MyTarget" BeforeTargets="pipelinePreDeployCopyAllFilesToOneFolder">
    <Exec Command="npm install" />
  </Target>

Can sometimes be used, it all depends on when you want to run npm install: for my test case I used angular-cli to manage my frontend (since we only have angular2 template for dotnet core preview2) and dotnet core webAPI for backend

Because the build of frontend and backend are independent of each other, it does not matter when I invoke npm and ng build, but for your repo you are building them together (".ts" + ".cs") you need to run npm install to restore packages before build

jvano commented 6 months ago

Hi

If the problem persists and is related to running it on Azure App Service, please open a support incident in Azure: https://learn.microsoft.com/en-us/azure/azure-portal/supportability/how-to-create-azure-support-request

This way we can better track and assist you on this case

Thanks,

Joaquin Vano Azure App Service