ASP.NET Core 2 and Angular 5

4.4 (20 reviews total)
By Valerio De Sanctis
  • Instant online access to over 7,500+ books and videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies
  1. Getting Ready

About this book

Become fluent in both frontend and backend web development by combining the impressive capabilities of ASP.NET Core 2 and Angular 5 from project setup right through the deployment phase.

Full-stack web development means being able to work on both the frontend and backend portions of an application. The frontend is the part that users will see or interact with, while the backend is the underlying engine, that handles the logical flow: server configuration, data storage and retrieval, database interactions, user authentication, and more.

Use the ASP.NET Core MVC framework to implement the backend with API calls and server-side routing. Learn how to put the frontend together using top-notch Angular 5 features such as two-way binding, Observables, and Dependency Injection, build the Data Model with Entity Framework Core, style the frontend with CSS/LESS for a responsive and mobile-friendly UI, handle user input with Forms and Validators, explore different authentication techniques, including the support for third-party OAuth2 providers such as Facebook, and deploy the application using Windows Server, SQL Server, and the IIS/Kestrel reverse proxy.

Publication date:
November 2017
Publisher
Packt
Pages
550
ISBN
9781788293600

 

Chapter 1. Getting Ready

ASP.NET Core MVC is a framework that runs on top of the full .NET framework (Windows) or .NET Core (cross-platform), specifically made for building efficient HTTP services that will be able to be reached by a massive range of clients, including web browsers, mobile devices, smart TVs, web-based home automation tools, and more.

Angular is the successor of AngularJS, a world-renowned development framework born with the idea of providing the coder with the toolbox needed to build reactive and cross-platform web-based apps optimized for desktop and mobile. It features a structure-rich template approach based upon a natural, easy-to-write, and readable syntax.

Technically, these two frameworks have little or nothing in common: ASP.NET Core is mostly focused on the server-side part of the web development stack, while Angular is dedicated to cover all the client-side aspects of web applications such as UI and UX. However, they were put together here because they share a common vision--the HTTP protocol is not limited to serving web pages; it can also be used as a viable platform to build web-based APIs to effectively send and receive data. A thought that slowly made its way through the first 20 years of the World Wide Web and is now an undeniable, widely acknowledged statement and also a fundamental pillar of almost every modern web development approach.

As for the reasons behind this perspective switch, there are plenty of good reasons for that, the most important of them being related to the intrinsic characteristics of the HTTP protocol: rather simple to use, and flexible enough to match most development needs of the always-changing environment that the World Wide Web happens to be in. Not to mention how universal it has become nowadays--almost any platform that we can think of has an HTTP library, so HTTP services can reach a broad range of clients, including browsers, mobile devices, and traditional desktop applications.

 

Two players, one goal


From the perspective of a fully-functional web-based application, we can say that the web API interface provided with the ASP.NET Core framework is a programmatic set of server-side handlers used by the server to expose a number of hooks and/or endpoints to a defined request-response message system, typically expressed in structured markup languages, such as JSON or XML. As we already said, this is achieved by making good use of the HTTP protocol handled by a publicly-available web server (typically IIS). Similarly, Angular can be described as a modern, feature-rich client-side library that pushes the HTML5 features--along with the modern browser's capabilities--to their full extent by binding the input and/or output parts of an HTML web page into a flexible, reusable, and easily testable JavaScript model.

These assumptions allow us to answer to a simple, yet inevitable question "can we combine the backend strengths of ASP.NET Core's web API with the frontend capabilities of the Angular framework in order to build a modern, feature-rich, and highly versatile web application?

The answer, in short terms, is yes. In the following chapters, we'll see how we can do that by analyzing all the fundamental aspects of a well-written, properly designed web-based product, and how ASP.NET Core and/or Angular can be used to handle each one of them.

The ASP.NET core revolution

To summarize what happened in the ASP.NET world within the last two years is not an easy task; in short words, we can say that we're undoubtedly facing the most important series of changes in the .NET Framework since the year it came to life. ASP.NET Core 1.0, which came out in Q3 2016, was a complete re-implementation of the ASP.NET we knew; the brand new framework unites all the previous web application technologies, such as MVC, Web API, and web pages, into a single programming module, formerly known as MVC6. The new framework introduces a fully-featured cross-platform component, also known as .NET Core, shipped with a brand new open source .NET Compiler Platform (currently known as Roslyn), a cross-platform runtime (known as CoreCLR), and an improved x64 Just-In-Time compiler (RyuJIT).

The 1.0 final release was shortly followed by ASP.NET Core 1.1 (Q4 2016), which brought some new features and performance enhancements, and also addressed many bugs and compatibility issues affecting the former one.

The third and, at the time of writing, the latest step was taken with ASP.NET Core 2.0, which came out in Q2 2017 as a preview and then in Q3 2017 for the final release; the newer version features among a number of significant improvements with a huge effort to standardize the shared APIs among the .NET Framework, .NET Core, and Xamarin, making it easy for developers to share and reuse code across the whole .NET ecosystem.

Note

Someone might be wondering about what happened to ASP.NET 5 and Web API 2, as these used to be quite popular names until mid-2016. ASP.NET 5 was no less than the original name of ASP.NET Core, before the developers chose to rename it to emphasize the fact that it is a complete rewrite. The reasons for that, along with the Microsoft vision about the new product, are further explained in the following Scott Hanselman's blog post that anticipated the changes on Jan 16, 2016:http://www.hanselman.com/blog/ASPNET5IsDeadIntroducingASPNETCore10AndNETCore10.aspx For those who don't know, Scott Hanselman is the outreach and community manager for .NET/ASP.NET/IIS/Azure and Visual Studio since 2007. Additional information regarding the perspective switch is also available in the following article by Jeffrey T. Fritz, Program Manager for Microsoft and NuGet team leader:https://blogs.msdn.microsoft.com/webdev/2016/02/01/an-update-on-asp-net-core-and-net-core/ As for Web API 2, it was a dedicated framework for building HTTP services returning pure JSON or XML data instead of web pages. Initially born as an alternative to the MVC platform, it has been merged with the latter into the new, general-purpose web application framework known as MVC6, which is now shipped as a separate module of ASP.NET Core.

What's new in Angular?

The new release of AngularJS, simply known as Angular, is a complete rewrite of the previous one, entirely based upon TypeScript and ECMAScript 6 specifications.

Note

If you're a seasoned web developer, most likely, you already know what TypeScript is. In case you don't, no worries, we'll get to that later on.

The choice of not making Angular backward compatible with AngularJS clearly demonstrates the intention of the author's team to adopt a completely new approach--any developer who already knows AngularJS will undoubtedly face a huge number of breaking changes, not only in the code syntax, but also in the way of thinking and designing the client app. Angular is highly modular, component-based, comes with a new and improved dependency injection model and a whole lot of programming patterns its older cousin never heard of.

However, the most important reason we're picking Angular over other excellent JS libraries such as ReactJS and EmberJS is the fact that it already comes out with a huge pack of features out of the box, making it most suited, although maybe not as simple to use than the aforementioned competitors; if we combine that with the consistency given by the TypeScript language, we can say that despite being the youngster, Angular embraced the framework approach more convincingly than the others. This has been confirmed over the course of the past 9 to 12 months, where the project hit two major versions (Angular 2 in Q3 2016 and Angular 4 in Q1 2017), gaining a lot in terms of stability, performances, and features, without losing much in terms of backward compatibility, best practices, and overall approach. All these reasons are solid enough to invest in it, hoping it will continue to keep up with these compelling premises.

 

A full-stack approach


Learning to use ASP.NET Core and Angular together would mean being able to work to both the frontend (client side) and backend (server side) of a web application; to put it in other words, it means being able to design, assemble, and deliver a complete product.

Eventually, in order to do that, we'll need to dig through the following:

  • Backend programming
  • Frontend programming
  • UI styling and UX design
  • Database design, modeling, configuration, and administration
  • Web server configuration and administration
  • Web application deployment

At first glance, it can seem that this kind of approach goes against common sense; a single developer should not be allowed to do everything by himself. Every developer knows well that the backend and the frontend require entirely different skills and experiences, so why in the world should we do that?

Before answering the question, we should understand what we really meant when we said "being able to". We don't have to become experts on every single layer of the stack; no one expects us to do so. When we choose to embrace the full-stack approach, what we really need to do is to raise our awareness level throughout the whole stack we're working on; it means that we need to know how the backend works and how it can and will be connected to the frontend. We need to know how the data will be stored, retrieved, and then served through the client; we need to acknowledge the interactions we will need to layer out between the various components that our web application is made of, and we need to be aware of security concerns, authentication mechanisms, optimization strategies, load-balancing techniques, and so on.

This doesn't necessarily mean that we have to have strong skills in all these areas; as a matter of fact, we hardly ever will. Nonetheless, if we want to pursue a full-stack approach, we need to understand the meaning, role, and scope of any of them, and possibly, be able to work there whenever we need to.

 

Single-Page Application


In order to demonstrate how ASP.NET Core and Angular can work together to their full extent, we couldn't think of anything better than building a Single-Page Application (SPA) project. The reason for that is quite obvious--there is no better approach to show some of the best features they have to offer nowadays. We'll have the chance to work with modern interfaces and patterns such as HTML5 pushState API, webhooks, data transport-based requests, dynamic web components, UI data bindings, and a stateless, AJAX-driven architecture capable to flawlessly encompass all of these.

Common features of a competitive SPA

To put it briefly, a SPA is a web-based application that struggles to provide the same user experience as a desktop application. If we consider the fact that all SPAs are still served through a web server and thus accessed by web browsers just like any other standard website, we can easily understand how that desired outcome can only be achieved by changing some of the default patterns commonly used in web development, such as resource loading, DOM management, and UI navigation. In a good SPA, both contents and resources--HTML, JavaScript, CSS, and such–-are either retrieved within a single page load or dynamically fetched when needed; this also means that the page doesn't reload or refresh, it just changes and adapts in response to user actions, performing the required server-side calls behind the scenes.

These are some of the key features provided by a competitive SPA nowadays:

  • No server-side roundtrips: A competitive SPA is able to redraw any part of the client UI without requiring a full server-side round trip to retrieve a full HTML page. This is mostly achieved by implementing a Separation of Concerns design principle, which means that the data will be separated from the presentation of data using a model layer that will handle the former, and a view layer that reads from the latter.
  • Efficient routing: A competitive SPA is able to keep track of the user current state and location during its whole navigation experience using organized, JavaScript-based routers. This is usually accomplished in one of two ways: the Hashbang technique, or the HTML5 History API usage. We'll talk about either one of them in Chapter 2, Backend with .NET Core.
  • Performance and flexibility: A competitive SPA usually transfers all of its UI to the client, thanks to its JavaScript SDK of choice (Angular, JQuery, Bootstrap, or any such). This is often good for network performance, as increasing client-side rendering and offline processing reduces the UI impact over the network. However, the real deal brought by this approach is the flexibility granted to the UI, as the developer will be able to completely rewrite the application frontend with little-to-no impact on the server, aside from a few of the static resource files.

