Search code examples
azure-devopsasp.net-core-mvccontinuous-integrationblazor

ASP.NET Core 6 MVC application with Mudblazor not working once deployed to Azure app service using Azure Devops


The setup

I have solution with quite few micro services in the form of Azure functions and a few shared projects and one MVC6 Mudblazor web app.

The Problem

When I deploy all of these components individually through Visual Studio 2022, everything works fine.

However, when I deploy these through an Azure Devops release pipeline, things start going crazy. Functions deploy fine. But the Webapp starts misbehaving. The webapp loads up fine but when i try to login, I get the following errors:

crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
Unhandled exception rendering component: ExpectedStartOfValueNotFound, < Path: $ | LineNumber: 0 | BytePositionInLine: 0.

System.Text.Json.JsonException: ExpectedStartOfValueNotFound, < Path: $ | LineNumber: 0 | BytePositionInLine: 0.
---> System.Text.Json.JsonReaderException: ExpectedStartOfValueNotFound, < LineNumber: 0 | BytePositionInLine: 0. at System.Text.Json.ThrowHelper.ThrowJsonReaderException(Utf8JsonReader& , ExceptionResource , Byte , ReadOnlySpan1 ) at System.Text.Json.Utf8JsonReader.ConsumeValue(Byte ) at System.Text.Json.Utf8JsonReader.ReadFirstToken(Byte ) at System.Text.Json.Utf8JsonReader.ReadSingleSegment() at System.Text.Json.Utf8JsonReader.Read() at System.Text.Json.Serialization.JsonConverter1[[MyProject.Platform.Shared.Wrapper.Result1[[MyProject.Platform.Application.Features.Accounts.Queries.GetById.GetProjectByIdResponse, PublicKeyToken=null]].ReadCore(Utf8JsonReader& , JsonSerializerOptions , ReadStack& ) Exception_EndOfInnerExceptionStack at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& , JsonReaderException ) at System.Text.Json.Serialization.JsonConverter1[[MyProject.Platform.Shared.Wrapper.Result`1[[MyProject.Platform.Application.Features.Accounts.Queries.GetById.GetProjectByIdResponse, at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task) at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task , ComponentState )

blazor.webassembly.js:1 crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
      Unhandled exception rendering component: Unexpected character encountered while parsing value: T. Path '', line 0, position 0.
Newtonsoft.Json.JsonReaderException: Unexpected character encountered while parsing value: T. Path '', line 0, position 0.
   at Newtonsoft.Json.JsonTextReader.ParseValue()
   at Newtonsoft.Json.JsonTextReader.Read()
   at Newtonsoft.Json.JsonReader.ReadAndMoveToContent()
   at Newtonsoft.Json.JsonReader.ReadForType(JsonContract contract, Boolean hasConverter)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonSerializer.Deserialize(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.DeserializeObject[Object](String value, JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.DeserializeObject[Object](String value)
   at 
   at Toolbelt.Blazor.HttpClientInterceptor.InvokeAsync(HttpClientInterceptorEventHandler asyncEventHandler, HttpClientInterceptorEventArgs args)
   at Toolbelt.Blazor.HttpClientInterceptor.InvokeAfterSendAsync(HttpClientInterceptorEventArgs args)
   at Toolbelt.Blazor.HttpClientInterceptorHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage , HttpCompletionOption , CancellationTokenSource , Boolean , CancellationTokenSource , CancellationToken )
   at 
   at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)
   at Microsoft.AspNetCore.Components.Forms.EditForm.HandleSubmitAsync()
   at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task , ComponentState )

 Failed to load resource: the server responded with a status of 405 (Method Not Allowed)

This is the pipeline YAML I used:

trigger:
- development
- master

pool:
  vmImage: 'windows-latest'

variables:
  solution: '**/*.sln'
  buildPlatform: 'Any CPU'
  buildConfiguration: 'Debug'
  publishPath: '$(Build.ArtifactStagingDirectory)/publish'

stages:

- stage: BuildApp
  displayName: Build Apps
  jobs:
  - job: BuildApp
    displayName: Build App
    steps:
    - task: DotNetCoreInstaller@2
      displayName: 'Install .NET 6 SDK'
      inputs:
        version: '6.x'

    - task: DotNetCoreInstaller@2
      displayName: 'Install .NET 7 SDK'
      inputs:
        version: '7.x'

    - task: DotNetCoreCLI@2
      displayName: 'Install WebAssembly tools for .NET 6'
      inputs:
        command: 'custom'
        custom: 'workload'
        arguments: 'install wasm-tools-net6'
        workingDirectory: '$(Agent.ToolsDirectory)/dotnet'
    - task: DotNetCoreInstaller@2
      displayName: 'Install .NET 3 SDK'
      inputs:
        version: '3.x'
    - task: NuGetToolInstaller@1
      inputs:
        versionSpec: '6.5'

    - task: NuGetCommand@2
      inputs:
        command: 'restore'
        restoreSolution: '$(System.DefaultWorkingDirectory)/WebApp/MyProject.Platform.sln'
        feedsToUse: 'config'
        nugetConfigPath: '$(System.DefaultWorkingDirectory)/nuget.config'
        arguments: '-Parallel'
    - task: MSBuild@1
      displayName: 'BUILD!!'
      inputs:
        solution: '$(System.DefaultWorkingDirectory)/WebApp/MyProject.Platform.sln'
        msbuildArchitecture: 'x64'
        platform: 'any cpu'
        configuration: $(buildConfiguration)
    - task: DotNetCoreCLI@2
      inputs:
        command: 'build'
        projects: '$(System.DefaultWorkingDirectory)/WebApp/MyProject.Platform.WebApp/Server/MyProject.Platform.Server.csproj'
        arguments: '--configuration Debug --output $(Build.ArtifactStagingDirectory)'
    - task: DotNetCoreCLI@2
      displayName: 'Publish'
      inputs:
        command: 'publish'
        publishWebProjects: True
        projects: '$(System.DefaultWorkingDirectory)/WebApp/MyProject.Platform.WebApp/Server/MyProject.Platform.Server.csproj'
        arguments: '--configuration Debug --output $(Build.ArtifactStagingDirectory)'
        zipAfterPublish: true
    - task: CopyFiles@2
      inputs:
        targetFolder: '$(Build.ArtifactStagingDirectory)'

    - task: PublishBuildArtifacts@1    
      displayName: 'Publish Artifact: drop'

The question

What am I doing wrong here?


Solution

  • I was finally able to get it working. The issue was here:

    - task: DotNetCoreCLI@2
      displayName: 'Publish'
      inputs:
        command: 'publish'
        publishWebProjects: True
        projects: '$(System.DefaultWorkingDirectory)/WebApp/MyProject.Platform.WebApp/Server/MyProject.Platform.Server.csproj'
        arguments: '--configuration Debug --output $(Build.ArtifactStagingDirectory)'
        zipAfterPublish: true 
    

    When you give publishWebProjects: True "If true, the task will try to find the web projects in the repository and run the publish command on them. Web projects are identified by presence of either a web.config file or wwwroot folder in the directory." - Azure devops info button

    Due to this being true originally, it was selecting Client every time because the CLIENT project has a wwwroot folder. With publishWebProjects set to false, you can specify a particular SERVER project.

    So, the SERVER project never got deployed.And that caused all of this havoc.

    This is the change that finally fixed it:

    - task: DotNetCoreCLI@2
      displayName: 'Publish'
      inputs:
        command: 'publish'
        publishWebProjects: False
        projects: '$(System.DefaultWorkingDirectory)/WebApp/MyProject.Platform.WebApp/Server/MyProject.Platform.Server.csproj'
        arguments: '--configuration Debug --output $(Build.ArtifactStagingDirectory)'
        zipAfterPublish: true