Running .NET 6 project in Docker throws Globalization.CultureNotFoundException
Asked Answered
A

4

28

I have upgraded API project from .NET 5 to .NET 6 successfully and running fine when executed locally (without Docker).

I have also updated the version in Dockerfile from "5.0-alpine3.13" to "6.0-alpine3.14" as below (only change I made).

ARG VERSION=6.0-alpine3.14

#Runtime stage
FROM mcr.microsoft.com/dotnet/aspnet:$VERSION AS base
EXPOSE 8080
ENV DOTNET_RUNNING_IN_CONTAINER=true \
  ASPNETCORE_URLS=http://+:8080

#Build stage
FROM mcr.microsoft.com/dotnet/sdk:$VERSION AS build
WORKDIR /src
COPY ["/src/RM.Api/RM.Api.csproj", "/src/RM.Api/"]
RUN dotnet restore "/src/RM.Api/RM.Api.csproj"
COPY . .
WORKDIR "/src/src/RM.Api"

#Publish dotnet project
FROM build AS publish
ARG BUILDCONFIG=RELEASE
RUN dotnet publish "RM.Api.csproj" -c $BUILDCONFIG -o /app/publish

#Create local user, change ownership, and copy artifacts
FROM base AS final
WORKDIR /app
RUN adduser \
  --disabled-password \
  --home /app \
  --gecos '' app \
  && chown -R app /app
USER app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "RM.Api.dll"]

But when I run this .NET 6 project in Docker it throws the below Azure.Storage exception in the Startup.cs file.

API-Startup.cs

Full stack trace is here.

Microsoft.Azure.Storage.StorageException: Only the invariant culture is supported in globalization-invariant mode. See https://aka.ms/GlobalizationInvariantMode for more information. (Parameter 'name')
en-US is an invalid culture identifier.
---> System.Globalization.CultureNotFoundException: Only the invariant culture is supported in globalization-invariant mode. See https://aka.ms/GlobalizationInvariantMode for more information. (Parameter 'name')
en-US is an invalid culture identifier.
at System.Globalization.CultureInfo..ctor(String name, Boolean useUserOverride)
at Microsoft.Azure.Storage.Core.Util.AuthenticationUtility.AppendCanonicalizedCustomHeaders(CanonicalizedString canonicalizedString, HttpRequestMessage request)
at Microsoft.Azure.Storage.Core.Auth.SharedKeyCanonicalizer.CanonicalizeHttpRequest(HttpRequestMessage request, String accountName)
at Microsoft.Azure.Storage.Auth.Protocol.StorageAuthenticationHttpHandler.GetSharedKeyAuthenticationTask(StorageRequestMessage request, CancellationToken cancellationToken)
at Microsoft.Azure.Storage.Auth.Protocol.StorageAuthenticationHttpHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpMessageInvoker.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.<>n__0(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
at Microsoft.Azure.Storage.Core.Executor.Executor.ExecuteAsync[T](RESTCommand`1 cmd, IRetryPolicy policy, OperationContext operationContext, CancellationToken token)
--- End of inner exception stack trace ---
at Microsoft.Azure.Storage.Core.Executor.Executor.ExecuteAsync[T](RESTCommand`1 cmd, IRetryPolicy policy, OperationContext operationContext, CancellationToken token)
at Microsoft.Azure.Storage.Blob.CloudBlobContainer.CreateAsync(BlobContainerPublicAccessType accessType, BlobRequestOptions options, OperationContext operationContext, CancellationToken cancellationToken)
at Microsoft.Azure.Storage.Blob.CloudBlobContainer.CreateIfNotExistsAsync(BlobContainerPublicAccessType accessType, BlobRequestOptions options, OperationContext operationContext, CancellationToken cancellationToken)
at RM.Api.Startup.ConfigureServices(IServiceCollection services) in /src/src/RM.Api/Startup.cs:line 91

I have updated the Dockerfile as below but it did not work. Can any one help here?

ARG VERSION=6.0-alpine3.14

#Runtime stage
FROM mcr.microsoft.com/dotnet/aspnet:$VERSION AS base
EXPOSE 8080
ENV DOTNET_RUNNING_IN_CONTAINER=true \
  ASPNETCORE_URLS=http://+:8080

#Build stage
FROM mcr.microsoft.com/dotnet/sdk:$VERSION AS build
WORKDIR /src
COPY ["/src/RM.Api/RM.Api.csproj", "/src/RM.Api/"]
RUN dotnet restore "/src/RM.Api/RM.Api.csproj"
COPY . .
WORKDIR "/src/src/RM.Api"

RUN apk add --no-cache icu-libs krb5-libs libgcc libintl libssl1.1 libstdc++ zlib

ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=true

#Publish dotnet project
FROM build AS publish
ARG BUILDCONFIG=RELEASE
RUN dotnet publish "RM.Api.csproj" -c $BUILDCONFIG -o /app/publish

#Create local user, change ownership, and copy artifacts
FROM base AS final
WORKDIR /app
RUN adduser \
  --disabled-password \
  --home /app \
  --gecos '' app \
  && chown -R app /app
USER app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "RM.Api.dll"]
Almoner answered 9/2, 2022 at 7:54 Comment(2)
ofcourse you have to update image to version 6, for example mcr.microsoft.com/dotnet/sdk:6.0.302-alpine3.16 and you need icu-libs and InvariantGlobalization false in csproj file.Parnassus
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false - this line you can remove from docker file if you have this value in csproj fileParnassus
T
5