The list can easily grow, as these are only some of the major advantages of a properly-designed, competitive SPA. These aspects play a major role nowadays, as many business websites and services are switching from their traditional Multi-Page Application mindset (MPA) to full-committed or hybrid SPA-based approaches. The latter ones, which have been increasingly popular since 2015, are commonly called Native Web Applications (NWA), because they tend to implement a number of small-scale, single-page modules bound together upon a multipage skeleton rather than building a single, monolithic SPA.

Not to mention the fact that there are also a lot of enterprise-level SPAs and Native Web Applications flawlessly serving thousands of users every day, want to name a few? WhatsApp Web and Teleport Web, Flickr, plus a wide amount of Google web services, including Gmail, Contacts, Spreadsheet, Maps, and more. These services, along with their huge user base, are the ultimate proof that we're not talking about a silly trend that will fade away with time; conversely, we're witnessing the completion of a consolidated pattern that's definitely meant to stay.

Product Owner expectations

One of the most interesting, yet underrated concepts brought out by many modern agile software development frameworks, such as SCRUM, is the importance given to the meanings and definitions of roles; among these, there's nothing as important as the Product Owner, also known as the customer in Extreme Programming methodology or customer representative elsewhere. They're the one who brings to the development table the expectations we'll struggle to satisfy. They will tell us what's most important to deliver and when they will prioritize our work based on its manifest business value rather than its underlying architectural value; they'll be entitled by the management to take decisions and make tough calls, which is sometimes great, sometimes not; this will often have a great impact on our development schedule. To cut it short, they're the one in charge of the project; that's why, in order to deliver a web application matching their expectancy, we'll need to understand their vision and feel it as if it were ours.

This is always true, even if the project's Product Owner is our dad, wife, or best friend: that's how it works.

Now that we made it clear, let's take a look at some of the most common Product Owner's expectations for a typical web-based SPA project. We ought to see if the choice of using ASP.NET Core and Angular will be good enough to fulfill each one of them.

  • Early release(s): No matter if we're selling a bunch of salad or web-based services, the customer will always want to see what he's buying. If we're using SCRUM, we'll have to release a potentially-shippable product at the end of each sprint; we'll have Milestones in a Waterfall-based approach, and so on. One thing is for sure--the best thing we can do in order to efficiently organize our development efforts will be to adopt an iterative and/or modular-oriented approach. ASP.NET Core and Angular, along with the strong Separation of Concerns granted by their underlying MVC or MVVM based patterns, will gracefully push us into the mindset needed to do just that.
  • GUI over backend: We'll often be asked to work to the GUI and frontend functionalities, because that will be the only real viewable and measurable thing for the customer. This basically means that we'll have to mock the data model and start working on the frontend as soon as possible, delaying everything that relies under the hood, even if that means leaving it empty; we can say that the hood is what we need the most. Note that this kind of approach is not necessarily bad; by all means, we're not tying up the donkey where the (product) owner wants. On the contrary, the choice of using ASP.NET Core along with Angular will grant us the chance to easily decouple the presentation layer and the data layer, implementing the first and mocking the latter, which is a great thing to do. We'll be able to see where we're going before wasting valuable time or being forced to make potentially wrong decisions. ASP.NET Core's Web API interface will provide the proper tools to do that by allowing us to create a sample web application skeleton in a matter of seconds using Visual Studio Controller templates and in-memory data contexts powered by Entity Framework 6, which we'll be able to access using entity models and code-first. As soon as we do that, we'll be able to switch to GUI design using the Angular presentation layer toolbox as much as we want until we reach the desired results; once we're satisfied, we'll just need to properly implement the Web API controller interfaces and hook up the actual data.
  • Fast completion: None of the preceding will work unless we also manage to get everything done in a reasonable time span. This is one of the key reasons to choose to adopt a server-side framework and a client-side framework working together with ease. ASP.NET Core and Angular are the tools of choice not only because they're both built on solid, consistent ground, but also because they're meant to do precisely that--get the job done on their respective side and provide a usable interface to the other partner.
  • Adaptability: As stated by the Agile manifesto, being able to respond to change requests is more important than following a plan. This is especially true in software development, where we can even claim that anything that cannot handle changes is a failed project. That's another great reason to embrace the Separation of Concerns enforced by our two frameworks of choice, as this grants the developer ability to manage--and even welcome, to some extent--most of the layout or structural changes that will be expected during the development phase.

Note

A few lines ago, we mentioned SCRUM, which is one of the most popular agile software development frameworks out there. Those who don't know it yet should definitely take a look at what it can offer to any result-driven Team Leader and/or Project Manager. Here's a good place to start--https://en.wikipedia.org/wiki/Scrum_(software_development).

That's about it. Note that we didn't cover everything here, as it will be impossible without knowing an actual assignment. We just tried to give an extensive answer to the following general questions: if we were to build a SPA, would ASP.NET Core and Angular be an appropriate choice? The answer is undoubtedly yes, especially when used together.

Does it mean that we're done already? Not a chance, as we have no intention of taking this assumption for granted. Conversely, it's time for us to demonstrate it by ceasing to speak in general terms and starting to put things in motion.

 

A sample Single-Page Application project


What we need now is to conceive a suitable test case scenario similar to the ones we will eventually have to deal with--a fully-featured, production-ready Single-Page Application project, complete with all the core aspects we would expect from a potentially shippable product.

In order to do this, the first thing we need to do is to become our own customer for a minute and come up with an idea, a vision to share with our own other self. We'll then be able to put our developer shoes back on and split our abstract plan into a list of items we'll need to implement; these will be the core requirements of our own project. Finally, we'll set up our workstation by getting the required packages, adding the resource files, and configuring both the ASP.NET Core and Angular frameworks into the Visual Studio IDE.

The vision

If we're going to demonstrate the key features of ASP.NET Core and Angular in a practical way such as committing ourselves into a full-stack SPA project and bringing it to life, we definitely need to go for a project where they can shine the most.

That's why we can't really take into consideration most presentation-oriented websites such as demos, product galleries, corporate or marketing showcases, photo/video/media reels, blogs, and the likes; we need something that can make better use of the asynchronous and parallel request processing capabilities of both frameworks, bringing them both toward their full extent; in order to fulfill these expectations, we would rather think about something similar to a CMS engine, a community-driven wiki, or even better, an interactive web application featuring some strong client-server interactions such as auth tokens, RESTful data transfer, and push notifications.

The latter seems to be the most appropriate, as it will mean going through a number of not-so-trivial implementation challenges while keeping the expected amount of source code small enough to fit into this book.

Not your usual "Hello World!"

The application we will build won't be just a shallow demonstration, we won't throw some working code here and there and expect the reader to connect the dots. Our objective is to create a solid, realistic web application using the frameworks we've chosen while following the current development best practices.

Each chapter will be dedicated to a single core aspect; if you feel like you already know your way there, feel free to skip to the next one. Conversely, if you're willing to follow us through the whole loop, you'll have a great journey through the most useful aspects of ASP.NET Core and Angular and how they can work together to deliver the most common and useful web-development tasks, from the most trivial one to the more complex beasts. It's an investment that will pay dividends, as it will leave you with a maintainable, extensible, and well-structured project, plus the knowledge needed to build your own.

To avoid making things too boring, we'll try to pick an enjoyable theme that will also have some usefulness in the real world; do you know anything about personality tests? They are questionnaires designed to reveal aspects of an individual's nature, trace a psychological makeup, or identify similarities with other notable real or fictional characters. The web is nothing less than full of them, featuring the most popular themes from the movie and entertainment industry--which Game of Thrones character are you?Are you a Jedi or a Sith? and so on.

Introducing TestMakerFree

I hope you like these kinds of questionnaires because we will build a web application that will allow users from anywhere in the world to build their own test(s). In order to do so, we'll put together a wizard-like tool that can be used to add questions and answers, upload images, choose a scoring method, assign a score to each answer, and define the possible outcomes/results. At the end of the wizard, the user will receive a unique URL that can be used to take the test and/or share it via email, blog/forum posts, IMs, social networks, and so on.

Ultimately, they will have a small yet useful web application featuring a server-side engine powered by ASP.NET Core and a web client mostly built using Angular.

The chosen name? TestMakerFree, also known as www.testmakerfree.com; needless to say, the free word means that our application will be free of charge. Luckily enough, the domain was still available at the time of writing this book. If you go there now, you'll be able to see the final outcome of what we will build from scratch during the course of this book; don't do that if you don't like spoilers, as it can ruin some of your fun.

Core features and requirements

Let's try to visualize how our application should work.

Our users will definitely need to register, so we'll be able to grant them the ownership of their own tests; once done, they will be able to create a new test. Each test will have a name, a description, a list of questions, and a series of possible results; each question will have a descriptive text, a list of answers, and an optional image; each answer will have a descriptive text, an optional image, and a list of score points; and each result will have a descriptive text and a score value.

The score points and the score value will be extensively discussed later on. For now, we'll just state the obvious--whenever a user completes the test, the sum of score points among all the given answers will be matched with the score value given to each possible result in order to determine the final outcome. The numbers will be shown or hidden to the user as per the test owner's choice.

Note

If you ever heard about the Myers-Briggs Type Indicator (MBTI) and/or the Five Factor Model (FFM), you most likely already know how we'll make use of score points and score values. In case you want to know more about these testing models, we strongly suggest you take a look at the en.wikipedia.org/wiki/Myers-Briggs_Type_Indicator and en.wikipedia.org/wiki/Big_Five_personality_traits Wikipedia pages.

That's about it. It might sound easy or not, depending on our programming experience, but one thing is certain--we got a plan.

Now that we have identified the key features, let's break them down into a list of development topics:

  • Routing: The application will have to properly respond to client requests, that is, routing them according to what they're up to.
  • Data model: We'll definitely adopt a database engine to store our tests, questions, answers, and so on; hence, we'll also need to develop the proper tools to access it in a modern, fashionable way. In order do so, we need to define our data architecture by setting up data repositories and domain entities that will be handled by the server and hooked to Angular through the most suited ASP.NET Core interface to handle HTTP communications--the Controller class.
  • Controllers: From an MVC-based architectural perspective, one of the main differences between multi-page and single-page applications is that the former's Controllers are designed to return views, while the latter ones, also known as API Controllers, mostly return serialized data. These are what we will need to implement to put Angular components in charge of the presentation layer.
  • Angular components: Switching to the client side, we will need to define a set of components to handle UI elements and state changes. As we probably already know, components are the most fundamental elements in Angular, replacing the AngularJS controllers and scopes. We'll get to know more about them soon enough.
  • Authentication: Soon enough, we'll have to deal with user login and registration. We'll take care of that by adding a membership context, so we'll be able to limit CRUD operations to authenticated users only, keeping track of each user action, requiring registration to access some pages/views, and so on.
  • UI styling: We will take our time to come to that, as we will stick to the core topics first, but we'll definitely get there eventually; the initial ugliness of our web client will flourish into a responsive, good-looking, and mobile-friendly user interface.

These will be our main development challenges. As we said earlier, we definitely have to understand how to properly handle each one of them, or we won't be able to succeed. Hence, let's get to work without further ado!

The following chapters will guide us through the journey; we'll also cover other important aspects such as SEO, Security, Performance Issues, Best Coding Practices, and Deployment, as they will be very important later on.

 

