asp.net-coreelectronsingle-page-applicationelectron.net

How to use Electron.NET to wrap an ASP.NET Core Single Page Application


I created a SPA with ASP.NET Core and react/typescript by following this blog post: https://www.nolanbradshaw.ca/net-react-typescript-template

While debugging the project I use the following in my launchSettings.json

"MySPA": {
      "commandName": "Project",
      "launchBrowser": true,
      "applicationUrl": "http://localhost:5181",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development",
        "ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.SpaProxy"
      }
    }

The SpaProxy settings in my .csproj file look like this...

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <Nullable>enable</Nullable>
    <TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
    <TypeScriptToolsVersion>Latest</TypeScriptToolsVersion>
    <IsPackable>false</IsPackable>
    <SpaRoot>client-app\</SpaRoot>
    <DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
    <SpaProxyServerUrl>http://localhost:3000</SpaProxyServerUrl>
    <SpaProxyLaunchCommand>npm start</SpaProxyLaunchCommand>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="ElectronNET.API" Version="13.5.1" />
    <PackageReference Include="Microsoft.AspNet.SignalR.Core" Version="2.4.3" />
    <PackageReference Include="Microsoft.AspNetCore.SpaProxy" Version="6.0.10" />
    <PackageReference Include="Serilog.Extensions.Logging" Version="3.1.0" />
    <PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
  </ItemGroup>
  <ItemGroup>
    <!-- Don't publish the SPA source files, but do show them in the project files list -->
    <Content Remove="$(SpaRoot)**" />
    <None Remove="$(SpaRoot)**" />
    <None Include="$(SpaRoot)**" Exclude="$(SpaRoot)node_modules\**" />
  </ItemGroup>
  <ItemGroup>
    <None Remove="client-app\src\components\TestPage.tsx" />
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\Services\Services.csproj" />
  </ItemGroup>
  <ItemGroup>
    <TypeScriptCompile Include="client-app\src\components\TestPage.tsx" />
  </ItemGroup>
  <Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('$(SpaRoot)node_modules') ">
    <!-- Ensure Node.js is installed -->
    <Exec Command="node --version" ContinueOnError="true">
      <Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
    </Exec>
    <Error Condition="'$(ErrorCode)' != '0'" Text="Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE." />
    <Message Importance="high" Text="Restoring dependencies using 'npm'. This may take several minutes..." />
    <Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
  </Target>
  <Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
    <!-- As part of publishing, ensure the JS resources are freshly built in production mode -->
    <Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
    <Exec WorkingDirectory="$(SpaRoot)" Command="npm run build" />
    <!-- Include the newly-built files in the publish output -->
    <ItemGroup>
      <DistFiles Include="$(SpaRoot)build\**" />
      <ResolvedFileToPublish Include="@(DistFiles-&gt;'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
        <RelativePath>wwwroot\%(RecursiveDir)%(FileName)%(Extension)</RelativePath>
        <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
        <ExcludeFromSingleFile>true</ExcludeFromSingleFile>
      </ResolvedFileToPublish>
    </ItemGroup>
  </Target>
  <ItemGroup>
    <Content Update="electron.manifest.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
  </ItemGroup>
</Project>

I would now like to wrap this project with Electron.net in order to run it as a local desktop app. I have installed nuget packages and followed setup instructions on the Electron.net github. I run my app via electionize start, everything looks to build correctly, and it opens up a blank electron window. The last few lines of my electronize output look like this.

ElectronHostHook handling started...
Invoke electron.cmd - in dir: C:\s-lab\repos\LxTraderV3\LxTraderV3\LxTraderV3\obj\Host\node_modules\.bin
electron.cmd "..\..\main.js"

Electron Socket IO Port: 8000
Electron Socket started on port 8000 at 127.0.0.1
ASP.NET Core Port: 8001
stdout: Use Electron Port: 8000

stdout: ASP.NET Core host has fully started.

ASP.NET Core Application connected... global.electronsocket iBNLmdfbkcPJRNlyAAAA 2023-03-01T21:45:18.720Z
stdout: BridgeConnector connected!

When I look at the developer tools in electron I see a request to http://localhost:8001/ with 404 error.

Where do I go from here to properly configure electron to host my project?


Solution

  • Please don't use the repo from the blog, there are some issues related the npm package.

    At first, I want use the repo in that blog and always failed in my side, maybe I am using high version of npm and node. It always failed, then I create a new project with .net5. And it works.

    You also can try to add any kind of web project and then use the electron, if you have finished your project, you need to make sure your project can run normally before using electron.

    My Test Result

    The output log in my side is different than you. And I found you are missing below.

    info
    stdout: : Microsoft.Hosting.Lifetime[0]
          Now listening on: http://localhost:8003
    info: Microsoft.Hosting.Lifetime[0]
          Application started. Press Ctrl+C to shut down.
    info
    stdout: : Microsoft.Hosting.Lifetime[0]
          Hosting environment: Production
    info: Microsoft.Hosting.Lifetime[0]
          Content root path: F:\AspNetCore\ReactTypeScript.NET-master\Project2\obj\Host\bin
    

    My logs

    ElectronHostHook handling started...
    Invoke electron.cmd - in dir: F:\AspNetCore\ReactTypeScript.NET-master\Project2\obj\Host\node_modules\.bin
    electron.cmd "..\..\main.js"
    
    Electron Socket IO Port: 8000
    Electron Socket started on port 8000 at 127.0.0.1
    ASP.NET Core Port: 8003
    stdout: Use Electron Port: 8000
    
    stdout: ASP.NET Core host has fully started.
    info
    stdout: : Microsoft.Hosting.Lifetime[0]
          Now listening on: http://localhost:8003
    info: Microsoft.Hosting.Lifetime[0]
          Application started. Press Ctrl+C to shut down.
    info
    stdout: : Microsoft.Hosting.Lifetime[0]
          Hosting environment: Production
    info: Microsoft.Hosting.Lifetime[0]
          Content root path: F:\AspNetCore\ReactTypeScript.NET-master\Project2\obj\Host\bin
    
    ASP.NET Core Application connected... global.electronsocket Jk0Cek48X1fg_pmtAAAA 2023-03-03T08:16:13.333Z
    stdout: BridgeConnector connected!
    
    stdout: warn: Microsoft.AspNetCore.HttpsPolicy.HttpsRedirectionMiddleware[3]
          Failed to determine the https port for redirect.
    

    I also following the doc, add below code in project. And it works fine.

    enter image description here

    enter image description here