Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React.NET fails when using Docker #1274

Open
atlidev opened this issue Dec 12, 2021 · 3 comments
Open

React.NET fails when using Docker #1274

atlidev opened this issue Dec 12, 2021 · 3 comments

Comments

@atlidev
Copy link

atlidev commented Dec 12, 2021

I'm using these library versions:

  • ReactJS.NET: 5.2.12
  • JavaScriptEngineSwitcher: Chakra 3.16.0
  • react and react-dom: (bundled)
  • docker: v20.10.6

Runtime environment:

  • OS: Windows 10 (64bit)
  • .NET Framework or .NET Core Version: .NET core 3.1

Steps to reproduce

  1. Install the "QuickStart" template
dotnet new -i React.Template
dotnet new reactnet-vanilla
  1. Add the following files:
    Dockerfile
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-alpine AS base

ARG BUILDCONFIG=RELEASE

RUN apk update && apk add libgdiplus libgdiplus-dev --update-cache --repository http://dl-3.alpinelinux.org/alpine/edge/testing/ --allow-untrusted
# copy csproj and restore as distinct layers
COPY ./tutorial-code.csproj ./ReactDotNetProject/
RUN dotnet restore ReactDotNetProject/tutorial-code.csproj

# copy everything else and build
COPY ./ ./ReactDotNetProject/
RUN dotnet publish ReactDotNetProject/tutorial-code.csproj --runtime linux-musl-x64 -c $BUILDCONFIG -o out

# build runtime image
FROM mcr.microsoft.com/dotnet/core/runtime-deps:3.1-alpine

RUN apk update && apk add terminus-font libgdiplus libgdiplus-dev --update-cache --repository http://dl-3.alpinelinux.org/alpine/edge/testing/ --allow-untrusted
ENV ASPNETCORE_URL=http//+:5000
ENV ASPNETCORE_ENVIRONMENT Production

# Expose port 5000 on the container
COPY . /app
WORKDIR /app

COPY --from=base /out ./

EXPOSE 5000
ENTRYPOINT ["./tutorial-code"]

docker-compose.yml

reactdotnet:
    build: .
    ports: 
        - "5000:5000"
  1. Change Program.cs to the following:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;

namespace ReactDemo
{
    public class Program
    {
         public static void Main(string[] args)
        {
            CreateHostBuilder(args)
            .Build()
            .Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>().UseUrls(new[] { "http://0.0.0.0:5000" });  // used for docker connection, will be on localhost on own machine
                });
    }
}

  1. Run docker-compose up --build

  2. Visit localhost:5000 in browser.

Expected Error:

