Trouble hosting Blazor wasm in Azure App service - asp.net-core

I created a blazor wasm app in VS2022 with the option of core hosted. This created 3 projects, client, server and shared.
The server app now contains my web api. I can run the site locally and all works well.
I've created the following Azure DevOps pipeline for build and deployment to an Azure App Service:
trigger:
- master
variables:
vmImageName: "windows-2022"
stages:
- stage: Build
displayName: Build stage
jobs:
- job: Build
displayName: Build
pool:
vmImage: $(vmImageName)
steps:
- task: DotNetCoreCLI#2
displayName: "build"
inputs:
command: build
projects: "**/BillByTime.sln"
configuration: "$(buildConfiguration)"
- task: DotNetCoreCLI#2
displayName: "test"
inputs:
command: test
projects: "**/BillByTime.UnitTest.csproj"
arguments: "--configuration Release"
continueOnError: true
- task: DotNetCoreCLI#2
displayName: "publish server app"
inputs:
command: publish
arguments: "--configuration Release --output $(Pipeline.Workspace)/publish_output"
publishWebProjects: False
projects: "**/BillByTime.Server.csproj"
zipAfterPublish: false
- task: ArchiveFiles#2
displayName: "Archive files"
inputs:
rootFolderOrFile: "$(Pipeline.Workspace)/publish_output"
includeRootFolder: false
archiveFile: "$(Pipeline.Workspace)/build$(Build.BuildId).zip"
- publish: "$(Pipeline.Workspace)/build$(Build.BuildId).zip"
displayName: "publish zip"
artifact: "application"
- stage: DeployDev
displayName: Deploy Dev Stage
jobs:
- deployment: DeployDev
displayName: deploy dev
pool:
vmImage: "Windows-Latest"
environment: "dev"
variables:
- name: env
value: "dev"
- name: svcConnection
value: "BizTalkersSvcCon"
strategy:
runOnce:
deploy:
steps:
- download: current
artifact: application
- download: current
artifact: sql-script
- task: AzureWebApp#1
displayName: deploy blazor app
inputs:
azureSubscription: ${{variables.svcConnection}}
appType: "webAppLinux"
appName: appsvc-billbytime-webapi-${{variables.env}}-001
package: $(Pipeline.Workspace)/application/**/*.zip
deployToSlotOrASE: false
resourceGroupName: rg-BillByTime-${{variables.env}}-001
The pipeline runs without error. If I navigate to the url of the app service (https://appsvc-billbytime-webapi-dev-001.azurewebsites.net) I get a 403 Forbidden error.
By making an FTP connection to the App Service, I can see the folder structure and files that have been deployed:
Within /site/wwwroot/BillByTime.Server/wwwroot I see the blazor client app is also deployed.
So, it seems all the files have deployed ok but I seem to be missing some kind of config that would route the browser to /site/wwwroot/BillByTime.Server/wwwroot/index.html ?

Please copy the all the contents under BillByTime.Server and paste to /site/wwwroot.
The reason for this problem is that after the release of the wwwroot folder, there is an extra layer of BillByTime.Server. Normally, under wwwroot, a web.config file is required.
Or you also can change the wwwroot like below:

Related

How to deploy Blazor WebAssembly as static site in GitLab Pages

I can't find any guide on how to deploy a Blazor web assembly app to GitLab Pages as a static site. Has anyone managed to do so for .NET 6?
I have created a sample web assembly Blazor client application:
https://gitlab.com/sunnyatticsoftware/sasw-community/sasw-editor
The steps to create this simple web assembly are:
Install .NET 6 SDK
Create repo and clone it (e.g: sasw-editor)
Create the solution with web assembly Blazor project
dotnet new gitignore
dotnet new blazorwasm --name Sasw.Editor.Web --output src/Sasw.Editor.Web --no-https
dotnet new sln
dotnet sln add src/Sasw.Editor.Web
Compile and run it
dotnet build
dotnet run --project src/Sasw.Editor.Web
That's a way to run the blazor app on the port defined at the launchsettings.json
Building...
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://localhost:5291
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
Content root path: C:\src\sasw-editor\src\Sasw.Editor.Web
I stop it. It works fine when served with Kestrel.
Now, the process to publish a distribution folder would be like this
dotnet publish -c Release -o publish
All the artifacts and files are now under publish folder. So, in theory, I can serve those things with a simple web server. I install a basic web server tool called local-web-server (it requires NodeJs/npm but you can use any other web server)
npm install -g local-web-server
Now I navigate to the publish/wwwroot folder where my index.html is
And I start the web server there
ws
Listening on http://5CD013DP5L:8000, http://192.168.1.13:8000, http://127.0.0.1:8000, http://172.21.208.1:8000
If I open the browser on http://127.0.0.1:8000, or any other of the above url, I can see my Blazor wasm app working perfectly.
I want to host that very same publish folder in GitLab pages which, in theory, is capable of serving static files.
So I create a .gitlab-ci.yml to compile, publish and copy contents to the public folder of GitLab pages.
image: mcr.microsoft.com/dotnet/sdk:6.0
variables:
GIT_DEPTH: 1000
PUBLISH_OUTPUT_DIR: publish
stages:
- build
- test
- publish
- delivery
build:
stage: build
script:
- dotnet restore --no-cache --force
- dotnet build --configuration Release --no-restore
artifacts:
paths:
- test
expire_in: 8 hour
rules:
- if: $CI_COMMIT_TAG
when: never
- when: always
test:
stage: test
script: dotnet test --blame --configuration Release
allow_failure: false
rules:
- if: $CI_COMMIT_TAG
when: never
- exists:
- test/**/*Tests.csproj
publish:
stage: publish
script:
- dotnet publish -c Release -o $PUBLISH_OUTPUT_DIR
artifacts:
paths:
- $PUBLISH_OUTPUT_DIR/
expire_in: 8 hour
rules:
- if: $CI_COMMIT_TAG
when: never
- when: on_success
pages:
stage: delivery
script:
- cp -a $PUBLISH_OUTPUT_DIR/ public
artifacts:
paths:
- public
only:
- main
The pipeline completes successfully. I can see the exact same structure I had locally within publish folder, this time under public folder in GitLab
But it fails to render the app
https://sunnyatticsoftware.gitlab.io/-/sasw-community/sasw-editor/-/jobs/1846501612/artifacts/public/wwwroot/index.html
shows
Loading...
An unhandled error has occurred. Reload 🗙
I can see it's attempting to access https://sunnyatticsoftware.gitlab.io/ or https://sunnyatticsoftware.gitlab.io/favicon.ico and returning 404
The favicon.ico would exist on https://sunnyatticsoftware.gitlab.io/-/sasw-community/sasw-editor/-/jobs/1846501612/artifacts/public/wwwroot/favicon.ico
so it must be some kind of URL re-write problem, right?
Any help would be much appreciated.
Always keep it at base href="/" and then in your ci change it to whatever you need. E.g. on gitlab you can use the CI_PROJECT_NAME variable.
pages:
stage: deploy
variables:
SED_COMMAND: 's#<base\shref="\/"\s?\/>#<base href="\/$CI_PROJECT_NAME\/" \/>#g'
script:
- cp -a $PUBLISH_OUTPUT_DIR/wwwroot public
- sed -r -i "$SED_COMMAND" public/index.html
artifacts:
paths:
- public
only:
- main
The solution is simply to use the following
pages:
stage: delivery
script:
- cp -a $PUBLISH_OUTPUT_DIR/wwwroot public
artifacts:
paths:
- public
only:
- main
and to use the <base href="/sasw-community/sasw-editor/" /> in index.html with the relative path.
I've recorded a quick tutorial on my Odysee channel https://odysee.com/#sunnyAtticSoftware:a/blazor-wasm-gitlab-pages:e
See https://gitlab.com/sunnyatticsoftware/training/blazorwasm-pages with a full sample
I still don't know of a good way to mix local development's base / relative path with prod base /sasw-community/sasw-editor/ and change it dynamically (is it even possible?)
But the problem is solved.

How to pass a github secret to asp.net core app deployed using github action?

I want to use GitHub secrets inside the repository code.
The repository is an asp.net core web app. I am deploying the app to the Azure app service using Github actions.
I have tried declaring env variable in the workflow like this
# Docs for the Azure Web Apps Deploy action: https://go.microsoft.com/fwlink/?linkid=2134798
# More GitHub Actions for Azure: https://go.microsoft.com/fwlink/?linkid=2135048
name: Azure App Service - TestJuzer(Production), Build and deploy DotnetCore app
on:
push:
branches:
- master
env:
TEST_STRING: ${{ secrets.TEST_STRING }}
jobs:
build-and-deploy:
runs-on: windows-latest
steps:
# checkout the repo
- name: 'Checkout Github Action'
uses: actions/checkout#master
- name: Set up Node.js '12.x'
uses: actions/setup-node#v1
with:
node-version: '12.x'
- name: Set up .NET Core
uses: actions/setup-dotnet#v1
with:
dotnet-version: '5.0.x'
- name: Build with dotnet
run: dotnet build --configuration Release
env:
TEST_STRING: ${{ secrets.TEST_STRING }}
- name: dotnet publish
run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/myapp
- name: Run Azure webapp deploy action using publish profile credentials
uses: azure/webapps-deploy#v2
with:
app-name: TestJuzer
slot-name: Production
publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_461CFB6B8D42419FA7F58944D621BA78 }}
package: ${{env.DOTNET_ROOT}}/myapp
env:
TEST_STRING: ${{ secrets.TEST_STRING }}
and accessing the env variable in .net like this
Environment.GetEnvironmentVariable("TEST_STRING")
"TEST_STRING" is the name of the secret. But I am getting null.
I want to pass secret as an environment variable in the workflow and use it in the deployed app.
Any help appreciated Thanks
You set env variable on agent machine. And here you should rather set it on App Service. You could use Azure App Service Settings:
Here is sample workflow:
# .github/workflows/configureAppSettings.yml
on: [push]
jobs:
build:
runs-on: windows-latest
steps:
- uses: azure/login#v1
with:
creds: '${{ secrets.AZURE_CREDENTIALS }}'
- uses: azure/appservice-settings#v1
with:
app-name: 'my-app'
slot-name: 'staging' # Optional and needed only if the settings have to be configured on the specific deployment slot
app-settings-json: '${{ secrets.APP_SETTINGS }}'
connection-strings-json: '${{ secrets.CONNECTION_STRINGS }}'
general-settings-json: '{"alwaysOn": "false", "webSocketsEnabled": "true"}' #'General configuration settings as Key Value pairs'
id: settings
- run: echo "The webapp-url is ${{ steps.settings.outputs.webapp-url }}"
- run: |
az logout
In you case it could be like:
- name: Set Web App settings
uses: Azure/appservice-settings#v1
with:
app-name: 'node-rnc'
app-settings-json: |
[
{
"name": "TEST_STRING",
"value": "${{ secrets.TEST_STRING }}",
"slotSetting": false
}
]

