When starting a new web application, we’re faced with many architectural choices for the way we construct our application. Even after narrowing down the technologies we intend to use to Angular and ASP.NET Core, we still need to decide between several alternative ways of using these architectures.
The Challenge
Angular, unlike its predecessor AngularJS, comes with a technology stack. Angular is intended for use with TypeScript, Webpack, npm and NodeJS. These are all technologies that are commonly found in the JavaScript ecosystem.
TypeScript is the language of choice for Angular: It was selected by the Angular team, and used to develop the Angular source code. TypeScript combines the dynamic world of JavaScript with the advantages of strong typing, and a syntax that could described as “C# like”. TypeScript code must be compiled into JavaScript that can then be run in the browser or NodeJS
In a typical Angular application development stack, Webpack is commonly used to provide dependency resolution, bundling, and tooling. Webpack’s method of bundling feels more like a compiler than a mere JavaScript bundler or minifier. In addition, Webpack’s tooling supports a method of refreshing the DOM on-the-fly with updates when either markup or code changes in the application. This method of keeping the live application up-to-date is called Hot Module Reloading (HMR) and is a preferred work-flow for modern web development. To facilitate HMR, Webpack creates a NodeJS express instance.
The primary way to install all of Angular, and its third-party dependencies is to use npm. It is the package manager of choice for the JavaScript ecosystem. In addition, npm also serves as a task runner during application development.
These aren’t usually the first technologies that come to mind when considering an ASP.NET application. Additional tooling and support libraries have been added to Visual Studio 15.x, .NET Core SDK 2.0, and ASP.NET Core 2.0 to bridge the gap between what developers may consider the C# and JavaScript world. With ASP.NET Core 2.0, Visual Studio now includes an Angular project template which includes Angular Services, which is a library that abstracts Webpack and NodeJS. To complete the experience, a GUI task runner for npm can also be installed.
Feature Overlap
Unlike AngularJS, Angular takes over many responsibilities that once belonged to ASP.NET MVC. Most of the overlap is in the view stack of the application. Angular apps are built using a component architecture which includes HTML templating and databinding. These are features that are handled by Razor in ASP.NET via HTML and Tag Helpers, view components and the like. In addition, Angular also features routing that allows a single page application to have page routes just as if it were a standard web application. Server-side rendering of HTML components and templates are also possible with Angular. However, server-side rendering in Angular requires additional configuration, and depends on NodeJS.
Finding the Right Fit
Neither the JavaScript technology stack, nor the feature overlap of views and routing, should be the cause of culture shock. There are several productive alternative approaches to building an application with Angular and ASP.NET Core. Your options for structuring the app’s client and server architecture depend on factors such as application size, mobile needs, and code sharing desires. An ASP.NET Core application using Angular can be designed as all-in-one monolithic project, a server & web-client project, or even a multi-client project. Let’s look at each scenario and explore the strengths of each choice.
All-in-one
In this scenario, we have a single project, solution, and server. ASP.NET Core fills the role of server-side web API as well as bootstrapping the Angular client-side application.
All-in-one strengths
By using an all-in-one approach, you minimize the scope of the application. One solution means a single server. Hosting an all-in-one application means that the entire application can be deployed under a single server instance. Having fewer moving pieces often means less chance for something to go wrong. Even the file structure is simplified into Models, ClientApp and Controllers folders that represent the familiar MVC pattern.
There are Quick-start solutions for creating such an application that can be used either via the command line or Visual Studio templates using the “File New Project, ASP.NET Core Web Application” dialog.
In these quick-start solutions, Angular, TypeScript, ASP.NET Core, and Webpack are all configured to work together out-of-the-box. Developers who are less experienced with these technologies can jump in and begin working much more quickly than they would if they tried to create such an application from scratch. This ease of use is due to Webpack abstractions built into the template. This technology is known as Microsoft ASP.NET Core JavaScript Service, a set of technologies that allows execution of arbitrary JavaScript modules at runtime from .NET code.
What we’re getting from the template is a highly opinionated setup where many of the nuances required to initialize a project are planned out for us. This means that Webpack is configured to deal with vendor dependencies and server-side rendering. Included in the setup are processes to kick off the actual tooling, such that Webpack is initialized from within the ASP.NET application at startup. In addition, Hot Module Reload (HMR) is triggered from the applications middleware, thereby further automating the development process.
In this excerpt from Startup.cs you can see HMR being enabled through ASP.NET Middleware.
1 |
// Startup.CSpublic void Configure(IApplicationBuilder app, IHostingEnvironment env){ if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions { HotModuleReplacement = true }); } ...} |
The most notable piece of this setup is the inclusion of Angular’s server-side rendering. Server-side rendering in Angular works much as you would expect from Razor, in that HTML is built using server resources. One key difference is that this technology utilizes JavaScript technologies with the consequence that NodeJS is required for processing HTML on the server. Once again JavaScript Services hides this behind a layer of abstraction, thereby allowing developers to be more productive.
All-in-one considerations
Because Angular is frequently updated, you will find that the versions of Angular that are used in the JavaScript Services templates can lag behind the Angular CLI bits from Google. Be cautious when using third party Angular modules as they may depend on versions of Angular that are more current that those included in the template. Although the tooling does work as intended, both the tooling and dependencies should be updated to the latest version before beginning a development task.
If we’re looking for something less opinionated, then a Server Web-Client setup may be a good option.
Server Web-Client
In a server web-client approach, the server-side application code is kept completely separate from the client code. The server-side application has a clear responsibility to provide API endpoints while the client-side of the application strictly handles the user interface. In addition to the clean separation of responsibility, the code resides in separate solutions. Each solution is deployed to its own server instance, one server handling the ASP.NET Core Web API, while the other (ASP.NET or Node) serving the Angular web-client application and static files.
Unlike the all-in-one approach, the server web-client approach requires additional setup to build the application. There are no templates available from Microsoft to provide this configuration out-of-the-box. To create such an application, an ASP.NET web API application must be created and paired with an Angular client-side app manually. Once the server and client applications have been create, a few further steps are needed to make the two communicate.
To begin, we’ll start with a project template either from the dotnet CLI or Visual Studio. For this scenario, we’ll choose the Web API template as we will not need the view features that MVC provides.
In addition to the Web API project, we’ll need a client-side application. For the client, we can create an app using the Angular CLI. The Angular CLI will generate a very simplistic template. It’s up to the developer to choose how the server and client applications are developed. Both can be worked on in the same solution in Visual Studio, or they can be developed independently by teams using tools they are familiar with. For example, the server application can be developed in Visual Studio while the client is built using Visual Studio Code and the Angular CLI.
Since the Angular CLI generated application is made of web technologies, it can easily be added to a Visual Studio project using the ‘Add > Existing Website’ dialog.
Proxies
Working with both projects requires some additional setup. Since the Web API and Angular projects will be running in development mode, they will generally occupy different ports on localhost. When calling the Web API from Angular code, the client application will need to navigate to the port where the Web API resides. A proxy for Angular must be created to allow the client and server to seamlessly work together in development. The Web API address can be mapped to the Angular application by adding a proxy.config.json file in the Angular project. When Angular detects the URL pattern specified in the proxy configuration, it will forward the request to the target location.
1 |
// example proxy.config.json{ "/api": { "target": "http://localhost:5000", "secure": false }} |
This means that if an Angular application is hosted on http://localhost:3000, then any call to /api can be routed to the where the Web API is located on http://localhost:5000 via proxy.
Server Web-Client strengths
By separating ASP.NET Core web API from the Angular web-client, each can be developed independently. Each development team (server & client) can use task-specific technologies and tooling. The server-side application can be built using Visual Studio & ASP.NET Core templates while the Angular web-client can be built using the Angular CLI and your choice of editor.
With a server and web-client solution, the client and server can be deployed to their own server instances, thereby allowing computing resources to scale independently.
Server Web-Client considerations
Using separate projects can add complexity to the solution, so this approach may be more fitting to teams that have experienced and dedicated server & client developers. The lack of opinionated project configuration and code samples seen in the template for the all-in-one approach may be attractive to some. Advanced features such as server-side rendering will require additional work.
In addition to needing a proxy for the client application to work in the development environment, it may be necessary, depending on how the application is hosted, to Configure Cross-Origin Resource Sharing (CORS) in production. When hosting on multiple domains, ASP.NET Core will need CORS middleware loaded and configured based on the applications needs.
As with any approach, use what suits your team’s skills and capabilities for the best results. If a native mobile app fits your requirements then maybe a multi-client code-sharing scenario meets your needs.
Multi-Client & Code Sharing
One of the features of Angular is that it isn’t tied to the web Document Object Model (DOM). Angular can now utilize templates for UI types other than HTML. This means that Angular can be used to power applications that run JavaScript and use UI markup languages such as XML. NativeScript is one such platform that can use Angular code to power iOS and Android applications. This allows NativeScript and an Angular web application to share common code while rendering different templates. NativeScript’s strength in the mobile spaces is that while it uses an Angular code base, it does NOT use a web view. NativeScript applications are truly native iOS and Android applications.
Brad Green from the Angular team shared, in the podcast Eat Sleep Code: “Engineering Angular with Brad Green”, details of the Angular template engine and how it can go beyond HTML
The web client of the application can be built using the all-in-one or server-client method with the addition of an extra project type. In this scenario, a NativeScript application using Angular will be built to provide a native iOS and/or Android experience. To bootstrap the native application, the NativeScript CLI tooling or NativeScript Sidekick application can be used. Both approaches are capable of producing a starter template using Angular. Additionally, a future NativeScript Sidekick plugin for Visual Studio will create a full featured experience within Visual Studio.
Once the NativeScript application is created, it can then be easily added to Visual Studio as a web site using the ‘Add > Existing Web Site’ dialog. Because NativeScript utilizes web technologies such as XML, CSS, and TypeScript, the files are understood by Visual Studio. The NativeScript Sidekick companion application also assists with building and debugging the application. Through a process called LiveSync, NativeScript applications are able to receive live updates on-the-fly as and when the application code is modified. The LiveSync process is similar to what Angular developers are used to with Webpack’s HMR functionality.
Code Sharing
Because NativeScript source code is Angular and TypeScript, some logic is interchangeable between web and native applications. As with any code-sharing techniques, there are some things to be considered. Because NativeScript does not use a web view, there is no DOM. This means that application code that is has a DOM dependency cannot be used. In addition, NativeScript views are written in XML, so that views are not interchangeable between NativeScript and Angular on the web. However, business logic and services can be shared between apps and components. Because TypeScript is in play, interfaces, basic objects, and even object inheritance can be shared between applications.
Server Multi-Client benefits
Many of the same benefits apply from the Server Web-Client scenario with the addition of code sharing. By utilizing Angular templates, much of the client-side application code can be shared between the web-client and native mobile OS versions of the application. Since all of the code is written with web technologies (HTML, XML, CSS, TypeScript / JavaScript), developers familiar with the web have a great opportunity to build large-scale apps for a massive ecosystem. This technique can be combined with the all-in-one or server web-client scenario.
Furthermore, we’re not only sharing code between web and mobile, but we’re sharing code between iOS and Android as well.
An example of this can be seen on GitHub https://github.com/EdCharbeneau/AngularDotnetNativeScript/tree/master/src
Server Multi-Client considerations
The ability to ‘write-once/deploy-anywhere’ has always been the holy grail for developers. However, this usually comes at the cost of added complexity. It takes some up-front planning In order to keep each client type in parity with each other and to minimize friction. Although code sharing is possible, top most of the UI layer of the application is not shared. This means that while the TypeScript code can power both web and native mobile UI logic, the actual presentation itself needs to be written twice; once for the web in HTML and once for mobile in XML. Additionally, code sharing comes with its own difficulties. Sharing code will require additional scripting to either simply copy common code, or create share-able packages using npm.
Other considerations include working with mobile device deployment and testing. During development, the server portion of the application will need special firewall rules in order for devices and emulators to reach a locally-hosted service. As with any multi-client web application, CORS must also be configured properly for clients to consume web APIs.
Wrap up
No matter which architectural choices we make, Angular has its place in the future of ASP.NET application development. With so many architecture possibilities, it’s important to avoid getting overwhelmed by the range of choices. Each of the project types covered here can be scaled up at any point. Start with what works best for the needs of the project, team’s expertise, and deadlines.
A video demonstration of the architectural choices in this article can be seen on Channel 9’s Visual Studio Toolbox
Load comments