Create ASP.NET Core with Vue.js SPA
Tags: vue, dotnet, aspnet, csharp
Published: 2023-08-28 05:25:44


### Required Tools

* [Node]("https://nodejs.org/en")
  * Version 14 or higher
* [.Net 6.0]("https://dotnet.microsoft.com/en-us/download/dotnet/6.0")
  * `winget install --id=Microsoft.DotNet.SDK.6 -e`

### Setup Project

#### Create Web Application

> `dotnet new webapi -n MyWebProject`

#### Create Vue Front-end

* Navigate inside your newly created Web Application project and create a new vue application:

> `npx create-vue@latest`
_At the time of writing, the current version includes: vue 3.3.4, vite 4.4.9 - it requires node 14.x to run._

* Name the vue project '__ClientApp__'

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5gu5k00ttcw2ha53p1in.png)

* The directory structure for you ASP.NET application should look like this:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0tpv1t12htc7o3jwmtqi.png)

### Add Necessary Packages

* Navigate to the Web Application folder and use the add package command:  

    `dotnet package add Microsoft.AspNetCore.SpaProxy --version 6.0.21`

Alternatively, you can add the package reference to your .csproj file and use the '__`dotnet restore`__' or '__`dotnet build`__' commands for immediate access to the namespace:

```csharp
<PackageReference Include="Microsoft.AspNetCore.SpaProxy" Version="6.0.21" />
```

### Configure Vite

* In your ClientApp directory, open the '__vite.config.js__' file, and edit the code to match the following:

```js
import { fileURLToPath, URL } from 'node:url';
import process from 'node:process';

//match the uri your web application is being hosted at
const proxyTarget = process.env.ASPNETCORE_HTTPS_PORT
  ? `https://localhost:${process.env.ASPNETCORE_HTTPS_PORT}`
  : process.env.ASPNETCORE_URLS
  ? process.env.ASPNETCORE_URLS.split(';')[0]
  : 'https://localhost:5001';

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url)),
    },
  },
  server: {
    port: 3001,
    proxy: {
      '^/weatherforecast': {
        target: proxyTarget,
        secure: false,
      },
      '^/swagger': {
        target: proxyTarget,
        secure: false,
      },
    },
  },
  build: {
    outDir: '../wwwroot',
    emptyOutDir: true,
  },
});
```

Now your Vue app will be served at <http://localhost:3001> and proxy requests to your backend at <https://localhost:5001>.

#####NOTE:  
You can configure vite and the spa proxy to serve your app over https, but that will be considered for another tutorial.

### Configure SPA proxy

* Open your __.csproj__ file and add the following fields in the first property group under `<TargetFramework>net6.0</TargetFramework>`:

  ```xml
    <SpaRoot>ClientApp\</SpaRoot>
    <DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
    <SpaProxyServerUrl>http://localhost:3001</SpaProxyServerUrl>
    <SpaProxyLaunchCommand>npm run dev</SpaProxyLaunchCommand>
  ```

* Observe that the '__SpaProxyLaunchCommand__' is `npm run dev` instead of `npm start`.
* The '__SpaProxyServerUrl__' must match the uri that your Vue app will be served at, which is set in the '__vite.config.js__' file, using the '__port__' keyword.
* Add the following fields to your __.csproj__ file for generation of artifacts when publishing:

  ```xml
  <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>

  <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->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
        <RelativePath>wwwroot\%(RecursiveDir)%(FileName)%(Extension)</RelativePath>
        <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
        <ExcludeFromSingleFile>true</ExcludeFromSingleFile>
      </ResolvedFileToPublish>
    </ItemGroup>
  ```

#### Configure launch settings

* Navigate to the launchSettings.json file in your Web Application project:

> Properties \> launchSettings.json

It should contain the following json content:

```json
      "applicationUrl": "https://localhost:5001",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development",
        "ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.SpaProxy"
      }
```

* Match the '__applicationUrl__' with the proxy target in your '__vite.config.json__' file.
* Add the '__ASPNETCORE_HOSTINGSTARTUPASSEMBLIES__' key with the value specified above.

### Modify Program.cs

Modify your '__Program.cs__' by adding the following lines before the map methods are called:

```csharp
app.UseStaticFiles();
app.MapFallbackToFile("index.html");
```

### Finished

Now you're finished creating an ASP.NET Core with Vue.js Application!

* You can run your project in Visual Studio or using the dotnet cli `dotnet run` command and you should see the SpaProxy loading page until the app content is served. Enjoy!