0

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)
kal93
  • 522
  • 1
  • 9
  • 22

2 Answers2

1

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

Eliseo
  • 50,109
  • 4
  • 29
  • 67
0

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).

inthevortex
  • 334
  • 5
  • 20
  • Correct me if I'm wrong but your answer seems to be referring to Net Core. Will this work in. NET? I appreciate your help. – kal93 Jan 17 '18 at 10:19
  • Yes, this refers to .net core. If you .net application isn't already in development, you can consider using .net core as it is more decoupled compared to .net framework. This is a way to couple .net core MVC/API app with an angular app. – inthevortex Jan 17 '18 at 10:39
  • You can follow this [tutorial](https://www.codeproject.com/Articles/1181888/Angular-in-ASP-NET-MVC-Web-API-Part) along with it's subsequent ones to combine your angular and .net461 app together. But this uses some old things, like systemjs.config instead of webpack, etc. Hope you like this solution if you want to strictly go for .net461 – inthevortex Jan 17 '18 at 10:43
  • Thanks. I've seen it before but it doesn't use razor views. Uses just inline html in TS files. – kal93 Jan 17 '18 at 10:49
  • @kal93 you can use inline html inside ts file or you can write a separate html file and give that path in the ts file. That's basically how angular works. The tutorial did that for the simplicity of things. If you need help in building your angular app, read the [tutorial here](https://angular.io/tutorial). This will help you out. – inthevortex Jan 17 '18 at 11:08
  • Let me ask it this way : Is it possible to use .cshtml & razor syntax for angular templates with path location routing.Something that was possible in AngularJS where you could write some of razor code in partial views. – kal93 Jan 17 '18 at 11:16
  • @kal93 no that was possible with angularjs which is angular v1 and currently the version widely used is either angular4 or angular5 (very new). From angular2 this has been changed. So you will have 2 stand alone apps, one of angular having apis to connect with the .net core apis to get the data which is being processed by the backend. Hope you understand the change in architecture. – inthevortex Jan 17 '18 at 13:18