Preparing the workspace


The first thing we have to do is to set up our workstation; it won't be difficult, because we only need a small set of essential tools. These include Visual Studio 2017, the web platform installer, the Node.JS runtime, a web server such as IIS or IIS Express, and a decent source code control system such as Git, Mercurial, or Team Foundation. We will take the latter for granted, as we most likely already have it up and running.

Note

In the unlikely case we don't, we should really make amends before moving on! Stop reading, go to www.github.com or www.bitbucket.com, create a free account, and spend some time to learn how to effectively use these tools; we won't regret it, that's for sure.

Disclaimer-Do (not) try this at home

There's something very important that we need to understand before proceeding. If we're a seasoned web developer we will most likely know about it already, however, since this book is for (almost) everyone, I feel like it's very important to deal with this matter as soon as possible.

This book will make an extensive use of a number of different programming tools, external components, third-party libraries and so on. Most of them, such as TypeScript, NuGet, NPM, Gulp, .NET Core Frameworks/runtimes, and so on are shipped together with Visual Studio 2017, while others such as Angular and its required JS dependencies will be fetched from their official repositories. These things are meant to work together in a 100% compatible fashion, however they are all subject to changes and updates during the inevitable course of time: as time passes by, the chance that these updates might affect the way they interact with each other and the project health will increase.

The broken code myth

In an attempt to minimize the chances that this can occur, this book will always work with fixed versions/builds of any third-party component that can be handled using the configuration files. However, some of them, such as Visual Studio and/or .NET framework updates, might be out of that scope and might bring havoc to the project. The source code might cease to work, or Visual Studio can suddenly be unable to properly compile it.

When something like that happens, the less experienced reader will always be tempted to put the blame on the book itself. Some of them may even start thinking something like this:

There are a lot of compile errors, hence the source code must be broken!

Alternatively, they may think like this:

The code sample doesn't work: the author must have rushed things here and there and forgot to test what he was writing.

There can be many other things like these.

It goes without saying that such hypotheses are hardly true, especially considering the amount of time that the authors, editors, and technical reviewers of these books spent in writing, testing, and refining the source code before building it up, making it available on GitHub and even publishing a working instance of the resulting application to a worldwide-available public website.

Any non-amateur developer will easily understand that most of these things couldn't even be done if there was some "broken code" somewhere; there's no way this book can even attempt to hit the shelves unless it comes with a 100% working source code, except for few possible minor typos that will quickly be reported to the publisher and thus fixed within the GitHub repository in a short while. In the unlikely case that it looks like it doesn't, such as raising unexpected compile errors, the non-novice reader should spend a reasonable amount of time trying to understand the root cause. Here's a list of questions they should try to answer before anything else:

  • Am I using the same development framework, third-party libraries, versions, and builds adopted by the book?
  • If I updated something because I felt like I needed to, am I aware of the changes that might affect the source code? Did I read the relevant change logs? Have I spent a reasonable amount of time looking around for breaking changes and/or known issues that could have had an impact on the source code?
  • Is the book's GitHub repository also affected by this issue? Did I try to compare it with my own code, possibly replacing mine?

Stay hungry, stay foolish, yet be responsible as well

Don't get it wrong: whenever you want to use a newer version of Visual Studio, update your Typescript compiler or upgrade any third-party library; you are free and also very encouraged to do that. This is nothing less than the main scope of this book--making the readers fully aware of what they're doing and capable of going on their path, way beyond the given code samples.

However, if you feel you're ready to do that, you will also have to adapt the code accordingly; most of the time, we're talking about trivial stuff, especially these days when you can Google out the issue and/or get the solution on StackOverflow. They changed the typings? Then you need to load the new typings; they moved the class somewhere else? Then you need to find the new namespace and change it accordingly; and so on.

That's about it, nothing more, nothing less. The code reflects the passage of time; the developer just needs to keep up with the flow, performing minimum changes to it when required. You can't possibly get lost and blame someone other than you if you update your environment and fail to acknowledge that you have to change a bunch of code lines to make it work again.

Am I implying that the author is not responsible for the source code of the book? It's the exact opposite, the author is always responsible. They're supposed to do their best to fix all the reported compatibility issues while keeping the GitHub repository updated. However, the reader should also take his very own level of responsibility; more specifically, he should understand how things work for any development book and the inevitable impact of the passage of time on any given source code. No matter how hard the author can work to maintain it, the patches will never be fast or comprehensive enough to make these lines of code always work on any given scenario. That's why the most important thing the reader needs to understand--even before the book topics--is the most valuable concept in modern software development: being able to efficiently deal with the inevitable changes that will always occur.

Whoever refuses to understand that is doomed; there's no way around it.

Versions and builds

These are the releases we will use:

  • Visual Studio 2017 version 15.4.4
  • Microsoft .NET Core SDK 2.0.3
  • TypeScript 2.4.2
  • NuGet Package Manager 4.1.0
  • NodeJS 6.9.0
  • Angular 5.0.2 final release

We strongly suggest using the same version used within this book, or newer, at your own risk! Jokes aside, if you prefer to use a different version, that's perfectly fine, as long as you will take responsibility if something doesn't work, just like we said a paragraph ago.

Setting up the project

The first thing we need to do is to download the .NET Core SDK, unless the release we want to use is already shipped with Visual Studio 2017. We can download the latest version from either the official Microsoft URL, that is, https://www.microsoft.com/net/core, or from the official GitHub project page, at https://github.com/dotnet/cli/tree/v2.0.3#installers-and-binaries.

The installation is very straightforward, just follow the wizard until the end to get the job done:

Once installed, launch Visual Studio 2017 and create a new ASP.NET Core Web Application project. Let's do that by following the mentioned steps:

  1. Fire up Visual Studio 2017 and, from the File menu, expand New and select Project to open a New Project modal window.
  2. From the Templates tree, expand the Visual C# node and select the Web subfolder; the right section of the modal window will be populated by a number of available project templates. Among these, there are two choices for creating an ASP.NET Core Web Application project: .NET Core and .NET Framework, as we can see in the following diagram:
  1. The first one, optimized for cross-platform deployment, entirely relies upon the new .NET Core framework; the latter, ideal for a Windows environment, is based upon the latest .NET Framework version (4.6.2 at the time of writing) instead.

Note

The good thing here is that, thanks to the ASP.NET Core versatility, we are free to choose the approach we like the most, as both frameworks are mature enough to support almost everything we will use within this book. That said, in order to have better compatibility with most NuGet packages we might choose to add, we'll be choosing the template based on .NET Core.

  1. Select the ASP.NET Core Web Application (.NET Core) template and fill the relevant Name, Location, and Solution name fields; set TestMakerFreeWebApp as Project Name and TestMakerFree as Solution name, just to not confuse them, and then click on OK to continue.
  2. In the next modal window, we can further customize our template by choosing the default contents to include in our project (Empty, Web API, or Web Application) and the authentication mechanism, should we want to use one. Select .NET Core and ASP.NET Core 2.0 from the drop-down list, and then select the Angular template icon with No Authentication; the Enable Docker Support checkbox, if present, should be disabled by default. Eventually, click on the OK button to create the project:

Those who're used to the Visual Studio Web Application Project templates for the previous ASP.NET versions will be tempted to choose Empty instead, thus avoiding the insane amount of sample classes, folders, and components, including a number of potentially outdated versions of various client-side frameworks such as Bootstrap, KnockoutJS, JQuery, and more. Luckily enough, these new ASP.NET Core project templates are quite lightweight and just ship the required files, resources, and dependencies to the project to Bootstrap a sample template based on the chosen client-side technology:

In our specific case, our template will set up a rather clean working environment containing the following:

  • The default ASP.NET MVC /Controllers/ and /Views/ folders, with some sample controllers and views
  • The /ClientApp/ folder, with some TypeScript files containing the source code of a sample Angular app
  • The /wwwroot/ folder, which will be used by VS2017 to build an optimized version of the client-side code whenever we need to execute it locally or have it published anywhere; that folder is initially empty, but it will be populated upon first-run

If we spend some time to browse through this folder and take a look at the content, we can see how the .NET Core developers did a tremendous job in easing the MVC-with-Angular setup and kickstart process. This template already supports SEO optimization and Server-Side Rendering (SSR), and also features a bunch of useful optimizations; those who fought with task runners and client-side building strategies in the recent past will most likely appreciate the fact that this template features a build process completely handled by NPM, Webpack, and .NET Core with specific loading strategies for development and production.

Note

More details on this approach, including a summary of the main reasons behind it, are well explained by the following .NET WebDev blog, which explains the great work done by Steve Sanderson to properly support Single-Page Applications in .NET Core:https://blogs.msdn.microsoft.com/webdev/2017/02/14/building-single-page-applications-on-asp-net-core-with-javascriptservices/

Alternative setup using the command line

If we take a look at the article mentioned in the information box at the end of the previous paragraph, we can see how the SPA templates are fetched and installed using the command line. Although we did that using the VS2017 GUI, we can also do that using the command line in the following way:

dotnet new angular

When using this command, the Angular project will be created within the folder where the command is executed.

The command line can also come in handy whenever we want to get the latest versions of the SPA templates, which is currently not supported within the GUI:

dotnet new --install Microsoft.AspNetCore.SpaTemplates::*

Test run

Before moving further, we should definitely attempt a quick test run to ensure that everything is working properly. Doing that should be just as easy as hitting the Run button or the F5 key:

This is an excellent consistency check to ensure that our development system is properly configured. If we see the sample Angular SPA up and running, as shown in the preceding screenshot, it means that we're good to go; if we don't, it probably means that we're either missing something or that we've got some conflicting software preventing VS2017 and its external web tools (NPM/NODE) from properly compiling the project.

In order to fix that, we can try to do the following:

  • Uninstall/reinstall Node.JS, as we can possibly have an outdated version installed.
  • Uninstall/reinstall Visual Studio 2017, as our current installation might be broken or corrupt. The.NET Core SDK should come shipped with it already; however, we can also try reinstalling it.
  • Update the SPA templates using the command-line interface by following the instructions we gave in the previous paragraph.
  • Install VS2017 on a clean environment (be it either a physical system or a VM) to overcome any possible issue related to our current operating system configuration.

Note

If none of these works, the best thing we can do is to ask for specific support on the .NET Core community forum, at https://forums.asp.net/1255.aspx/1?ASP+NET+Core.

 

Looking around


Now that our project has been created, it's time to take a quick look around and try to understand some of the hard work that the .NET Core SPA Template has done to make it work. Hey, wait a minute! Shouldn't we skip all these setup technicalities and just jump into coding? As a matter of fact, yes, we'll definitely be doing that in a little while. However, before doing that, it can be wise to highlight a couple of aspects of the code that has been put in place already so that we'll know how to properly move within our project in advance: where to find the server-side and client-side code, where to put some new content, how to change our initialization parameters, and so on. It will also be a good chance to review our base knowledge about the Visual Studio environment and the required packages we will need.

Note