Azure Pipeline MSBuild

I am new to the whole azure pipeline. I have a project running on .net framework and want to create YAML with MSBuild in order to perform the following:
Cleaning solution
Restore Nuget Package
Build Solution
Run Unit Test (in different folder)
Package and publish
Can someone please help me?
To use YAML in Azure DevOps Pipeline, you could create a new YAML pipeline from scratch:
To add more tasks in the pipeline, you could click Show assistant and select the tasks you need:
The .yml file may look like below:
trigger:
- master
pool:
vmImage: 'windows-latest'
variables:
solution: '**/*.sln'
buildPlatform: 'Any CPU'
buildConfiguration: 'Release'
steps:
- task: NuGetToolInstaller#1
- task: NuGetCommand#2
inputs:
restoreSolution: '$(solution)'
- task: VSBuild#1
inputs:
solution: '$(solution)'
platform: '$(buildPlatform)'
configuration: '$(buildConfiguration)'
clean: true
- task: VSTest#2
inputs:
platform: '$(buildPlatform)'
configuration: '$(buildConfiguration)'
- task: PublishBuildArtifacts#1
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
ArtifactName: 'drop'
publishLocation: 'Container'
Since you are new to Azure DevOps and want to start with YAML, please see our Azure Pipelines documentation for great getting started guides and examples. More information, you could refer to YAML schema documentation. You can also find additional documentation and samples in azure-pipelines-yaml GitHub repo.

