Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle routes by VueJS in ASP.NET core using Endpoints?

Am trying to create a VueJS SPA with ASP.NET core in the backend

Since dotnet SDK version 3.0.100 no longer supports Vue, I created a React app

dotnet new react

and swapped the ClientApp with a Vue app

rm -rf ClientApp
vue create frontend

Everything works perfectly except for 1 thing

Whenever I launch the app http://localhost:5000 and click on any Vue Router link, say http://localhost:5000/about (it works) but if I refresh I get an expected 404

Cannot GET /about

Same goes if I typed the URL into the browser and access directly

It's worth noting that the default React app doesn't face this problem, I compared everything between the files of the two ASP.NET apps using this tool and found no differences

Now Vue Router handles routes by Javascript because it's using the #!hash behind the scenes, so ASP.NET router tries to match the URL to an AboutController@index which doesn't exist hence the 404

Researching revealed that I should set a wildcard fallback to the SPA router in Startup.cs, but all the answers I found here, here, here, this question, answer here, this question and this one are using app.UseMvc() and I don't have that enabled, I am using app.UseEndpoints instead

I also tried searching GitHub but same results

This Answer recommends I stick to app.UseEndPoints and Microsoft migration guide too

The Vue Router Documentation talks about this very issue and proposes a solution for .NET apps using web.config for IIS like the answer here but am running Kestrel server on a Linux machine so this takes no effect

Here's my Startup.cs file

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.SpaServices.ReactDevelopmentServer;

namespace spa
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {

            services.AddControllersWithViews();

            // In production, the Vue files will be served from this directory
            services.AddSpaStaticFiles(configuration =>
            {
                configuration.RootPath = "frontend/dist";
            });
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseStaticFiles();

            app.UseSpaStaticFiles();

            app.UseRouting();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller}/{action=Index}/{id?}");
            });

            app.UseSpa(spa =>
            {
                spa.Options.SourcePath = "frontend";

                if (env.IsDevelopment())
                {
                    spa.UseReactDevelopmentServer(npmScript: "serve:bs");
                }
            });
        }
    }
}

I pushed this app to GitHub here to make it easy to reproduce just in case I forgot something

How can I achieve the same effect of this

app.UseMvc(routes =>
{
  routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}");
  routes.MapRoute("spa-fallback", "{*anything}", new { controller = "Home", action = "Index" });
});

using app.UseEndpoints?


Just in case this is relevant, here's my Vue router

import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'
import NotFound from './views/NotFound.vue'

Vue.use(Router)

export default new Router({
    mode: 'history',
    base: process.env.BASE_URL,
    routes: [{
            path: '/',
            name: 'home',
            component: Home
        },
        {
            path: '/about',
            name: 'about',
            // route level code-splitting
            // this generates a separate chunk (about.[hash].js) for this route
            // which is lazy-loaded when the route is visited.
            component: () => import( /* webpackChunkName: "about" */ './views/About.vue')
        },
        {
            path: '/forecast',
            name: 'forecast',
            component: () => import( /* webpackChunkName: "forecast" */ './views/Forecast.vue')
        },
        {
            path: '*',
            component: NotFound
        }
    ]
})
like image 220
Salim Djerbouh Avatar asked Sep 28 '19 17:09

Salim Djerbouh


People also ask

What is endpoint routing in ASP NET Core?

The Endpoint Routing is the Process by which ASP.NET Core inspects the incoming HTTP requests and maps them to applications executable Endpoint. We define the Endpoint during the application startup. The Routing Module then matches the incoming URL to an Endpoint and dispatches the request to it.

How does vue router handle routes by JavaScript?

Now Vue Router handles routes by Javascript because it's using the #!hash behind the scenes, so ASP.NET router tries to match the URL to an AboutController@index which doesn't exist hence the 404

What are the basics of Vue JS?

We’re also going to see the basics of Vue JS such as conditional statements and data binding. To start, let’s create a new project in visual studio.

How do I integrate Vue with empty ASP NET Web API?

Search for Vue in the search bar at the top and then select Standalone JavaScript Vue Template or Standalone TypeScript Vue Template. Give your project and solution a name. When you get to the Additional information window, be sure to check the Add integration for Empty ASP.NET Web API Project option.


1 Answers

Try this template https://github.com/SoftwareAteliers/asp-net-core-vue-starter. It's recently updated and support .Net Core 3.0 and Vue CLI 3.0.

like image 109
Fernando Feliciano Jr. Avatar answered Sep 28 '22 19:09

Fernando Feliciano Jr.