IMPORTANT! The sample code we're reviewing here is the one that's being shipped with the Angular SPA Visual Studio Template at the time of writing--MVC ASP.NET Core with Angular. In the (likely) event that this sample code will get updated in future releases, ensure to get the former source code from the web using this book's official NuGet repository and use it to replace the contents of your /TestMakerFreeWebApp/ folder. If we avoid doing that, our sample code might differ from the one featured in this book.

The first thing that meets the eye is that, as we already mentioned, the layout of a standard ASP.NET Core solution is quite different from what it used to be in ASP.NET 4 and earlier versions. The main difference is the brand new /wwwroot/ folder, which will contain the compiled, ready-to-publish contents of our application: HTML, JS, and CSS files, along with fonts, images, and everything else we want our users to have access to in terms of static files.

Other things worth noting are as listed:

  • The good old /Controllers/ and /Views/, which come shipped with any MVC-based ASP.NET application since the former release of the MVC framework
  • The /ClientApp/ folder, which already hosts a bunch of Angular source code files; we can see that they all have a .ts extension, which means we'll be using the TypeScript programming language (we'll say more about this in a bit)
  • The Dependencies virtual folder, which is basically the replacement of the old Resources folder and contains all the internal, external, and third-party references required to build and run our project
  • A bunch of root-level .cs, .json, and .js files that will determine our web application's configuration, the available client-side and server-side modules and also their setup, compilation, and publishing rules; we'll address them in a while

Just by observing these folders, provided that we already got a glimpse of ASP.NET MVC experience, we are already able to figure out how things will be handled:

  • Each request will be received by the MvcApplication, which will handle them at the server-side level and route those related to the GUI through the appropriate Controller
  • The Controller will do the required server-side tasks and then, depending on the given request, either serve raw JSON data or return the response content using a View
  • The View will serve the required client-side content (HTML, JS, and CSS), including the required JS modules that will be served in a highly-optimized fashion using a dedicated dynamic loader (Webpack)

Let's quickly review the whole process, starting with the root configuration files.

The configuration files

Let's start with the main .NET Core startup files: Program.cs and Startup.cs.

Program.cs

The Program.cs file will most likely raise the curiosity of most seasoned ASP.NET programmers, as it's not something we usually see in a web application project. First introduced in ASP.NET Core 1.0, the Program.cs file's main purpose is to set up and build the IWebHost.

Note

That's great to know, but what is a Web Host? In a very few words, a host is the execution context of any ASP.NET Core app. In a web-based application, the host must implement the IWebHost interface, which exposes a collection of web-related features and services and also a Start method. The Web Host references the server that will handle requests. The preceeding statement can lead to thinking that the web host and the web server are the same thing; however, it's very important to understand that they're not, as they serve very different purposes. The following excerpt from the .NET Core GitHub project does a great job explaining the key difference between them: The host is responsible for application startup and lifetime management. The server is responsible for accepting HTTP requests. Part of the host's responsibility includes ensuring that the application's services and the server are available and properly configured. We could think of the host as being a wrapper around the server. The host is configured to use a particular server; the server is unaware of its host. Source: http://aspnetcore.readthedocs.io/en/stable/fundamentals/hosting.html

If we open the Program.cs file, we can easily see that the web host is built in an extremely easy way:

public class Program
{
    public static void Main(string[] args)
    {
        BuildWebHost(args).Run();
    }

    public static IWebHost BuildWebHost(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>()
            .Build();
}

The WebHost.CreateDefaultBuilder() method is one of the many improvements of ASP.NET Core 2.0 over its 1.x counterpart as it simplifies the amount of source code required to set up basic use cases, thus making it easier to get started with a new project.

To understand this better, let's take a look at the sample Program.cs equivalent, like it was in ASP.NET Core 1.x:

public class Program
{
    public static void Main(string[] args)
    {
        var host = new WebHostBuilder()
            .UseKestrel()
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseIISIntegration()
            .UseStartup<Startup>()
            .UseApplicationInsights()
            .Build();

            host.Run();
        }
    }

This used to perform the following steps:

  • Setting up the Kestrelweb server
  • Setting the Content root folder, that is, where to look for the appsettings.json file and other configuration files
  • Setting up the IIS Integration
  • Defining the Startup class to use (usually defined in the Startup.cs file)
  • Finally, Build and Run the now configured IWebHost

In .NET Core 1.x, all these steps must be called explicitly here and also manually configured within the Startup.cs file; in .NET Core 2.0, we can still do this, yet using the WebHost.CreateDefaultBuilder() method will generally be better as it will take care of most of the job, also letting us change the defaults whenever we want.

Note

If you're curious about this method, you can even take a peek at the source code on GitHub at https://github.com/aspnet/MetaPackages/blob/rel/2.0.0/src/Microsoft.AspNetCore/WebHost.cs.https://github.com/aspnet/MetaPackages/blob/rel/2.0.0/src/Microsoft.AspNetCore/WebHost.cs At the time of writing, the WebHost.CreateDefaultBuilder() method implementation starts at line #152.

Startup.cs

Let's move to the Startup.cs file. If you're a seasoned .NET developer, you might be already familiar with it, since it was first introduced in OWIN-based applications to replace most of the tasks previously handled by the good old Global.asax file.

Note

OWIN (for Open Web Interface for .NET) and comes as part of Project Katana, a flexible set of components released by Microsoft back in 2013 for building and hosting OWIN-based web applications. For additional info, refer to https://www.asp.net/aspnet/overview/owin-and-katana.

However, the similarities end here; the class has been completely rewritten to be as pluggable and lightweight as possible, which means that it will include and load only what's strictly necessary to fulfill our application's tasks. More specifically, in .NET Core, the Startup.cs file is the place where we can do the following:

  • Add and configure Services and Dependency Injection, in the ConfigureServices method
  • Configure HTTP request pipeline by adding the required Middleware packages, in the Configure method

To better understand this, let's take a look at the following lines taken from the Startup.cs source code shipped with the project template we chose:

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions
        {
            HotModuleReplacement = true
        });
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }

    app.UseStaticFiles();

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

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

This is the Configure method implementation, where--as we just said--we can set up and configure the HTTP request pipeline.

The code is very readable, so we can easily understand what happens here:

  • The first bunch of lines features an if-then-else statement that implements two different behaviors to handle runtime exceptions in development and production, throwing the exception in the former case or showing an opaque error page to the end user in the latter; that's a neat way to handle runtime exceptions in a very few lines of code.
  • The app.UseStaticFiles() call adds the Microsoft.AspNetCore.StaticFiles middleware to the HTTP pipeline, which will allow our web server to serve the static files within the web root. Without this line, we won't be able to serve locally hosted assets such as JS, CSS, and images; hence, having it there is a good thing. Also, note how the method is called with no parameters; the StaticFiles middleware default settings are more than enough for us, so there's nothing to configure or override here.
  • We can't say the same for the subsequent app.UseMvc() call, which comes with some interesting configuration parameters. We'll extensively talk about that in Chapter 2, Backend with .NET Core; for now, let's just understand that these lines serve the purpose of adding the MVC Middleware within the HTTP pipeline and also setting up a couple of HTTP routing rules pointing to the HomeController Index action method, which will be the web application main entry point.

Let's perform a quick test to ensure that we properly understand how these Middlewares work. From Visual Studio's Solution Explorer, go to the /wwwroot/ folder and add a new test.html page to our project. Once done, fill it with the following contents:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Time for a test!</title>
</head>
<body>
    Hello there!
    <br /><br />
    This is a test to see if the StaticFiles middleware is working properly.
</body>
</html>

Now, let's launch the application in debug mode--using the Run button or the F5 keyboard key--and point the address bar to http://localhost:<port>/test.html.

We should be able to see our test.html file in all its glory:

Now, let's go back to our Startup.cs file and comment out the app.UseStaticFiles() call to prevent the StaticFiles middleware from being loaded:

 // app.UseStaticFiles();

Once done, run the application again and go back to the previous URL:

 

As expected, static files aren't being served anymore. If we point our address bar to /home, we can see how this new behavior is also preventing the sample SPA provided by the Angular template from even loading, which means that we just broke our web app, yay!

Now that we proved our point, let's bring the StaticFiles middleware back in place by removing the comments and go ahead.

Note

For additional information regarding the StaticFiles middleware and static files handling in .NET Core, visit and read https://docs.asp.net/en/latest/fundamentals/static-files.html.

All in all, we can honestly say that the Startup.cs file shipped with the Angular SPA template already has everything we need, so we can leave it as it is for now. However, before going ahead, let's take another look at the if-then-else statement contained within this code snippet; we can easily see that there are other things planned when the application is in development mode. We're talking about the UseWebpackDevMiddleware() method with the HotModuleReplacement option set to true. This is one of the great features shipped with the Microsoft.AspNetCore.SpaServices package for those who use Webpack, which includes us; we'll get there later on, when talking about the Webpack configuration file.

Now, it's time to take a quick look at the three .json files also lying in the root folder. Each one of them is a configuration file for something; let's look at a bunch of words for each one of them.

The appsettings.json file

The appsettings.json file is nothing less than the replacement of the good old Web.config file; the XML syntax has been replaced by a more readable (and less verbose) JSON format. Moreover, the new configuration model is based upon key/value settings that can be retrieved from a wide variety of sources, including--yet not limited to--Json files, using a centralized interface.

Once retrieved, they can be easily accessed within our code using Dependency Injection via literal strings (using the vanilla IConfiguration class):

public SampleController(IConfiguration configuration)
{ 
    var myValue = configuration["Logging:IncludeScopes"];
}

Alternatively, even in a strongly-typed fashion using a custom POCO class (we'll get there later on).

Note

It's worth noting that there's also an appsettings.Development.json file nested below the former one. Such file serves the same purpose of the old Web.Debug.config file since ASP.NET 4.x; everything is written there will override the appsettings.json values as long as the application runs in the development mode. Back in .NET Core 1.x, this overriding behavior had to be specified manually within the Startup.cs file; in .NET Core 2, the WebHost.CreateDefaultBuilder() method within the Program.cs file takes care of that automatically, assuming that you don't need to add another custom .json configuration file.

Assuming that we understood everything here, it's time to move on to the next configuration file.

The package.json file

The package.json file is the NPM Configuration File; it basically contains a list of NPM packages that the developer want to be restored before the project starts. Those who already know what NPM is and how it works can skip to the next paragraph, while the others should definitely keep reading.

NPM (shortcode for Node Package Manager) started its life as the default package manager for the JavaScript runtime environment known as Node.js. During the latest years, though, it was also being used to host a number of independent JS projects, libraries, and frameworks of any kind, including Angular; eventually, it became the de facto package manager for JavaScript frameworks and tooling. If you never used it, you may easily think of it as the Nuget for the JavaScript world.

Although NPM is mostly a command-line tool, the easiest way to use it from Visual Studio is to properly configure a package.json file containing all the NPM packages we want to get, restore, and keep up to date later on. These packages get downloaded in the /node_modules/ folder within our project directory, which is hidden by default within Visual Studio; however, all the retrieved packages can be seen from the /Dependencies/npm/ virtual folder. As soon as we add, delete, or update the package.json file, Visual Studio will automatically update that folder accordingly.

In the Angular SPA template we've been using, the shipped package.json contains a huge amount of packages--all Angular packages plus a good bunch of dependencies, tools, and third-party utilities such as Karma (a great Test Runner for JavaScript/TypeScript).

Before moving ahead, let's take an additional look at our package.json file and try to get the most out of it. We can see how all the packages are listed within a standard JSON object entirely made of key-value pairs; the package name is the key, while the value is used to specify the version number. We can either input precise build numbers or use the standard npmJS syntax to specify auto-update rules bound to custom version ranges using the supported prefixes, such as the following:

  • The Tilde (~): A value of "~1.1.4" will match all 1.1.x versions, excluding 1.2.0, 1.0.x, and so on

  • The Caret (^): A value of "^1.1.4" will match everything above 1.1.4, excluding 2.0.0 and above

This is another scenario where Intellisense will come inhandy, as it will also suggest how to do that.

Note

For an extensive list of available npmJS commands and prefixes, it's advisable to check out the official npmJS documentation at https://docs.npmjs.com/files/package.json.

Upgrading (or downgrading) Angular

As we can see, the Angular SPA Template uses fixed version numbers for all the Angular-related packages; this is definitely a wise choice since we have no guarantees that newer versions will seamlessly integrate with our existing code without raising some potentially breaking issues and/or compiler errors. Needless to say, the version number will naturally increase with the passage of time, because the template developers will definitely try to keep their good work up to date.

That said, these are the Angular packages and releases that will be used within this book:

"@angular/animations": "5.0.2",
"@angular/common": "5.0.2",
"@angular/compiler": "5.0.2",
"@angular/compiler-cli": "5.0.2",
"@angular/core": "5.0.2",
"@angular/forms": "5.0.2",
"@angular/http": "5.0.2",
"@angular/platform-browser": "5.0.2",
"@angular/platform-browser-dynamic": "5.0.2",
"@angular/platform-server": "5.0.2",
"@angular/router": "5.0.2"

As we can see, the version number is the same for all packages and corresponds to the Angular release currently installed.

Note

The final version of Angular 5, codename Pentagonal Donut, has been released on November 1, 2017--just days before this book will hit the shelves: we did our best to use the latest possible final (non-beta, non-rc) version to give the reader the best possible experience with the most recent technology available. That said, that "freshness" will eventually decrease over time and this book's code will start to become obsolete: when it will happen, don't blame us for that!

If we want to ensure the highest possible level of compatibility between our project and this book's source code, we should definitely adopt that same release, which, at the time of writing, also corresponds to the latest stable one. We can easily perform the upgrade--or downgrade--by changing the version numbers; as soon as we save the file, Visual Studio will automatically fetch the new versions through NPM. In the unlikely case it won't, manually deleting the old packages and issuing a full rebuild should be enough to fix the issue.

As always, we're free to overwrite such behavior and get newer (or older) versions of these packages, assuming that we properly understood the consequences and according to this chapter's Disclaimer.

Note

If you encounter problems while updating your package.json file, such as conflicting packages or "broken" code, ensure that you download the full source code from the official GitHub repository of this book, which includes the same package.json file that has been used to write, review, and test this book; it will definitely ensure a great level of compatibility with the source code you'll find here.

Upgrading (or downgrading) the other packages

As we can easily expect, if we upgrade (or downgrade) Angular to 5.0.0 final, we also need to take care of a series of other NPM packages that might require to be updated (or downgraded) as well. Here's the full package list we'll be using in our package.json file throughout the book: the important packages are highlighted--be sure to triple-check them!

{
  "name": "TestMakerFree",
  "private": true,
  "version": "0.0.0",
  "scripts": {
    "test": "karma start ClientApp/test/karma.conf.js"
  },
  "dependencies": {
    "@angular/animations": "5.0.2",
    "@angular/common": "5.0.2",
    "@angular/compiler": "5.0.2",
    "@angular/compiler-cli": "5.0.2",
    "@angular/core": "5.0.2",
    "@angular/forms": "5.0.2",
    "@angular/http": "5.0.2",
    "@angular/platform-browser": "5.0.2",
    "@angular/platform-browser-dynamic": "5.0.2",
    "@angular/platform-server": "5.0.2",
    "@angular/router": "5.0.2",
    "@ngtools/webpack": "1.8.2",
    "@types/webpack-env": "1.13.2",
    "angular2-template-loader": "0.6.2",
    "aspnet-prerendering": "3.0.1",
    "aspnet-webpack": "2.0.1",
    "awesome-typescript-loader": "3.4.0",
    "bootstrap": "3.3.7",
    "css": "2.2.1",
    "css-loader": "0.28.7",
    "es6-shim": "0.35.3",
    "event-source-polyfill": "0.0.9",
    "expose-loader": "0.7.3",
    "extract-text-webpack-plugin": "2.1.2",
    "file-loader": "1.1.5",
    "html-loader": "0.5.1",
    "isomorphic-fetch": "2.2.1",
    "jquery": "3.2.1",
    "json-loader": "0.5.7",
    "preboot": "5.1.7",
    "raw-loader": "0.5.1",
    "reflect-metadata": "0.1.10",
    "rxjs": "5.5.2",
    "style-loader": "0.19.0",
    "to-string-loader": "1.1.5",
    "es6-shim": "0.35.3",
    "typescript": "2.4.2",
    "url-loader": "0.6.2",
    "webpack": "2.6.1",
    "webpack-hot-middleware": "2.20.0",
    "webpack-merge": "4.1.1",
    "zone.js": "0.8.12"
  },
  "devDependencies": {
    "@types/chai": "4.0.1",
    "@types/jasmine": "2.5.53",
    "chai": "4.0.2",
    "jasmine-core": "2.6.4",
    "karma": "1.7.0",
    "karma-chai": "0.1.0",
    "karma-chrome-launcher": "2.2.0",
    "karma-cli": "1.0.1",
    "karma-jasmine": "1.1.0",
    "karma-webpack": "2.0.3"
  }
}

Note

It's advisable to perform a manual command-linenpm update from the project's root folder right after applying these changes to the package.json file, in order to trigger a batch update of all the project's NPM packages: sometimes Visual Studio doesn't update the packages automatically and doing that using the GUI can be tricky. For this very reason, a convenient update-npm.bat batch file has been added to this book's source code repository on GitHub to handle that--without manually having to type the above command.

For further reference and/or future updates, please also check the updated source code within this book's official GitHub repository, which will always contain the latest improvements, bug fixes, compatibility fixes and so on.

The tsconfig.json file

The tsconfig.json file is the TypeScript configuration file. Again, those who already know what TypeScript is won't need to read all this, although the others should most likely stay.

In less than 100 words, TypeScript is a free, open source programming language developed and maintained by Microsoft that acts as a JavaScript superset; this means that any JavaScript program is also a valid TypeScript program. TypeScript also compiles to JavaScript, so it can seamlessly work on any JS-compatible browser without external components. The main reason to use it is to overcome the syntax limitations and overall shortcomings of JavaScript when developing large-scale applications or complex projects: in very short terms, to ease the developer's life when he's forced to deal with non-trivial JavaScript code.

In this project, we will definitely use TypeScript for a number of good reasons; the most important ones of them are as follows:

  • TypeScript has a number of features over JavaScript, such as static typing, classes, and interfaces. Using it in Visual Studio also gives us the chance to benefit from the built-in IntelliSense, which is a great benefit and often leads to a remarkable productivity burst.
  • For a large client-side project, TypeScript will allow us to produce a more robust code, which will also be fully deployable anywhere a plain JavaScript file would run.

Not to mention the fact that the Angular SPA template we chose is using it, hence we can say that we got a leg in that boat already!

Jokes aside, we're not the only ones praising TypeScript; it's something acknowledged by the Angular team itself, considering the fact that the Angular source code has been written using TypeScript since Angular 2, as proudly announced by Microsoft in the following MDSN blog post in March 2015:

https://blogs.msdn.microsoft.com/typescript/2015/03/05/angular-2-built-on-typescript/

It was further emphasized by this great post by Victor Savkin (co-founder of Narwhal Technologies and acknowledged Angular consultant) on his personal blog in October 2016:

https://vsavkin.com/writing-angular-2-in-typescript-1fa77c78d8e8

Getting back to the tsconfig.json file, there's not much to say; the option values used by the Angular SPA Template are more or less what we need to configure both Visual Studio and TSC (the TypeScript compiler) to properly transpile the TS code files included in the /ClientApp/ folder: however, while we're here, we can take the chance to tweak them a little more:

{
  "compilerOptions": {
    "module": "es2015",
    "moduleResolution": "node",
    "target": "es5",
    "sourceMap": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "skipDefaultLibCheck": true,
    "skipLibCheck": true,
    "strict": true,
    "lib": [ "es6", "dom" ],
    "types": [ "webpack-env" ]
  },
  "exclude": [ "bin", "node_modules" ],
  "atom": { "rewriteTsconfig": false },
  "angularCompilerOptions": {
    "strictMetadataEmit": true
  }
}

The interesting stuff here is the angularCompilerOptions object, which can be used to configure the behavior of the Angular AoT compiler: the strictMetadataEmit setting which we added will tell the compiler to report syntax errors immediately rather than produce an error log file.

Note

For more info regarding the new Angular AoT compiler, read the following URL: https://angular.io/guide/aot-compiler

The webpack configuration files

Last but not least we must spend some words on the webpack.config.js and webpack.config.vendor.js files, which play the most important role for the client-side components of our project because of the insane amount of tasks they take care of. Let's start with the usual question: what is Webpack to begin with? Those who know can move forward; as for the others, keep reading.

In short, Webpack is the most used--and arguably the most powerful nowadays--module bundler for modern JavaScript applications. Its main job is to recursively build a dependency graph of all the NPM modules needed by the client-side application before starting it, package them all into a small number of bundles--often only one--and then feed them (or it) to the browser.

The benefits brought to the developer by this revolutionary approach are simply too many and too great to be summarized in a short paragraph like this, as they will require too much space to be properly explained. We'll just scratch the surface by mentioning the most important ones:

  • Dramatically reduces the HTTP requests to load the client-side assets in normal scenarios, that is, when no package managers, task runners, or concatenation strategies are being used
  • Dramatically reduces the chance of variable conflicts when using standard concatenation strategies such as the .concat().uglify().writeTo() chains featured by Gulp, Grunt, and the likes
  • Dramatically increases the control over static files, as it can be configured to skip all the "dead" JS/CSS and even image (!) assets, reduce/optimize the size of CSS files even before minifying them, easily switch between CDNs URLs and locally hosted files, and so on

All these good things are real, as long as the tool is properly configured, which brings us to the only real bad thing about Webpack; it's not easy to set it up properly, especially for a newcomer, for a number of good reasons--the documentation has been greatly improved within the past 2 years, yet it's still not as good as other projects; the configuration file is quite hard to read and the syntax might be quite confusing at times.

Luckily enough, despite the steep learning curve, there's a gigantic amount of established examples, boilerplate projects, and code snippets available through the web that can be easily adapted to be used within most projects. The Angular SPA Template we've chosen is no exception, as it comes with two great configuration files - webpack.config.js and webpack.config.vendor.js - that already do all we need: the former one will be used to construct the bundle containing the application code, while the latter will bundle all the required vendor dependencies.

If we open them, we can see how they're both set up to build three main configuration objects:

  • The sharedConfig object for the assets that will be used within either the client-side and server-side bundles
  • The clientBundleConfig object used to bundle together the client-side assets for running-in browsers
  • The serverBundleConfig object used to bundle together the server-side (prerendering) assets

The former section acts as a prerequisite bundle that gets merged with the other two before they are deployed within the /wwwroot/ folder.

Note

If you want to know more about Webpack, we strongly suggest you to take a look at the official documentation, available at https://webpack.js.org/ . Also, it's worth noting that Webpack v2.x introduced a built-in validator for the config files that will greatly help the developer to track most coding errors; this new feature is extremely handy for those who want to update/improve the existing configuration files. For specific instruction on how to properly set up Webpack for Angular, it's also advisable to read the https://angular.io/docs/ts/latest/guide/webpack.html article from the official Angular documentation.

Do you remember the UseWebpackDevMiddleware() method we found in the Startup.cs file a short while ago? Now that we shed some light on Webpack, we can bring back the topic and easily explain what it was.

That middleware, only available when the web application is running in development mode, will intercept any request that will match files built by Webpack, dynamically build those files on demand and serve them to the browser without writing them to disk. Basically, it will act as an in-memory webhook.

Needless to say, such behavior will bring some benefits during development, such as these:

  • No need to run Webpack manually or set up file watchers: If you've been using task runners, you know how difficult it can be to have these always up in terms of resources
  • The browser will always receive up-to-date built output: No more outdated code due to caching issues or watchers not being up
  • Overall speed increase (at least arguably): The built artifacts should be served extremely quickly since the active Webpack instance should keep their partial compilation states already cached in memory

Note

For further information regarding the Webpack Dev Middleware, we suggest you to read the official documentation on the Microsoft.AspNetCore.SpaServices GitHub repository, available at https://github.com/aspnet/JavaScriptServices/tree/dev/src/Microsoft.AspNetCore.SpaServices#webpack-dev-middleware.

Updating the webpack.config.js file

Switching from Angular 4 to Angular 5 requires to perform a manual update to the webpack.config.js file to replace the previous AotPlugin to the new AngularCompilerPlugin: both of them are Webpack plugins that perform an AoT compilation of Angular components and modules. The former has been used since Angular 2 and up to Angular 4, while the latter has been released to work with Angular 5.

Open the webpack.config.js file with the Visual Studio editor and update line 4 in the following way (updated code highlighted):

const AotPlugin = require('@ngtools/webpack').AngularCompilerPlugin;

Right after that, scroll down to the sharedConfig : module : rules section and replace the simple test: /\.ts$/ rule with the following one:

[...]

module: {
    rules: [
        { test: /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/, [...]

[...]

Note

At the time of writing these steps are required because the template package still built around Angular 4 and AotPlugin. However, this will most likely change in the near future: if the AngularCompilerPlugin is already present in the webpack.config.js file we can skip this paragraph and go ahead.

Patching the webpack.config.vendor.js file

Before going further, the webpack.config.vendor.js file needs to be updated as well in order to fix a nasty bug that would prevent it from working as expected with Angular 5. Open that file and add the following line to the already existing sharedConfig.plugin array in the following way (new line highlighted):

[...]

plugins: [
    new webpack.ProvidePlugin({ $: 'jquery', jQuery: 'jquery' }), // Maps these identifiers to the jQuery package (because Bootstrap expects it to be a global variable)
    new webpack.ContextReplacementPlugin(/\@angular\b.*\b(bundles|linker)/, path.join(__dirname, './ClientApp')), // Workaround for https://github.com/angular/angular/issues/11580
    new webpack.ContextReplacementPlugin(/angular(\\|\/)core(\\|\/)@angular/, path.join(__dirname, './ClientApp')), // Workaround for https://github.com/angular/angular/issues/14898
    new webpack.ContextReplacementPlugin(/\@angular(\\|\/)core(\\|\/)esm5/, path.join(__dirname, './ClientApp')), // Workaround for https://github.com/angular/angular/issues/20357
    new webpack.IgnorePlugin(/^vertx$/) // Workaround for https://github.com/stefanpenner/es6-promise/issues/100
]

[...]  

For further info regarding this fix, you can refer to the relevant GitHub issue at the following URL: https://github.com/angular/angular/issues/20357

Note

At the time of writing, this patch has to be done manually; however, it's more than likely that it will be included in a future release of the template package, together with the other GitHub issues already present. Needless to say, if that's the case we can skip this paragraph and go ahead.

Why use a dynamic module bundler?

Before moving ahead, it can be useful to explain why we just did so much hard work with a dynamic module packer/bundler such as Webpack instead of dropping a bunch of links pointing to all the relevant JS files--either hosted locally or, even better, through a high-performance CDN--right from the beginning.

To keep it simple, we did that because it's the only way to efficiently handle any modern JavaScript modular system such as Angular, RxJS, and also all applications based upon them, including the one we're working on right now.

What's a modular system exactly? It's nothing more than a package, library, or application split into a series of smaller files depending on each other using reference statements such as import and require. ASP.NET, Java, Python, and most compilation-based languages have it; that's not the case of script-based languages such as PHP and JavaScript, which are doomed to preload everything in memory before being able to determine whenever they'll be using it or not. All these change with the introduction of ECMAScript 6 (also known as ES6), which brings a full-featured module and dependency management solution for JavaScript.

Module bundlers such as Webpack pack a number of relevant JS/CSS resources at build time, including most ES6-polyfills for browsers that don't support it already, allowing us to get that module system working in modern browsers. Since both Angular and RxJS leverage such an approach, implementing it within our project will result in a huge performance gain.

We chose Webpack over other module packers, bundlers, and/or loaders (such as SystemJS) because of its great flexibility, as it provides a great way to properly package our application (concat, uglify, and the likes) with the additional knowledge given by its dependency graph. Additionally, Webpack received a great level of support in .NET Core 2, thanks to the introduction of the Microsoft ASP.NET Core JavaScript Services project and the Webpack Middleware, as we've already seen in this paragraph, making it the most logical choice when developing with .NET Core and Angular.

Refreshing the Webpack-generated files

To force Webpack to re-compile the vendor configuration file taking into account the fix we applied early on, we need to run the following command-line instruction from the project's root folder:

> node node_modules/webpack/bin/webpack.js --config webpack.config.vendor.js

Note

A convenient update-webpack.bat batch file has been added to this book's source code repository on GitHub to handle that--without manually having to type the above command.

Alternatively, we can also delete the /wwwroot/dist/ folder to force a full re-compilation upon the first project build.

It's generally wise to recompile the vendor configuration file everytime whenever we perform a task that could impact the generated bundles, such as: update the package.json file, perform a manual npm update from the command-line, alter the webpack.config.js configuration file, and so on.

The server-side code

Now that we've understood the meaning of the root configuration files, we can take a look at the Server-Side code shipped with the Angular SPA Template. As we already saw, we're talking about the contents of the /Controllers/ and /Views/ folders; let's start with the former.

Controllers/HomeController.cs

If we remember what we've seen within the Startup.cs file, we already know that it is the controller that all the requests not pointing to static files will be routed to. In other words, HomeController will handle all the requests that point (or get redirected to) our Single-Page Application first landing page, which we'll call Home View from now on.

More specifically, these requests will be handled by the Index action method. If we open the HomeController.cs file, we can see that the method does indeed exist, although being extremely lightweight--a single line of code that just returns the default Index View. That's more than enough; there's nothing to add there, as this is precisely what we need for a Single-Page Application entry page--just serve the Home View and let the client-side framework, Angular via Webpack, in our scenario, handle the rest.

The only exception for such behavior will be when we need to route the user away from the SPA, for example, when he's hitting an unrecoverable error. For these kinds of scenarios, an Error() action method was also implemented within the HomeController, which returns a dedicated Error View; however, before doing that, it will add some basic debug information to the ViewData collection (the current request unique identifier). This level of error handling is far from ideal, but we can live with it for the time being.

Controllers/SampleDataController.cs

The HomeController is a perfect example of a standard MVC Controller returning Views; conversely, the SampleDataController.cs is only returning structured JSON data, thus making it conceptually closer to the APIControllers featured by the ASP.NET Web API framework. Luckily enough, the new MVC 6 merged the best of both worlds into one, which means that there's no difference between these two kinds of controllers anymore; we're free to return any content we want from within the same controller class.

That said, there's no need to dig much into this controller's code for now; we'll do that soon enough, starting from Chapter 2, Backend with .NET Core. Let's just take a look at the resulting JSON data by issuing a couple of requests.

Start the application in debug mode by clicking on the Run button or pressing the F5 keyboard key; then, replace the /home part of the address bar URL with /api/SampleData/WeatherForecasts. The full URL should be just like the following:

http://localhost:<port>/api/SampleData/WeatherForecasts

We should be able to see something like this:

These are the raw (sample) data elements coming out from the server. Now, point the URL back to /home, which will bring us back to the Home View. From there, click on the Fetch data link from the left menu to get the following:

These are the same data elements mentioned earlier, fetched and served by Angular through the sample SPA provided by our current project template. All the GUI elements--menu links, page title, and labels, HTML code, CSS styles, and so on--are inside the /ClientApp/ folder; the server-side code only provides the raw data, just like it's meant to be.

The /Views/ folder

A quick look at the /Views/ folder is more than enough, as the view files merely contain the least possible amount of required code:

  • A minimalistic HTML5 skeleton to host the <head> and <body> elements, along with some child elements, such as the <title> page
  • Some <script> and <link> elements pointing to the local paths where the Webpack bundles will be built
  • The <app> element, which is the DOM placeholder used by Angular to inject the SPA into

Those who are used to the ASP.NET MVC and Razor convention can easily see how the template did a good job in putting all the common HTML structure in the Layout view (the _Layout.cshtml file), leaving the Index and Error views as lightweight as possible. The result is stunning and also very easy to read--the whole HTML base structure is comprised within a few lines of Razor and HTML code.

The client-side code

Last but not least, let's pay a visit to the sample Angular app and see how it works. Rest assured, we won't stay for long; we just want to take a glimpse of what's under the hood.

By expanding the /ClientApp/ directory, we can see that there are three subfolders and two files. However, the only thing that we should take into consideration, for the time being, is the /ClientApp/app/ folder, along with all its subfolders; this is the place containing all the Angular TypeScript files. In other words, the whole source code of our client-side application is meant to be put here.

Before going there, let's spend a couple words on its siblings:

  • The /ClientApp/dist/ folder and the boot.server.ts file are both used by Webpack to build the server bundles that will be used to enable the Angular Universal's Server-Side Rendering (SSR), which has been adopted and implemented by .NET Core 2.0 within the Microsoft ASP.NET Core JavaScript Services package. We'll get back to it later on; however, we can safely ignore them both for now.
  • The /Client/test/ folder is where we'll put our unit tests; we can entirely skip it for now and get back once we're ready.
  • The boot.browser.ts file contains the first code that will be executed by the browser, thus acting as the client-side bootstrapper of our Angular application; if we open it and take a look at the code, we can see how it imports the required packages to perform the bootstrap--including the AppModule from the /ClientApp/app/ folder--and then perform the app initialization within the <app> HTML element, also using different behaviors for development and production. Although it plays a very important role, we won't need to change its contents for a while; hence it's better to leave it as it is for now and focus on the application source code instead.

Note

If you're curious about Angular Universal and Server-Side Rendering and want to know more about them, we strongly suggest you to start with reading this good article by Burak Tasci:https://medium.com/burak-tasci/angular-4-with-server-side-rendering-aka-angular-universal-f6c228ded8b0 Although not diving deep into these concepts, it does a good job of explaining the core concept of this innovative approach. As soon as you get the basics, you can take a look at the real deal here:https://universal.angular.io/https://github.com/aspnet/JavaScriptServices

The /ClientApp/app/ folder

The /ClientApp/app/ folder loosely follows the Angular folder structure best practices, thus containing the following:

  • A /component/ folder, containing all the Angular components. We will talk more about them in Chapter 3, Frontend with Angular; for now, we'll just say that these are the building UI blocks of any Angular application, to the point that we can say that it is basically a tree of components working together. Each component has its very own namespace, which is represented with a subfolder, and comes with the following:
    • A required TypeScript file, which follows the <componentName>.component.ts naming conventions
    • An optional HTML file containing the component template, or (in other words) its UI layout structure
    • An optional CSS file to handle the UI styling
    • Other optional files, such as the counter.component.spec.ts in the /components/counter/ folder, which can be used whenever we need to split the component code into multiple files for readability or code reuse purposes
  • Three TypeScript files: app.module.browser.ts, app.module.server.ts, and app.module.shared.ts containing the Angular root module class, also known as the AppModule.

If you already have some Angular experience, you most likely know what the AppModule is and how it works. If you don't, the only thing you need to understand is that it serves as the main application entry point, the one that gets bootstrapped by the boot file(s) we talked about earlier.

Here's a schema of the standard Angular Initialization Cycle that will help us better visualize how it works:

As we can see, the boot.ts file bootstraps the app.module.ts (AppModule), which then loads the app.component.ts file (AppComponent); the latter will then load all the other components whenever the application needs them.

We can find such structure in any Angular application, it being the default initialization behavior enforced by the Angular.io project developers. However, the Angular SPA template we've chosen features a slightly more complex scenario because, as we said earlier, it also supports Server-Side Rendering; for this very reason, it needs to take care of the server-side part as well. This is why we got two very different boot files --boot.browser.ts and boot.server.ts, respectively--to load our app into the browser and to support Server-Side Rendering, and also two different AppModule classes to boot: the app.module.browser.ts and app.module.server.ts, both of them including the common app.module.shared.ts file.

Here's the improved schema when using SSR:

All these files will then be processed by Webpack and built in the /wwwroot/dist/main-client.js and /ClientApp/dist/main-server.js files, which will contain the "bundled" version of our Angular app, respectively, for Client-Side and Server-Side rendering.

That's about it, at least for now. If you feel like you're still missing something here, don't worry, we'll be back there soon enough to understand all of this better.

 

Getting to work


Now that we've got a general picture of our new project, it's time to do something. Let's start with two simple exercises that will also come handy in the future: the first one of them will involve the server-side aspects of our application, while the latter will be performed on the client-side. Both will help us acknowledge whether we really understood everything there is to know before proceeding to the subsequent chapters.

Static file caching

Let's start with the server-side task. Do you remember the /wwwroot/test.html file we added when we wanted to check how the StaticFiles middleware works? We will use it to do a quick demonstration of how our application will internally cache static files.

The first thing we have to do is to run the application in debug mode (by clicking on the Run button or pressing the F5 key) and put the following URL in the address line, so we can have another good look at it.

Right after that, without stopping the application, open the test.html file and add the following lines to its existing content (new lines are highlighted):

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Time for a test!</title>
</head>
<body>
    Hello there!
    <br /><br />
    This is a test to see if the StaticFiles middleware is working properly.
    <br /><br />
    IT DOES, BUT THE FILES ARE CACHED ON CLIENTS BY DEFAULT!
</body>
</html>

Save the file, then go back to the browser address bar and press Enter again to issue another HTTP request to the test.html file. Ensure that you don't use F5 or the refresh button, as it will force a page refresh from the server, which is not what we want; you will see that the preceding changes won't be reflected by your browser, which means that you hit a client-cached version of that page.

Caching static files on the clients can be a good thing in production servers, but is definitely annoying during development. Luckily enough, as we said earlier, the Webpack middleware will automatically fix this issue for all the TypeScript files, and also for all the static assets we'll serve through Webpack itself. However, what about the other ones? We'll most likely have some static HTML files, favicons, image files, audio files, or anything else that we would like to be directly served by the web server.

Is there a way to fine-tune the caching behavior for static files? If so, can we also set up different behaviors for the debug/development and release/production scenarios?

The answer is yes for both questions; let's see how we can do that.

A blast from the past

Back in ASP.NET 4, we could easily disable static files caching by adding some lines to our main application's Web.config file, such as the following:

 <caching enabled="false" /> 
<staticContent> 
  <clientCache cacheControlMode="DisableCache" /> 
</staticContent> 
<httpProtocol> 
  <customHeaders> 
    <add name="Cache-Control" value="no-cache, no-store" /> 
    <add name="Pragma" value="no-cache" /> 
    <add name="Expires" value="-1" /> 
  </customHeaders> 
</httpProtocol> 

That would be it; we can even restrict such behavior to the debug environment by adding these lines to the Web.debug.config file.

We can't use the same approach in .NET Core, as the configuration system has been redesigned from scratch and is now quite different from the previous versions; as we said earlier, the Web.config and Web.debug.config files have been replaced by the appsettings.json and appsettings.Development.json files, which also work in a completely different way. Now that we understood the basics, let's see whether we can solve that caching issue by taking advantage of the new configuration model.

Back to the future

The first thing to do is to understand how we can modify the default HTTP headers for static files; as a matter of fact, we can do that by adding a custom set of options to the app.UseDefaultFiles() method call in the Startup.cs file that adds the StaticFiles middleware to the HTTP request pipeline.

In order to do that, open Startup.cs, scroll down to the Configure method, and replace that single line with the following code (new/modified lines are highlighted):

app.UseStaticFiles(new StaticFileOptions()
{
    OnPrepareResponse = (context) =>
    {
        // Disable caching for all static files. 
        context.Context.Response.Headers["Cache-Control"] = "no-cache,    
         no-store";
        context.Context.Response.Headers["Pragma"] = "no-cache";
        context.Context.Response.Headers["Expires"] = "-1";
    }
});

That wasn't hard at all; we just added some additional configuration values to the method call, wrapping them all within a dedicated StaticFileOptions object instance.

However, we're not done yet; now that we learned how to change the default behavior, we just need to change these static values with some convenient references pointing to the appsettings.Development.json file. To do that, we can add the following key/value section to the appsettings.Development.json file in the following way (new lines highlighted):

 {
  "Logging": {
    "IncludeScopes": false,
    "Debug": {
      "LogLevel": {
        "Default": "Debug",
        "System": "Information",
        "Microsoft": "Information"
      }
    },
    "Console": {
      "LogLevel": {
        "Default": "Debug",
        "System": "Information",
        "Microsoft": "Information"
      }
    }
  },
  "StaticFiles": {
    "Headers": {
      "Cache-Control": "no-cache, no-store",
      "Pragma": "no-cache",
      "Expires": "-1"
    }
  }
} 

Then, change the preceding Startup.cs code accordingly (modified lines highlighted):

 app.UseStaticFiles(new StaticFileOptions()
{
    OnPrepareResponse = (context) =>
    {
        // Disable caching for all static files. 
        context.Context.Response.Headers["Cache-Control"] = 
            Configuration["StaticFiles:Headers:Cache-Control"];
        context.Context.Response.Headers["Pragma"] = 
            Configuration["StaticFiles:Headers:Pragma"];
        context.Context.Response.Headers["Expires"] = 
            Configuration["StaticFiles:Headers:Expires"];
    }
});

Ensure that you add these values to the non-development version of the appsettings.json file as well, otherwise the application won't find them (when executed outside a development environment) and throw an error.

Since this will most likely happen in a production environment, we can take the chance to relax these caching policies a bit:

 {
  "Logging": {
    "IncludeScopes": false,
    "Debug": {
      "LogLevel": {
        "Default": "Warning"
      }
    },
    "Console": {
      "LogLevel": {
        "Default": "Warning"
      }
    }
  },
  "StaticFiles": {
    "Headers": {
      "Cache-Control": "max-age=3600",
      "Pragma": "cache",
      "Expires": null
    }
  }
}  

That's about it. Learning how to use this pattern is strongly advisable, as it's a great and effective way to properly configure our application's settings.

Testing it up

Let's see whether our new caching strategy is working as expected. Run the application in debug mode, and then issue a request to the test.html page by typing the following URL in the browser address bar:

http://localhost:<port>/test.html

We should be able to see the updated contents with the phrase we wrote earlier; if not, press F5 from the browser to force a page retrieval from the server:

Now, without stopping the application, edit the test.html page and update its contents in the following way (updated lines are highlighted):

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Time for a test!</title>
 </head>
 <body>
    Hello there!
    <br /><br />
    This is a test to see if the StaticFiles middleware is working 
     properly.
    <br /><br />
    It seems like it works, and now it doesn't even cache those files!
</body>
</html>

Right after that, go back to the browser, select the address bar, and press Enter; again, ensure that you did not press the refresh button or the F5 key, or you'll have to start over. If everything worked properly, we will immediately see the updated contents on screen:

We did it! Our server-side task was successfully completed.

The strongly-typed approach(es)

The approach that we chose to retrieve the appsettings.json configuration values makes use of the generic IConfiguration object, which can be queried using the preceding string-based syntax. This approach is rather practical; however, if we want to retrieve this data in a more robust way, for example, in a strongly-typed fashion, we can--and should--implement something better. Although we won't dive deeper into that within this book, we can suggest reading the following great articles showing three different approaches to achieve this result:

The first one, written by Rick Strahl, explains how to do that using the IOptions<T> provider interface:

https://weblog.west-wind.com/posts/2016/may/23/strongly-typed-configuration-settings-in-aspnet-core

The second, by Filip W, explains how to do that with a simple POCO class, thus avoiding the IOptions<T> interface and the extra dependencies required by the preceding approach:

https://www.strathweb.com/2016/09/strongly-typed-configuration-in-asp-net-core-without-ioptionst/

The third, by Khalid Abuhakmeh, shows an alternative way to use a standard POCO class and directly register it as a Singleton with the ServicesCollection, while also (optionally) shielding it from unwanted modifications due to development mistakes:

https://rimdev.io/strongly-typed-configuration-settings-in-asp-net-core-part-ii/

All of these approaches were meant to work with .NET Core 1.x; however, they can still be very usable in .NET Core 2. That said, if we were to choose, we would probably go with the latter, as we found it to be the most clean and clever one.

Client app cleanup

Now that our server-side journey has come to an end, it's time to challenge ourselves with a quick client-side exercise. Don't worry, it will be just a rather trivial demonstration of how we can update the Angular source code that lies within the /ClientApp/ folder to better suit our needs. More specifically, we will remove all the stuff we don't need from the sample Angular app shipped with our chosen Angular SPA Template and replace them with our own content.

Note

We'll never say it enough, so it's worth repeating it again. The sample source code explained in the following paragraphs is taken from the MVC ASP.NET Core with Angular project template originally shipped with Visual Studio 2017 v15.3; since it might be updated in the future, it's important to check it against the code published in this book's GitHub repo. If you find relevant differences between the book code and yours, feel free to get the one from the repository and use that instead.

Trimming down the component list

If we navigate through the /ClientApp/app/components/ folder, we can take another close look at the components that are currently in place:

  • The /app/ folder contains the files related to the AppComponent, which is the main application component file; it's the one in charge to dynamically load all the other components, hence we definitely want to keep it.
  • The /home/ folder contains the files related to HomeComponent, which hosts the Home View contents. Do you remember the introductory text shown on the browser when we run the project? This is where we can find (and update) it. Our SPA will most likely need a home as well, so it's better to keep it too.
  • The /navmenu/ folder contains the files related to NavMenuComponent, which handles the layout and the functionalities of the navigation menu to the left. Even if we will make a lot of changes to this menu, keeping it as a working base would be a good idea.

The /counter/ and /fetchdata/ folders contain two sample components, which demonstrate how to implement two very common Angular features: respectively, affect the DOM in real time and fetch data from the web server. Although they can still use them as valuable code samples, keeping them within our client code will eventually confuse us, hence it's better to move these two folders outside the project - or just entirely delete them - to prevent the Visual Studio TypeScript compiler from messing with the .ts files contained there.

However, as soon as we do that, the Visual Studio Error List view will immediately raise two blocking TypeScript-based issues:

Error TS2307 (TS) Cannot find module './components/fetchdata/fetchdata.component'.
Error TS2307 (TS) Cannot find module './components/counter/counter.component'. 

Both errors will point to the app.module.shared.ts file, which, as we already know, contains the references of all the TypeScript files used by our Angular application and required by either the client (for browser rendering) and the server (to enable server-side rendering). If we open the file, we can clearly see where the problem is:

To fix it, we need to remove the offending references. However, when we do that, the following TypeScript errors will be raised:

Error TS2304 (TS) Cannot find name 'CounterComponent'.
Error TS2304 (TS) Cannot find name 'FetchDataComponent'.
Error TS2304 (TS) Cannot find name 'CounterComponent'.
Error TS2304 (TS) Cannot find name 'FetchDataComponent'.

All these issues will also point to the app.module.shared.ts file, which now has four names without a valid reference:

Remove all the four lines containing the errors to fix them.

Once done, our updated AppModuleShared file should look like this:

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { RouterModule } from '@angular/router';

import { AppComponent } from './components/app/app.component';
import { NavMenuComponent } from './components/navmenu/navmenu.component';
import { HomeComponent } from './components/home/home.component';

@NgModule({
    declarations: [
        AppComponent,
        NavMenuComponent,
        HomeComponent
    ],
    imports: [
        CommonModule,
        HttpModule,
        FormsModule,
        RouterModule.forRoot([
            { path: '', redirectTo: 'home', pathMatch: 'full' },
            { path: 'home', component: HomeComponent },
            { path: '**', redirectTo: 'home' }
        ])
    ]
})
export class AppModuleShared {
}

Since we're here, those who don't know how Angular works should spend a couple of minutes to understand how an AppModule class actually works. We already know why we got three files instead of one--to allow SSR--but we never talked about the source code.

The AppModule class(es)

Angular Modules, also known as NgModules, have been introduced in Angular 2 RC5 and are a great and powerful way to organize and bootstrap any Angular application; they help developers consolidate their own set of components, directives, and pipes into reusable blocks.

Every Angular application since v2 RC5 must have at least one module, which is conventionally called root module and thus given the AppModule class name.

AppModule is usually split into two main code blocks:

  • A list of import statements, pointing to all the references (in the form of TS files) required by the application.
  • The root NgModule declaration, which--as we can see--is basically an array of named arrays, each one containing a set of Angular objects that serves a common purpose: directives, components, pipes, modules, providers, and so on. The last one of them contains the component we want to bootstrap, which in most scenarios--including ours--is the main application component, the AppComponent.

Updating the NavMenu

If we run our project in debug mode, we can see that our code changes don't prevent the client app from booting properly. We didn't break it this time, yay! However, if we try to use the navigation menu to go to the Counter and/or Fetch data, nothing will happen; this is hardly a surprise, since we just moved these components out of the way. To avoid confusion, let's remove these links from the menu as well.

Open the /ClientApp/app/components/navmenu/navmenu.component.html file and delete the offending lines. Once done, the updated source code should look as follows:

<div class='main-nav'>
    <div class='navbar navbar-inverse'>
        <div class='navbar-header'>
            <button type='button' class='navbar-toggle' data-   
              toggle='collapse' data-target='.navbar-collapse'>
                <span class='sr-only'>Toggle navigation</span>
                <span class='icon-bar'></span>
                <span class='icon-bar'></span>
                <span class='icon-bar'></span>
            </button>
            <a class='navbar-brand' [routerLink]=" 
            ['/home']">TestMakerFree</a>
        </div>
        <div class='clearfix'></div>
        <div class='navbar-collapse collapse'>
            <ul class='nav navbar-nav'>
                <li [routerLinkActive]="['link-active']">
                    <a [routerLink]="['/home']">
                        <span class='glyphicon glyphicon-home'></span>       
                          Home
                    </a>
                </li>
            </ul>
        </div>
    </div>
</div>

While we're here, let's take the chance to get rid of something else. Do you remember the Hello, World! introductory text shown by the browser when we firstly ran the project? Let's change it with our own content.

Open the /ClientApp/app/components/home/home.component.html file and replace its whole content with the following:

<h1>Greetings, stranger!</h1>
<p>This is what you get for messing up with .NET Core and Angular.</p>

Save, run the project in debug mode and get ready to see the following:

The Counter and Fetch data menu links are gone, and our Home View welcome text couldn't be sleeker.

That's about it for now. Rest assured, we can easily do the same with other components and completely rewrite their text, including the navigation menu; we'll do that in the following chapters, where we'll also update the UI layout, add new components, and so on. For the time being, understanding how easy it is to change the content--and also how fast Webpack will handle our modifications--is good enough.

 

References


  • Native Web Apps, Henrik Joreteg, 2015
  • Manifesto for Agile Software Development, Kent Beck, Mike Beedle & many others, 2001
 

Suggested topics


SCRUM, Extreme Programming, MVC and MVVM architectural patterns, ASP.NET Core, .NET Core, Roslyn, CoreCLR, RyuJIT, Single-Page Application (SPA), NuGet, NPM, ECMAScript 6, Bower, Webpack, SystemJS, RxJS, Cache-Control, HTTP Headers, .NET Middleware, Angular Universal, Server-Side Rendering (SSR).

 

Summary


So far so good; we just set up a working skeleton of what's about to come. Before moving further, let's do a quick recap of what we just did in this chapter.

We briefly described our platforms of choice--ASP.NET Core and Angular--and acknowledged their combined potential in the process of building a modern web application. Then, we chose a Native Web Application with a Single-Page Application approach as the ideal field of choice for testing what our frameworks are able to do (and how to do it).

In an attempt to reproduce a realistic production-case scenario, we also went through the most common SPA features, first from a technical point of view, and then putting ourselves in the shoes of a typical Product Owner and trying to enumerate their expectations. We also made a quick list of everything we need to put together a potentially shippable product featuring all the expected goodies.

Eventually, we did our best to properly set up our development environment; we chose to do that using the default Angular SPA Template shipped with Visual Studio, thus adopting the standard ASP.NET Core approach. Right after that, we also spent some valuable time to look up and understand its core components, how they're working together, and their distinctive roles: the root configuration files, the server-side code, and the client-side code.

Finally, we performed some quick tests to see whether we're ready to hold our ground against what's coming next: setting up an improved request-response cycle, building our own Controllers, defining additional routing strategies, and more.

About the Author

  • Valerio De Sanctis

    Valerio De Sanctis is a skilled IT professional with over 12 years' experience in lead programming, web-based development, and project management using ASP.NET, PHP, and Java. He previously held senior positions at a range of financial and insurance companies, most recently serving as Chief Technology Officer and Chief Operating Officer at a leading after-sales and IT service provider for many top-tier life and non-life insurance groups.

    In the course of his career, Valerio De Sanctis helped many private organizations implement and maintain .NET-based solutions, working side-by-side with many IT industry experts and leading several frontend, backend, and UX development teams. He designed the architecture and actively oversaw the development of a wide number of corporate-level web application projects for high-profile clients, customers, and partners, including London Stock Exchange Group, Zurich Insurance Group, Allianz, Generali, Harmonie Mutuelle, AIG, QBE, Marsh & McLennan, Lloyd's, Honda Motor, FCA Group, Luxottica, ANSA, Saipem, ENI, Enel, Terna, Banzai Media, Virgilio, la Repubblica, and Corriere della Sera.

    He is an active member of the Stack Exchange Network, providing advice and tips for .NET, JavaScript, HTML5, and other web-related topics on the StackOverflow, ServerFault, and SuperUser communities. Most of his projects and code samples are available under open source licenses on GitHub, BitBucket, NPM, CocoaPods, JQuery Plugin Registry, and WordPress Plugin Repository.

    Starting from 2015, he has also run an IT-oriented, web-focused blog featuring news, reviews, code samples, and guides to help developers and enthusiasts worldwide. Between 2016 and 2017, he wrote two books on web development: ASP.NET Core and Angular 2, and ASP.NET Core: Cloud-ready, Enterprise Web Application Development, with over 5,000 copies sold worldwide.

    Browse publications by this author

Latest Reviews

(20 reviews total)
Good book to learn how to startup a SPA easily. I just give 4 stars because the book has few typos with the exercice source codes but you can download the examples by chapter to correct them.
This book is definitively Great ! A bunch of valuable information. I don't put 5 stars because the approach of using a template from visual studio is not the most common one (regarding what I understant) and It prevents to start with whatever version of angular you want. So, It's perhaps not the most generic approach that you can have. For the rest, everything is very well documented and the author has done a really fine and impressive job.
Tudo 100% ok. Muito bom!!!

Recommended For You

ASP.NET Core 2 and Vue.js

Leverage ASP.NET core 2.0 web API and the power of Vue.js at the client side to create modern applications from scratch

By Stuart Ratcliffe
C# 8.0 and .NET Core 3.0 – Modern Cross-Platform Development - Fourth Edition

Learn the fundamentals, practical applications, and latest features of C# 8.0 and .NET Core 3.0 from expert teacher Mark J. Price.

By Mark J. Price
Hands-On Software Architecture with C# 8 and .NET Core 3

Design scalable and high-performance enterprise applications using the latest features of C# 8 and .NET Core 3

By Francesco Abbruzzese and 1 more
Docker on Windows - Second Edition

Learn how to run new and old applications in Docker containers on Windows - modernizing the architecture, improving security and maximizing efficiency.

By Elton Stoneman