Add configuration to web.config in .NET Core build/publishing

I have a build pipeline that builds and publishes an ASP.NET Core 3.x application.
# ASP.NET Core
pool:
vmImage: 'ubuntu-latest'
variables:
buildConfiguration: 'Release'
steps:
- script: dotnet build --configuration $(buildConfiguration)
displayName: 'dotnet build $(buildConfiguration)'
- task: DotNetCoreCLI#2
displayName: 'Publish to artifacts directory'
inputs:
command: 'publish'
publishWebProjects: True
arguments: '--configuration $(BuildConfiguration) --output $(Build.ArtifactStagingDirectory)'
zipAfterPublish: True
The application is automatically deployed to IIS in a different process.
However, the web.config generated needs to be adjusted to disable compression:
<configuration>
...// aspNetCore stuff
<system.webServer>
// Add this to generated web.config
<urlCompression doStaticCompression="false" doDynamicCompression="false" />
</system.webServer>
</configuration>
Apart from a custom PowerShell script, is there a better way to achieve this?
UPDATE, this is how resulting zip is deployed to IIS:
steps:
- task: IISWebAppDeploymentOnMachineGroup#0
displayName: 'Deploy IIS Website/App:'
inputs:
WebSiteName: '$(IISWebSiteName)'
Package: 'PathToPublishedApp.zip'
RemoveAdditionalFilesFlag: true
TakeAppOfflineFlag: true
JSONFiles: appsettings.json

No package found when deploying an Asp.Net Core application to Azure using Azure DevOps

I have the following Publish and Deploy tasks in Azure DevOps:
variables:
buildConfiguration: 'Release'
buildPlatform: 'any cpu'
azureSubscription: 'subscription'
azureAppType: 'Web App on Windows'
webAppName: 'webapp'
steps:
# Other tasks
- task: DotNetCoreCLI#2
displayName: 'Publish'
inputs:
command: publish
publishWebProjects: false
arguments: '--configuration $(buildConfiguration) --output $(build.artifactstagingdirectory)'
zipAfterPublish: true
- task: AzureRmWebAppDeployment#4
displayName: 'Deploy'
inputs:
package: $(System.DefaultWorkingDirectory)/**/MyProj.zip
azureSubscription: '$(azureSubscription)'
appType: '$(azureAppType)'
webAppName: '$(webAppName)'
The publish tasks succeeds but I get the error on the Deploy task:
[error]Error: No package found with specified pattern: /home/vsts/work/1/s/**/MyProj.zip
What am I doing wrong?
Review your YAML:
You publish with the following parameters:
--output $(build.artifactstagingdirectory)
You try to deploy from a completely different location:
package: $(System.DefaultWorkingDirectory)/**/MyProj.zip
Try deploying $(build.artifactstagingdirectory)/**/MyProj.zip.