kal93
kal93

Reputation: 572

Angular with Razor views & .NET MVC5

I've been trying to make PathLocation(i.e without ' # ' in the URL) routing angular work with razor views in .NET MVC and have had no luck so far.

AppComponent

// app component
import { Component} from '@angular/core'

        @Component({
            moduleId: module.id,
            selector: 'app-root',
            templateUrl: '/Harness2.0/Main/app',// -> MVC controller 
            styleUrls: ['app.component.css']
        })

AppHeader TS

// app-header.ts
import { Component } from '@angular/core';

@Component({
    moduleId: module.id,
    selector: 'app-header-demo',
    templateUrl: '/Harness2.0/Component/AppHeader',
})

Angular Routing Module:

const appRoutes: Routes = [
    { path: 'appheader-test', component: AppHeaderTestComponent },  
    { path: '', redirectTo: '/', pathMatch: 'full' },

];

Index.cshtml

@{
    ViewBag.Title = "Harness 2.0";
}
<!DOCTYPE html>
<html>
<head>
    <base href="./" />
    <title>@ViewBag.Title</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- Load styles -->
    @Styles.Render("~/Content/css")
    @Styles.Render("~/Content/material")
    <!-- Load libraries & Configure SystemJS -->
    @Scripts.Render("~/scripts/ng")
    <script>
        System.import('src').catch(function (err) {
            console.error(err);
        });
    </script>
</head>
<body>
    <app-root>Loading app-root...</app-root>
</body>
</html>

RouteConfig.cs

routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional, }
            );

routes.MapRoute(
                name: "NotFound",
                url: "{*catchall}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );

HomeController.cs

public class HomeController : Controller
    {

        public ActionResult Index()
        {
            return View();
        }
    }

MainController.cs

public class MainController : Controller
    {

        public ActionResult App()
        {
            return View();
        }
    }

ComponentsController.cs

public class ComponentController : Controller
    {

        public ActionResult AppHeader()
        {
            return View();
        }
    }

When the application fist loads the URL is http://localhost/Harness2.0/ & the MVC rotuer defaults to HomeController & Index.cshtml is loaded where <app-root> is present.When I navigate to http://localhost/Harness2.0/app-header the components view is loaded & on browser refresh(F5) I get Not found 404 which makes sense as the entire URL goes over to the server & there's no Controller action associated with that particular URL.

One solution I tried was IIS URL Rewrite

<rewrite>
      <rules>
        <rule name="Rewrite URL" stopProcessing="true">
          <match url=".*" />
          <conditions logicalGrouping="MatchAll">
            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
            <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
          </conditions>
          <action type="Rewrite" url="./" />
        </rule>
      </rules>
    </rewrite>

This renders the Index on refresh but instead of bootstrapping the AppModule it directly enters the app.component.ts where I have some console logs in the constructor which run infinitely until call stack size exceeds.

Any help in this would be much appreciated.

P.S:

I have tried the hash location strategy by using useHash property in RouterModule & everything works fine with it. But I've to make it work with PathLocation which I haven't been able to so far.Also I'm not using .NET Core.

Other related links:

  1. http://knightcodes.com/angular2/2017/01/04/angular-2-routes-with-asp-net-mvc.html
  2. ASP.NET 5 + Angular 2 routing (template page not REloading)

Upvotes: 0

Views: 3815

Answers (2)

inthevortex
inthevortex

Reputation: 334

I have also tried it in a different manner than Eliseo. This is the Configure method of my Startup class.

Startup.cs

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.Use(async (context, next) => {
                await next();
                if (context.Response.StatusCode == 404 &&
                    !Path.HasExtension(context.Request.Path.Value) &&
                    !context.Request.Path.Value.StartsWith("/api/"))
                {
                    context.Request.Path = "/index.html";
                    await next();
                }
            });

            app.UseMvcWithDefaultRoute();

            app.UseDefaultFiles();
            app.UseStaticFiles();
        }

launchSettings.json

{
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:49600/",
      "sslPort": 0
    }
  },
  "profiles": {
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "AngularCoreDemo": {
      "commandName": "Project",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "applicationUrl": "http://localhost:5000/"
    }
  }
}

You will also have to add a proxy class so that the /api requests are routed to localhost:5000 (.net core app) and the other requests are routed to localhost:4200 (angular app).

proxy.config.json

{
  "/api": {
    "target": "http://localhost:5000",
    "secure":  false
  }
}

You need to build your angular app so that the static files rest in wwwroot folder and need to start the server from command line giving the proxy file as argument (please look up the exact syntax).

Upvotes: 0

Eliseo
Eliseo

Reputation: 58039

Kal93, if you're using angular, you needn't use routerConfig.cs. Your page it's always the same (index.cshtml). e.g. in my .NET Core 2.0 I have

    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");

        routes.MapSpaFallbackRoute(
            name: "spa-fallback",
            defaults: new { controller = "Home", action = "Index" });
    });

Is Angular who manage the router

Upvotes: 1

Related Questions