You've put the ENV statement in the 'build' part of the Dockerfile which means that it doesn't get placed in the final image. Either put it in the 'base' part or the 'final' part.

I'd put it in the 'base' section with the other ENV statements.

You might also want to move the apk add to the base or final sections of the file, if you want the software installed in the final image.

Tokoloshe answered 9/2, 2022 at 7:59 Comment(0)
B
29

Your docker file should look like this for the base section:

FROM mcr.microsoft.com/dotnet/aspnet:6.0-alpine AS base
WORKDIR /app
RUN apk add --no-cache icu-libs
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false
EXPOSE 80
EXPOSE 443
Breeches answered 12/5, 2022 at 14:16 Comment(0)
A
9

Making the following two changes resolved the issue.

  1. Updating the Dockerfile as below
    ARG VERSION=6.0-alpine3.14

    #Runtime stage
    FROM mcr.microsoft.com/dotnet/aspnet:$VERSION AS base
    EXPOSE 8080

    ENV DOTNET_RUNNING_IN_CONTAINER=true \
      ASPNETCORE_URLS=http://+:8080
    
    RUN apk add --no-cache icu-libs krb5-libs libgcc libintl libssl1.1 libstdc++ zlib
    
    ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false
  1. Added the below in .csproj file

  <PropertyGroup>
    <InvariantGlobalization>false</InvariantGlobalization>
  </PropertyGroup>
Almoner answered 9/2, 2022 at 9:11 Comment(0)
T
5

You've put the ENV statement in the 'build' part of the Dockerfile which means that it doesn't get placed in the final image. Either put it in the 'base' part or the 'final' part.

I'd put it in the 'base' section with the other ENV statements.

You might also want to move the apk add to the base or final sections of the file, if you want the software installed in the final image.

Tokoloshe answered 9/2, 2022 at 7:59 Comment(0)
M
0

adding below two line to docker file will resolves this issue.

FROM mcr.microsoft.com/dotnet/aspnet:6.0-alpine3.18 AS release
WORKDIR /workspace

RUN apk add --no-cache icu-libs

ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false
Mistrust answered 31/7, 2023 at 17:29 Comment(2)
The error is resolved but the DateTime.TryParseExact Date parsing fails.Chinaman
Ok I found the issue with the DateTime.TryParseExact. It is unrelated to the actual icu-libs or invariant. However anybody who is going from SDK 3.1 to 7.0+ along with Linux Alpine and using DateTime.TryParseExact may run into the same issue, hence referencing the answer here. https://mcmap.net/q/504075/-why-datetime-tryparseexact-is-not-workingChinaman

© 2022 - 2024 — McMap. All rights reserved.