dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
15.18k stars 4.72k forks source link

Unable to rename ICUDT.dat file in Blazor WASM App Hosted(client server) project publish #100638

Closed praveenpallekaate closed 6 months ago

praveenpallekaate commented 6 months ago

Is there an existing issue for this?

Describe the bug

I have Blazor WASM App Hosted application. It has Client & Server project. It was in .Net 7, then i migrated to .Net 8 & client project with WasmEnableWebcil option as the .dll's wer blocked. After the migration .dat files got blocked & followed this post.

Client.csproj

...
  <!-- After the application is build/published -->
  <Target Name="RenameIcuToAppBundle" AfterTargets="Build">
    <Message Text="Rename ICU called!"/>
    <Message Text="$(OutputPath)"/>
    <ItemGroup>
      <!-- Find all ICU files in AppBundle -->
      <IcuFiles Include="$(OutputPath)\**\*.dat" />
    </ItemGroup>

    <!-- Change their extension to 'NewIcuFileExtension' -->
    <Move SourceFiles="@(IcuFiles)"
      OverwriteReadOnlyFiles="true"
      DestinationFiles="%(RelativeDir)%(Filename)$(NewIcuFileExtension)" />
  </Target>
...

First Approach: I added the above to client csproj file and icudt.dat is getting renamed on local build & on DevOps publish, but the server csproj publish stage it fails with icudt.dat file missing message as below. WebAssembly.Browser.targets(561,5): error MSB3954: Failed to compute hash for file 'D:\a\1\s\src\Client\bin\Release\net8.0\wwwroot\_framework\icudt.dat' because it does not exist or is inaccessible.

Second Approach: When i add the same setting to server csproj the rename does not work for AfterTargets on Build, Publish or both. The publish artifact zip show icudt.dat file in wwwroot\_framework folder as is. Below is the DevOps yaml to publish.

...
      # Build.
      - task: DotNetCoreCLI@2
        displayName: '🔨 dotnet build'
        inputs:
          command: 'build'
          projects: |
            src/Server.csproj
          arguments: '--no-restore --configuration Release'

      # Optimise and publish web package.
      - task: DotNetCoreCLI@2
        displayName: '📦 dotnet publish'
        inputs:
          command: 'publish'
          publishWebProjects: false
          projects: |
            src/Server.csproj
          arguments: '--no-build --configuration Release --output $(Build.ArtifactStagingDirectory)'

      # Publish artifacts.
      - task: PublishBuildArtifacts@1
        displayName: '📤 Publish artifacts'
        inputs:
          PathtoPublish: '$(Build.ArtifactStagingDirectory)/Server.zip'
          ArtifactName: 'drop'
          publishLocation: 'Container'

How do i go ahead here, should id modify blazor.boot.json & is it possible?

Expected Behavior

No response

Steps To Reproduce

No response

Exceptions (if any)

No response

.NET Version

8.0.203

Anything else?

No response

ilonatommy commented 6 months ago

Could you, please try custom ICU load instead (doc)? 1) Take the icudt.dat and rename it to not be any of: icudt, icudt_EFIGS, icudt_CJK, icudt_no_CJK but to start with icudt. You can change its extension if you need. 2) Place it in a known path, e.g. in the root of the project. 3) Add <BlazorIcuDataFileName>$(MSBuildThisFileDirectory)icudt_custom.$(NewIcuFileExtension)</BlazorIcuDataFileName> to your MsBuild's PropertyGroup in the Client app. Let me know if it works for you.

praveenpallekaate commented 6 months ago

I added the icudt file to root folder as icudt_custom.icu. Updated the client csproj as below

<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <!--<BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>-->
    <WasmEnableWebcil>true</WasmEnableWebcil>
    <NewIcuFileExtension>.icu</NewIcuFileExtension>
    <BlazorIcuDataFileName>$(MSBuildThisFileDirectory)icudt_custom.icu</BlazorIcuDataFileName>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Components.QuickGrid" Version="0.1.0-alpha.22351.1" />
    <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.3" />
    <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="8.0.3" PrivateAssets="all" />
    <PackageReference Include="Microsoft.Authentication.WebAssembly.Msal" Version="8.0.3" />
    ...
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="..\Shared\Shared.csproj" />
  </ItemGroup>

  <ItemGroup>
    <TrimmerRootAssembly Include="Microsoft.Authentication.WebAssembly.Msal" />
    <TrimmerRootAssembly Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" />
  </ItemGroup>

  <ItemGroup>
    <None Update="icudt_custom.icu">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
  </ItemGroup>

</Project>

On local build of client app the icudt_custom.icu file is copied to bin. But on DevOps publish the icudt_custom.icu file is not added to output zip.

On browsing the app, it's stuck in 100%. Console shows below error

image

ilonatommy commented 6 months ago

CopyToOutputDirectory works for build. What about

<ItemGroup>
  <Content Include="$(MSBuildThisFileDirectory)icudt_custom.icu">
    <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
  </Content>
</ItemGroup>

that should assure the file is there on publish? Also, is your problem limited to DevOps publish? Or is publishing to a local folder not working either?

praveenpallekaate commented 6 months ago

Thanks @ilonatommy That helped. I made few updates to the client csproj

<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">

    <PropertyGroup>
        <TargetFramework>net8.0</TargetFramework>
        <Nullable>enable</Nullable>
        <ImplicitUsings>enable</ImplicitUsings>
        <BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
        <WasmEnableWebcil>true</WasmEnableWebcil>
        <NewIcuFileExtension>.icu</NewIcuFileExtension>
        <BlazorIcuDataFileName>$(MSBuildThisFileDirectory)icudt_custom.icu</BlazorIcuDataFileName>
    </PropertyGroup>

    <ItemGroup>
        <PackageReference Include="Microsoft.AspNetCore.Components.QuickGrid" Version="0.1.0-alpha.22351.1" />
        ...
    </ItemGroup>

    <ItemGroup>
        <ProjectReference Include="..\Shared\Shared.csproj" />
    </ItemGroup>

    <ItemGroup>
        <TrimmerRootAssembly Include="Microsoft.Authentication.WebAssembly.Msal" />
        <TrimmerRootAssembly Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" />
    </ItemGroup>

    <!-- To handle public site load -->
    <ItemGroup>
        <None
          Include="icudt_custom.icu"
          CopyToOutputDirectory="Always"
          TargetPath="wwwroot\_framework\%(Filename)%(Extension)"
        />
    </ItemGroup>

    <ItemGroup>
        <Content
          Include="icudt_custom.icu"
          CopyToPublishDirectory="Always"
          TargetPath="wwwroot\_framework\%(Filename)%(Extension)"
        />
    </ItemGroup>

</Project>

After this change in DevOps publish i was able to see icudt_custom.icu file in wwwroot_framework folder & i added below script in the index.html in wwwroot folder as mentioned in this post.

...
<script src="_framework/blazor.webassembly.js" autostart="false"></script>
<script>
    Blazor.start({
        loadBootResource: function (type, name, defaultUri, integrity) {
            console.log(`Loading: '${type}', '${name}', '${defaultUri}', '${integrity}'`);

            if (type == 'globalization') {
                defaultUri = defaultUri.replace('.dat', '_custom.icu');
            }

            return defaultUri;
        }
    });
</script>
...

The site loads as expected.