reactdotnet_1  | warn: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[60]
reactdotnet_1  |       Storing keys in a directory '/root/.aspnet/DataProtection-Keys' that may not be persisted outside of the container. Protected data will be unavailable when container is destroyed.
reactdotnet_1  | info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0]
reactdotnet_1  |       User profile is available. Using '/root/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest.
reactdotnet_1  | info: Microsoft.Hosting.Lifetime[0]
reactdotnet_1  |       Now listening on: http://0.0.0.0:5000
reactdotnet_1  | info: Microsoft.Hosting.Lifetime[0]
reactdotnet_1  |       Application started. Press Ctrl+C to shut down.
reactdotnet_1  | info: Microsoft.Hosting.Lifetime[0]
reactdotnet_1  |       Hosting environment: Production
reactdotnet_1  | info: Microsoft.Hosting.Lifetime[0]
reactdotnet_1  |       Content root path: /app
reactdotnet_1  | info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
reactdotnet_1  |       Request starting HTTP/1.1 GET http://localhost:5000/
reactdotnet_1  | info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
reactdotnet_1  |       Executing endpoint 'ReactDemo.Controllers.HomeController.Index (tutorial-code)'
reactdotnet_1  | info: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[3]
reactdotnet_1  |       Route matched with {action = "Index", controller = "Home"}. Executing controller action with signature Microsoft.AspNetCore.Mvc.ActionResult Index() on controller ReactDemo.Controllers.HomeController (tutorial-code).
reactdotnet_1  | info: Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor[1]
reactdotnet_1  |       Executing ViewResult, running view Index.
reactdotnet_1  | info: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[2]
reactdotnet_1  |       Executed action ReactDemo.Controllers.HomeController.Index (tutorial-code) in 121.9638ms
reactdotnet_1  | info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
reactdotnet_1  |       Executed endpoint 'ReactDemo.Controllers.HomeController.Index (tutorial-code)'
reactdotnet_1  | fail: Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware[1]
reactdotnet_1  |       An unhandled exception has occurred while executing the request.
reactdotnet_1  | React.Exceptions.ReactNotInitialisedException: ReactJS.NET has not been initialised correctly. Please ensure you have called services.AddReact() and app.UseReact() in your Startup.cs file.
reactdotnet_1  |  ---> React.TinyIoC.TinyIoCResolutionException: Unable to resolve type: React.ReactEnvironment
reactdotnet_1  |  ---> React.TinyIoC.TinyIoCResolutionException: Unable to resolve type: React.JavaScriptEngineFactory
reactdotnet_1  |  ---> JavaScriptEngineSwitcher.Core.JsEngineLoadException: Failed to create instance of the ChakraCoreJsEngine. Most likely it happened, because the 'libChakraCore.so' assembly or one of its dependencies was not found. Try to install the JavaScriptEngineSwitcher.ChakraCore.Native.linux-x64 package via NuGet.
reactdotnet_1  |
reactdotnet_1  | Engine name: ChakraCoreJsEngine
reactdotnet_1  | Engine version: 1.11.13
reactdotnet_1  | Category: Engine load error
reactdotnet_1  | Description: Most likely it happened, because the 'libChakraCore.so' assembly or one of its dependencies was not found. Try to install the JavaScriptEngineSwitcher.ChakraCore.Native.linux-x64 package via NuGet. ---> System.DllNotFoundException: Unable to load shared library 'ChakraCore' or one of its dependencies. In order to help diagnose loading problems, consider setting the LD_DEBUG environment variable: Error loading shared library libChakraCore: No such file or directory
reactdotnet_1  |    at JavaScriptEngineSwitcher.ChakraCore.JsRt.NativeMethods.JsCreateRuntime(JsRuntimeAttributes attributes, JsThreadServiceCallback threadService, JsRuntime& runtime)
reactdotnet_1  |    at JavaScriptEngineSwitcher.ChakraCore.JsRt.JsRuntime.Create(JsRuntimeAttributes attributes, JsThreadServiceCallback threadServiceCallback)
reactdotnet_1  |    at JavaScriptEngineSwitcher.ChakraCore.ChakraCoreJsEngine.<>c__DisplayClass10_1.<.ctor>b__0()
reactdotnet_1  |    at JavaScriptEngineSwitcher.ChakraCore.ScriptDispatcher.<>c__DisplayClass11_0.<Invoke>b__0()
reactdotnet_1  |    at JavaScriptEngineSwitcher.ChakraCore.ScriptDispatcher.StartThread()
reactdotnet_1  | --- End of stack trace from previous location where exception was thrown ---
reactdotnet_1  |    at JavaScriptEngineSwitcher.ChakraCore.ScriptDispatcher.InnnerInvoke(Func`1 del)
reactdotnet_1  |    at JavaScriptEngineSwitcher.ChakraCore.ScriptDispatcher.Invoke(Action action)
reactdotnet_1  |    at JavaScriptEngineSwitcher.ChakraCore.ChakraCoreJsEngine..ctor(ChakraCoreSettings settings)
reactdotnet_1  |    at JavaScriptEngineSwitcher.ChakraCore.ChakraCoreJsEngine..ctor(ChakraCoreSettings settings)
reactdotnet_1  |    at JavaScriptEngineSwitcher.ChakraCore.ChakraCoreJsEngineFactory.CreateEngine()
reactdotnet_1  |    at JSPool.JsPool`2.CreateEngine()
reactdotnet_1  |    at JSPool.JsPool`2.PopulateEngines()
reactdotnet_1  |    at JSPool.JsPool`2..ctor(JsPoolConfig`1 config)
reactdotnet_1  |    at JSPool.JsPool..ctor(JsPoolConfig config)
reactdotnet_1  |    at React.JavaScriptEngineFactory.CreatePool()
reactdotnet_1  |    at React.JavaScriptEngineFactory..ctor(IJsEngineSwitcher jsEngineSwitcher, IReactSiteConfiguration config, ICache cache, IFileSystem fileSystem)
reactdotnet_1  |    at lambda_method(Closure , Object[] )
reactdotnet_1  |    at React.TinyIoC.TinyIoCContainer.ConstructType(Type requestedType, Type implementationType, ConstructorInfo constructor, NamedParameterOverloads parameters, ResolveOptions options)
reactdotnet_1  |
reactdotnet_1  |    --- End of inner exception stack trace ---
reactdotnet_1  |    at React.TinyIoC.TinyIoCContainer.ConstructType(Type requestedType, Type implementationType, ConstructorInfo constructor, NamedParameterOverloads parameters, ResolveOptions options)
reactdotnet_1  |    at React.TinyIoC.TinyIoCContainer.ConstructType(Type requestedType, Type implementationType, ConstructorInfo constructor, ResolveOptions options)
reactdotnet_1  |    at React.TinyIoC.TinyIoCContainer.SingletonFactory.GetObject(Type requestedType, TinyIoCContainer container, NamedParameterOverloads parameters, ResolveOptions options)
reactdotnet_1  |    at React.TinyIoC.TinyIoCContainer.ResolveInternal(TypeRegistration registration, NamedParameterOverloads parameters, ResolveOptions options)
reactdotnet_1  |    at React.TinyIoC.TinyIoCContainer.ConstructType(Type requestedType, Type implementationType, ConstructorInfo constructor, NamedParameterOverloads parameters, ResolveOptions options)
reactdotnet_1  |    --- End of inner exception stack trace ---
reactdotnet_1  |    at React.TinyIoC.TinyIoCContainer.ConstructType(Type requestedType, Type implementationType, ConstructorInfo constructor, NamedParameterOverloads parameters, ResolveOptions options)
reactdotnet_1  |    at React.TinyIoC.TinyIoCContainer.ConstructType(Type requestedType, Type implementationType, ConstructorInfo constructor, ResolveOptions options)
reactdotnet_1  |    at React.TinyIoC.TinyIoCContainer.CustomObjectLifetimeFactory.GetObject(Type requestedType, TinyIoCContainer container, NamedParameterOverloads parameters, ResolveOptions options)
reactdotnet_1  |    at React.TinyIoC.TinyIoCContainer.ResolveInternal(TypeRegistration registration, NamedParameterOverloads parameters, ResolveOptions options)
reactdotnet_1  |    at React.TinyIoC.TinyIoCContainer.Resolve(Type resolveType)
reactdotnet_1  |    at React.TinyIoC.TinyIoCContainer.Resolve[ResolveType]()
reactdotnet_1  |    at React.ReactEnvironment.get_Current()
reactdotnet_1  |    at React.ReactEnvironment.get_GetCurrentOrThrow()
reactdotnet_1  |    --- End of inner exception stack trace ---
reactdotnet_1  |    at React.ReactEnvironment.get_GetCurrentOrThrow()
reactdotnet_1  |    at React.AspNet.HtmlHelperExtensions.get_Environment()
reactdotnet_1  |    at React.AspNet.HtmlHelperExtensions.React[T](IHtmlHelper htmlHelper, String componentName, T props, String htmlTag, String containerId, Boolean clientOnly, Boolean serverOnly, String containerClass, Action`3 exceptionHandler, IRenderFunctions renderFunctions)
reactdotnet_1  |    at AspNetCore.Views_Home_Index.<ExecuteAsync>b__8_1() in /ReactDotNetProject/Views/Home/Index.cshtml:line 10
reactdotnet_1  |    at Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperExecutionContext.SetOutputContentAsync()
reactdotnet_1  |    at AspNetCore.Views_Home_Index.ExecuteAsync() in /ReactDotNetProject/Views/Home/Index.cshtml:line 3
reactdotnet_1  |    at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageCoreAsync(IRazorPage page, ViewContext context)
reactdotnet_1  |    at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageAsync(IRazorPage page, ViewContext context, Boolean invokeViewStarts)
reactdotnet_1  |    at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderAsync(ViewContext context)
reactdotnet_1  |    at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, String contentType, Nullable`1 statusCode)
reactdotnet_1  |    at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ActionContext actionContext, IView view, ViewDataDictionary viewData, ITempDataDictionary tempData, String contentType, Nullable`1 statusCode)
reactdotnet_1  |    at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor.ExecuteAsync(ActionContext context, ViewResult result)
reactdotnet_1  |    at Microsoft.AspNetCore.Mvc.ViewResult.ExecuteResultAsync(ActionContext context)
reactdotnet_1  |    at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResultFilterAsync>g__Awaited|29_0[TFilter,TFilterAsync](ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
reactdotnet_1  |    at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)
reactdotnet_1  |    at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)
reactdotnet_1  |    at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters()
reactdotnet_1  | --- End of stack trace from previous location where exception was thrown ---
reactdotnet_1  |    at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
reactdotnet_1  |    at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
reactdotnet_1  |    at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
reactdotnet_1  |    at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
reactdotnet_1  | --- End of stack trace from previous location where exception was thrown ---
reactdotnet_1  |    at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
reactdotnet_1  |    at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
reactdotnet_1  |    at React.AspNet.BabelFileMiddleware.Invoke(HttpContext context)
reactdotnet_1  |    at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task)
reactdotnet_1  | info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
reactdotnet_1  |       Request finished in 228.19910000000002ms 404
reactdotnet_1  | info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
reactdotnet_1  |       Request starting HTTP/1.1 GET http://localhost:5000/favicon.ico
reactdotnet_1  | info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
reactdotnet_1  |       Request finished in 6.6058ms 404

This is a surprising error since the tutorial-code.csproj file has the JavascriptEngineSwitcher.ChakraCore.native.linux-x64 package.
When I run dotnet run and visit localhost:5000 (on Windows), the program works as expected.
When I shell into the docker container it also seems to be installing the JavascriptEngineSwitcher.ChakraCore.native.linux-x64 package.

What can be done to fix this? All help is appreciated

@dustinsoftware
Copy link
Member

dustinsoftware commented Dec 12, 2021 via email

@Daniel15
Copy link
Member

Since the stack trace is in JavaScriptEngineSwitcher, you could try asking @Taritsyn over in the project's repo: https://github.com/Taritsyn/JavaScriptEngineSwitcher/issues

@atlidev
Copy link
Author

atlidev commented Dec 13, 2021

I'll try asking there. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants