When serving up Angular 2 script and views, some people have chosen node.js or ASP.Net core server solutions that pre-render data into the angular views being delivered to the client, other implementations go the other way, adopting a simpler philosophy of just serving ‘flat’ unmodified script and HTML views. A few have gone part way, using webpack to collect bundles of views, styles and code. A few rely on ASP.Net Core to serve data using Web API and generally do not use Razor syntax, Tag Helpers or anything much of ASP.Net Cores’ features.
This series of posts will describe a middle ground, where we’ll leverage as much of ASP.Net Core as we can, give users the responsiveness that comes with Angular – delivering data from Web API and caching views where practical.
In the last step we added Angular, served from flat HTML, and had to browse index.html. Now we switch out index.html and replace this with a standard MVC view and use _layout.cshtml to handle the common content.
The standard ASP.Net Core MVC template has a Views Folder in which, by convention, are a folder corresponding to each controller, and in each folder a .CSHTML view corresponding to each method in these controllers.
Later we’ll add other MVC views but for now, drop out all views except home/index. So the Home controller should now look like this:
using Microsoft.AspNetCore.Mvc; namespace Angular2MultiSPA.Controllers { public class HomeController : Controller { public IActionResult Index() { return View(); } public IActionResult Error() { return View(); } } }
Next go to the views/home folder, edit index.cshtml and change it to this:
<my-app>Loading...</my-app>
Next go the views/shared folder and edit the _layout.cshtml file to this:
<!DOCTYPE html> < html> < head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>@ViewData["Title"] - Angular2MultiSPA</title> < link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" /> < link rel="stylesheet" href="~/css/site.css" /> </head> < body> < div class="container body-content"> @RenderBody() < hr /> < footer> < p>Angular2MultiSPA</p> </footer> </div> < script src="/node_modules/core-js/client/shim.min.js"></script> < script src="/node_modules/zone.js/dist/zone.js"></script> < script src="/node_modules/reflect-metadata/Reflect.js"></script> < script src="/node_modules/systemjs/dist/system.src.js"></script> < script src="~/systemjs.config.js"></script> < script> System.import('app').catch(function (err) { console.error(err); }); </script> @RenderSection("scripts", required: false) </body> </html>
NOTE: WordPress seems to filter out some of the HTML, particularly script tags. If you are having trouble please just go to GitHub to grab the source here.
Rather than repeat details of ASP.Net Core, please see the excellent documentation already covering this at https://docs.asp.net/en/latest/
You now should be able rebuild the application and see the same content at http://localhost:7010/index.html as at http://localhost:7010/home/index
Next we’ll replace the embedded angular view, which is simply an HTML string, with an HTML partial view. First add a new controller, alongside HomeController.cs called PartialController.cs in the Controllers folder:
using Microsoft.AspNetCore.Mvc; namespace Angular2MultiSPA.Controllers { /// <summary> /// Partial controller - delivers CSHTML partial views, for angular /// </summary> public class PartialController : Controller { public IActionResult AppComponent() => PartialView(); } }
Create a new folder called Partial in the Views folder, alongside Views/Home and Views/Shared, then in Views/Partial add a new CSHTML view called AppComponent.cshtml containing the following:
@{ // Angular 2 now with razor :) string counter = "Third"; } <h1>My @counter Angular {{1+1}} App</h1>
This simple snippet will demonstrate Razor syntax, albeit rather simple to begin with, and at the same time you’ll see it can be mixed with angular code {{1+1}}
Last step, we’ll change the app.component.ts file from serving embedded HTML to use the new partial component. Where app.component.ts had this:
import { Component } from '@angular/core'; @Component({ selector: 'my-app', template: '<h1>My First Angular 2 App</h1>' }) export class AppComponent { }
change it to have this:
import { Component } from '@angular/core'; @Component({ selector: 'my-app', templateUrl: '/partial/appComponent' }) export class AppComponent { }
You can now save changes to the app.component.ts file, then delete the original index.html file from the wwwroot folder, rebuild the app, and by browsing to http://localhost:7010 now see the partial view being rendered from our /views/partial/appcomponent.cshtml file, complete with injected server-side razor code and delivering from the server, angular code to kick in once it reaches the client.
Even though we’re only adding 1+1 for now, you now have the beginnings of a mechanism to serve intelligent pages – with ‘smarts’ at the server and at the client too.
NOTE: WordPress seems to filter out some of the HTML, particularly script tags. If you are having trouble please just go to GitHub to grab the source here. The final source is at https://github.com/RobertDyball/Angular2MultiSPA
Next post we’ll switch across from Bootstrap3.3.6 to the new (currently alpha) Bootstrap 4, add a simple Web API service to serve up data from the server, when requested by our angular code from the browser.