40,81 €
Leverage ASP.NET core 2.0 web API and the power of Vue.js at the client side to create modern applications from scratch
Key Features
Book Description
This book will walk you through the process of developing an e-commerce application from start to finish, utilizing an ASP.NET Core web API and Vue.js Single-Page Application (SPA) frontend.
We will build the application using a featureslice approach, whereby in each chapter we will add the required frontend and backend changes to complete an entire feature. In the early chapters, we'll keep things fairly simple to get you started, but by the end of the book, you'll be utilizing some advanced concepts, such as server-side rendering and continuous integration and deployment. You will learn how to set up and configure a modern development environment for building ASP.NET Core web APIs and Vue.js SPA frontends.You will also learn about how ASP.NET Core differs from its predecessors, and how we can utilize those changes to our benefit.
Finally, you will learn the fundamentals of building modern frontend applications using Vue.js, as well as some of the more advanced concepts, which can help make you more productive in your own applications in the future.
What you will learn
Who this book is for
This book is aimed at ASP.NET developers who are looking for an entry point in learning how to build a modern client-side SPA with Vue.js, or those with a basic understanding of Vue.js who are looking to build on their knowledge and apply it to a real-world application. Knowledge of JavaScript is not necessary, but would be an advantage.
Das E-Book können Sie in Legimi-Apps oder einer beliebigen App lesen, die das folgende Format unterstützen:
Seitenzahl: 697
Veröffentlichungsjahr: 2018
Copyright © 2018 Packt Publishing
All rights reserved. No part of this book may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, without the prior written permission of the publisher, except in the case of brief quotations embedded in critical articles or reviews.
Every effort has been made in the preparation of this book to ensure the accuracy of the information presented. However, the information contained in this book is sold without warranty, either express or implied. Neither the author, nor Packt Publishing or its dealers and distributors, will be held liable for any damages caused or alleged to have been caused directly or indirectly by this book.
Packt Publishing has endeavored to provide trademark information about all of the companies and products mentioned in this book by the appropriate use of capitals. However, Packt Publishing cannot guarantee the accuracy of this information.
Commissioning Editor: Amarabha BanerjeeAcquisition Editor:Siddharth MandalContent Development Editor: Aishwarya GawankarTechnical Editor: Prajakta MhatreCopy Editor: Safis EditigProject Coordinator: Sheejal ShahProofreader: Safis EditingIndexer:Tejal Daruwale SoniProduction Coordinator:Arvindkumar Gupta
First published: July 2018
Production reference: 1270718
Published by Packt Publishing Ltd. Livery Place 35 Livery Street Birmingham B3 2PB, UK.
ISBN 978-1-78883-946-4
www.packtpub.com
Mapt is an online digital library that gives you full access to over 5,000 books and videos, as well as industry leading tools to help you plan your personal development and advance your career. For more information, please visit our website.
Spend less time learning and more time coding with practical eBooks and Videos from over 4,000 industry professionals
Improve your learning with Skill Plans built especially for you
Get a free eBook or video every month
Mapt is fully searchable
Copy and paste, print, and bookmark content
Did you know that Packt offers eBook versions of every book published, with PDF and ePub files available? You can upgrade to the eBook version at www.PacktPub.com and as a print book customer, you are entitled to a discount on the eBook copy. Get in touch with us at [email protected] for more details.
At www.PacktPub.com, you can also read a collection of free technical articles, sign up for a range of free newsletters, and receive exclusive discounts and offers on Packt books and eBooks.
Stuart Ratcliffe is a professional software developer who lives and works in the East Midlands, UK. He has held positions at some of the largest IT companies in the world, working on high-profile projects for the UK government. Currently, he has been working on track-and-trace systems for medical instruments that undergo sterilization. He holds a Tech Lead position on the digital side of a healthcare company, building both web and mobile applications to support the clinical side of the business. He is a full-stack .NET developer who loves to learn new technologies.
Daniel Jiménez García is a software developer with more than 12 years of experience. His journey began with C# and VB6, continued with several iterations of Microsoft technologies and web frameworks such as Backbone, and finished with Node, Vue, Docker, and ASP.NET Core.
Nowadays, he is working as a tech lead for Oliver Wyman Labs, building web and mobile applications, mentoring fellow team members, and driving their common stack, tools, and architecture for web development.
Being a regular contributor to the DotNetCurry magazine, he has written 18 articles on a range of topics including ASP.NET Core and Vue.js.
If you're interested in becoming an author for Packt, please visit authors.packtpub.com and apply today. We have worked with thousands of developers and tech professionals, just like you, to help them share their insight with the global tech community. You can make a general application, apply for a specific hot topic that we are recruiting an author for, or submit your own idea.
Title Page
Copyright and Credits
ASP.NET Core 2 and Vue.js
Dedication
Packt Upsell
Why subscribe?
PacktPub.com
Contributors
About the author
About the reviewer
Packt is searching for authors like you
Preface
Who this book is for
What this book covers
To get the most out of this book
Download the example code files
Conventions used
Get in touch
Reviews
Understanding the Fundamentals
Thinking in components
What is a component?
UI composition
Introduction to Vue
The Vue instance
Attaching to the DOM
Defining data properties
Rendering data into the DOM using expressions
Building component trees
Reactivity
Component behavior
State
Props
Methods
Computed properties
Watchers
Lifecycle hooks
Component presentation
Directives
Attribute binding with v-bind
Conditional display with v-show
Control flow with v-if and v-else
Rendering lists with v-for
Event handling with v-on
Form input binding with v-model
Parent-child component communication
ASP.NET Core – what's new?
Middleware pipeline
Application startup
DI is a first-class citizen
EF Core – what's new?
Configuring relationships
Global query filters
Compiled queries
In-memory provider for testing
Summary
Setting Up the Development Environment
Choosing a web browser
Installing frontend tools and dependencies
Installing Node and npm
Installing Vue
npm or Yarn?
Installing backend tools and dependencies
Installing ASP.NET Core
Installing PostgreSQL
Choosing and installing an IDE
Productivity tools
Installing VS Code extensions
Installing the Vue.js Chrome devtools extension
Installing a Terminal Emulator on Windows (optional)
Summary
Getting Started with the Project
ASP.NET Core SPA templates versus CLI tools
An introduction to webpack
What is webpack?
How does it work?
Basic webpack configuration
Bundle splitting
Production bundles
Scaffolding a project with the dotnet CLI
Refactoring the frontend setup
Removing TypeScript
Replacing the default components
Refactoring the backend setup
Refactoring to a feature folder structure
Setting up the database
Creating a database context
Registering the database context for DI
Creating the database
Creating an initial migration
Creating and seeding the database on start-up
Testing the completed setup
Summary
Building Our First Vue.js Components
Displaying a list of products
Conditional rendering
Component composition
Client-side routing
Fetching data from an API
Summary
Building a Product Catalog
Improving the existing UX
Choosing a UX framework
What is Bootstrap-Vue?
Installing additional required dependencies
Modifying the webpack configuration to support SASS
Updating the webpack vendor configuration
Rebuilding the vendor bundle
Adding application-wide layout elements
Adding application-wide styles
Styling the product list and product details components
Fetching data before navigation
Adding a page loading indicator
Adding a transition on page change
Extending the existing data model
Dropping the existing database
Adding new/updating existing entities
Updating the DbContext class
Creating a migration to reflect the model changes
Updating the application's seed data
Filtering on the server
Updating controller actions to support filtering
Testing our filtering logic
Filtering on the client
Installing additional dependencies
Installing Font Awesome
Installing additional npm packages
Building an accordion component
Defining the accordion template structure
Defining the accordion behavior
Styling the accordion component
Building the filters component
Scaffolding the filters component template
Adding a brand filter
Adding a price filter
Adding a screen size filter
Adding the remaining color, OS, and feature filters
Scaffolding the filters component behavior
Defining the filters component computed properties
Defining the filters component methods
Styling the filters component
Adding the filters component to the catalog page
Updating the catalog page template
Adding the catalog page filter behavior
Tidying up our existing components
Testing the completed filtering logic
Refactoring the filters component
Highlighting duplication in our existing implementation
Extracting a common multi-select filter component
Extracting a common range filter component
Rendering the new multi-select and range filter components
Testing that everything still works
Client-side sorting
Building a sort component
Adding the sort component to the catalog page
Creating a search bar component
Triggering API requests using watchers
Debouncing API requests to limit how often they fire
Summary
Building a Shopping Cart
Evaluating our options
Persisting to the database
Persisting to session state
Persisting to local storage
Finishing the product details page
Creating the gallery component
Adding variants to the product details component
Introduction to Vuex
What is Vuex?
How does Vuex work?
Mutations
Actions
Getters
Putting it all together
Installing and configuring Vuex
Adding products to the cart
Creating the mutations
Creating an action 
Creating a shopping cart page
Creating a CartItem component
Displaying the list of cart items
Creating a currency filter
Removing products from the cart
Updating cart items
Adding a getter to display the cart total
Creating a cart summary component
Persisting the cart to local storage
Improving the UX with add to cart feedback
Summary
User Registration and Authentication
Adding JWT authentication to the API
Why JWTs?
Configuring JWT authentication
Issuing JWTs
Adding user role support
Testing JWT authentication
User registration
Authentication and user registration in the client app
Vuex state properties for authentication
Vuex mutations for managing authentication state
Vuex authentication getters
Vuex login, register, and logout actions
Authentication modal component
Login form component
Register form component
Auth navigation item component
Wiring up the new components in App.vue
Protecting pages with navigation guards
Setting the authentication state on app startup
Summary
Processing Payments
Why use Stripe?
Simple PCI compliance
Easy integration
Excellent dashboard
Getting started with Stripe and client-side validation
Registering for a Stripe account
Including the Stripe checkout JavaScript library
Installing VeeValidate for client-side validation
Building the checkout components
Building a cart summary component
Building a checkout form component
First look at client-side validation
Finishing the delivery address form fields
Capturing payment information
Initializing Stripe elements
Validating form input state
Verifying payment details with Stripe
Submitting the order to the API
Adding basic Bootstrap styling to Stripe elements
Building a checkout success component
Building a my account page
Building the OrderList component
Formatting dates with a reusable date filter
Linking to the my account page
Fixing the register form component
Server-side payment processing
Adding orders to the data model
Owned entity types in EF Core 2.0
Why use owned entity types?
Defining an owned type
Configuring owned types
Creating the orders migration
Installing and configuring the Stripe.net NuGet package
Configuring Stripe
Processing orders and payments
Persisting the order object
Calculating the total order price
Processing the payment with Stripe
Adding an order list API endpoint
Summary
Building an Admin Panel
Extending the authentication endpoint with user roles
Client-side role-based authorization
Adding role checks to client-side routes
Server-side role-based authorization
Hiding UI elements based on role
Building the admin panel components
Configuring nested route definitions
Refactoring components for reuse
Product list component
Creating a product form component
Creating an add variant modal component
Vue component inheritance
Defining a form input base component
Inheriting from a base component
Building custom input controls
Building a custom typeahead control
Building a multi-select control
Persisting new products to the database
Creating a slug generator
Creating the API endpoint
Remote validation with Vee-Validate
Making our app aware of the new custom validation rule
Creating the validation API endpoint
Tidying things up
Linking to the admin panel
Fixing a logout bug
Fixing a bug by selecting a product variant
Summary
Deployment
Registering for an Azure account
Setting up an Azure environment
Understanding Azure subscriptions and resources
Creating a subscription and resource group
Creating a database
Creating an app service
Configuring environment variables
Preparing the application for deployment
Configuring multiple database providers
Tweaking the post-publish build steps
Configuring Git deployments
Finalizing the apps configuration
Enabling logging in Azure
Forcing HTTPS connections only
Summary
Authentication and Refresh Token Flow
Understanding refresh tokens
What are refresh tokens used for?
What are refresh tokens?
Why use refresh tokens?
Adding refresh token support to the backend
Extending the AppUser model
Generating refresh tokens
Refreshing JWT access tokens
Finishing up
Adding refresh token support to the frontend
Extracting router configuration into separate files
Refreshing access tokens with axios interceptors
Finishing up
Summary
Server-Side Rendering
Why use SSR in the first place?
Search engine optimization
Performance
How does SSR work?
The easy way – Nuxt.js
Preparing the application for SSR
Installing npm packages required for SSR
Adding Vuex actions and mutations for all API requests
Defining additional Vuex actions
Defining the additional Vuex mutations
Defining the additional store state properties
Updating existing pages to use Vuex
Refactoring the catalog page
Refactoring the product details page
Refactoring the account page
Refactoring the orders admin page
Refactoring the products admin page
Refactoring the create product admin page
Changing the way we persist user authentication state
Changing our approach of persisting state to local storage
Storing authentication state in cookies
Setting up and configuring SSR
Defining the shared boot logic
Defining the client-specific boot logic
Hydrating the client-side store
Loading shopping cart data from local storage
Pre-fetching component data
Remembering our promises
Defining the server-specific boot logic
Deleting the old boot file
Making webpack aware of the client/server boot files
Defining a shared webpack configuration object
Defining client- and server-specific webpack configuration objects
Updating the vendor webpack configuration to include SSR libraries
Enabling SSR
Conditionally rendering elements that rely on the browser
Fixing the range filter component
Fixing the checkout form component
Fixing page transition animations in the router
Fixing the store subscription to persist cart items to local storage
Testing our server-rendered application
Summary
Continuous Integration and Continuous Deployment
CI/CD – why bother?
Continuous integration
Continuous deployment
Disabling Azure app service Git deployments
Getting started with VSTS
Creating a VSTS account
Setting up a team services project
Building a CI/CD pipeline
Setting up a VSTS build
Enabling CI
Setting up a VSTS release
Enabling CD
Summary
Other Books You May Enjoy
Leave a review - let other readers know what you think
These days, it is rare to see a standard web application with little to no client-side code involved. Developers are usually burdened with writing masses and masses of JavaScript, often using libraries such as jQuery, to create rich and responsive user interfaces. As an application like this grows, it is incredibly easy for this client-side code to become unwieldy and a nightmare to maintain. This style of web application also relies on the DOM to store the application's current state, and we end up writing a lot of code to micromanage and manipulate the DOM in order to correctly display that state.
Imagine a web application using nothing but jQuery on the client, where we have a single piece of data that we need to display in multiple places within a UI. Now think about how we'd need to go about changing that piece of data, and ensuring that the DOM represents the correct value in every location where we are displaying it. Up to a handful of places is perhaps not a big deal; we could write a bunch of similar lines of jQuery that manually go and update each UI element currently displaying that piece of data, and just make sure we don't forget any.
By now, you should be able to see the problem we're trying to solve. This way of developing web applications is incredibly error-prone for anything but the most simple user interfaces. However, this is 2018 and we aren't limited to writing our client applications with jQuery any more. There are countless SPA frameworks dedicated to building UIs for our web applications that automatically react to data changes and handle the displaying of that data in the DOM for us. We no longer need to write countless lines of code with a single purpose of changing the value of a DOM element.
We don't manipulate the DOM with these frameworks. Instead, we manipulate the data. The DOM simply acts as a means of displaying that data to our users. Let's go back to the preceding example, where we have a single piece of data being displayed in 10 different UI elements. When that piece of data changes, instead of manually updating all 10 DOM elements to reflect the change, we simply store it in a JavaScript object and update the value whenever we like. The SPA framework then reacts to these changes, and handles all the heavy lifting for us by updating any DOM element that cares about that piece of data; one simple data change rather than 10 separate DOM manipulation calls.
As with choosing a technology for the frontend of a modern web app, there are also plenty of options when it comes to building a backend. Some of the most popular choices currently include Node.js, PHP, Rails, Golang, and ASP.NET. Node.js is incredibly popular for a number of reasons, most notably for being able to use JavaScript for the whole application. The Laravel framework is arguably one of the only reasons PHP is still a viable option, else it would likely be fading into the background the way Rails is. Golang is a fairly new language that is getting some very good reviews, particularly in the performance benefits it provides over Node. However, due to how new Golang is, there are far fewer packages and frameworks to assist us in building more complex applications. ASP.NET is older than both Node.js and Golang, and, as such, there is no such shortage of packages and frameworks like there is with Go. In fact, the .NET framework has a lot of functionality already built in where you'd normally be reaching for an external package in other languages and frameworks. Even when you do need an external package, there is usually one made by Microsoft themselves, which helps avoid a well-known issue with Node.js applications referred to as "dependency hell". ASP.NET is also based around strongly-typed compiled languages that can provide a number of performance and security benefits over a weakly typed language, such as JavaScript.
ASP.NET has been around since January 2002 when version 1.0 of the .NET framework was released as the successor to Microsoft Active Server Pages. Since then, there have been a multitude of major versions released, the current being version 4.7 at the time of writing. In 2016, Microsoft changed their game entirely, with the release of ASP.NET Core. For the first time in over 14 years, ASP.NET was made both open source and cross-platform in a complete rewrite from the ground up. When version 1.0 of ASP.NET Core was released, there was one potentially significant downside depending on the size and complexity of your application. If you have a requirement to host on a platform other than Windows, you can't target the full .NET framework. The issue with this was a potential lack of necessary APIs that had not yet been ported over to the core CLR. However, version 2.0 has recently been released, and with it comes a compatibility shim that enables .NET Core apps to reference any .NET framework library.
If you've been avoiding the move to ASP.NET Core, then now is a great time to change that. Version 2.0 has added a number of other improvements aside from backward compatibility with .NET framework APIs and libraries: Simplified configuration setup, simplified NuGet package references, and additional SPA project templates, to name but a few. One of Microsoft's most well-known developers, Steve Sanderson (creator of the very popular KnockoutJS framework), has made it his goal to make ASP.NET Core the best backend choice for single-page applications. To achieve that goal; his team has implemented some amazing features to seamlessly integrate frontend and backend builds using ASP.NET Core middleware. These features, along with the latest improvements released in version 2.0, really do make ASP.NET Core a fantastic choice for any web application.
With so many SPA frameworks to choose from, why should we bother with Vue? Most developers with any kind of interest in modern web application development have probably heard of React and Angular, but far fewer will have heard of Vue. Initially created by a single developer, Evan You, and currently developed by a relatively small international team, you could be forgiven for ignoring it in favor of its main competition. After all, React and Angular are developed by the tech giants that are Facebook and Google, respectively.
However, after working at both Google and the Meteor Development Group, Evan You knows a little something about SPA frameworks. Vue was created after both React and AngularJS had some time to be battle tested by thousands of developers around the world. In the eyes of its creators, Vue incorporates the best parts that either of these frameworks had to offer, while also trying to avoid the pitfalls that caused common grievances throughout the community. The result is a very lightweight and focused library dedicated to building UIs only. However, the Vue team has always intended for this library to be incrementally adoptable in any web project, and has provided several supporting libraries that make Vue a fantastic choice for building fully fledged SPAs as well.
In my opinion, Vue is far simpler to learn than most of the alternatives, which makes it a great choice for experienced backend .NET developers looking to branch out into the world of frontend frameworks and modern SPAs. If you already know enough HTML and jQuery to make a standard MVC application, then the template syntax used by Vue won't be much of a problem, and a lot of the syntax can be directly compared to that of Razor. The barrier to entry may be low, and the library itself may be incredibly lightweight, but Vue can be every bit as powerful as any other SPA framework that exists today.
This book is aimed at ASP.NET developers who are looking for an entry point in learning how to build a modern client-side SPA with Vue.js, or those with a basic understanding of Vue.js who are looking to build on their knowledge and apply it to a real-world application. Knowledge of JavaScript is not necessary, but would be an advantage.
Chapter 1, Understanding the Fundamentals, starts by looking at the fundamentals of Vue.js to give readers a basic understanding of the techniques used to build the sample applications later in the book. It discusses some of the benefits of Vue.js, as well as some of the reasons why we'd bother to choose it for building our applications. Finally, it looks at how ASP.NET Core / EF Core differ from their previous counterparts, focusing on the very latest versions of the frameworks, and putting the emphasis on the newest features that you may not know about yet.
Chapter 2, Setting Up the Development Environment, walks you through the process of installing and configuring the tools that you'll need to build and run an ASP.NET Core and Vue.js SPA. It takes the cross-platform nature of ASP.NET Core into consideration while evaluating some of the options available to us when selecting a client-side package manager, an IDE, and an RDBMS. Finally, it shows you how to install some productivity tools that make our lives far easier while building Vue.js applications with Google Chrome.
Chapter 3, Getting Started with the Project, looks at the options available to you when starting and scaffolding a brand new project with ASP.NET Core and Vue.js. It introduces the basics of what webpack is and how it works, before scaffolding an application that will form the foundations that will be built on for the rest of the book. Finally, it looks at how to refactor the default application structure to meet your own needs and preferences.
Chapter 4, Building Our First Vue.js Components, jumps into building a basic product list component, before composing a component structure based on the standard master-details pattern to display more information about a selected product. It then introduces client-side routing by refactoring the UI into separate pages for the product list and details components, before replacing the hardcoded product data with dynamic data fetched from the backend API.
Chapter 5, Building a Product Catalog, expands the existing components into a fully featured product catalog, including filtering, sorting, and searching. It also improves the existing look and feel of the application by introducing the Bootstrap CSS framework, as well as adding animations and loading indicators in between page changes. The reader will learn how to identify and extract duplication into common reusable components, as well as how to import and render components from third-party libraries.
Chapter 6, Building a Shopping Cart, starts by evaluating the options available to us for persistent shopping cart items. It then introduces Vuex for centralizing client-side state and enabling access to it from multiple components. Readers will then learn how to consume Vuex state by building a shopping cart component, as well as a shopping cart summary component to display it. They will also learn how to create custom Vue.js filters to reduce duplication in presentation logic, as well as how to provide feedback to users by displaying toast messages. Finally, we will see how to quickly and easily persist Vuex state to local storage to make sure that it is available on subsequent visits to the application.
Chapter 7, User Registration and Authentication, looks at how to add access control using JWT-based authentication. You will learn how to protect API routes using ASP.NET Core middleware and action filters, as well as how to prevent access to client-side pages using Vue.js router navigation guards. You will also extend the existing Vuex store to include register and login functionality, as well as building the necessary components for consuming it.
Chapter 8, Processing Payments, completes the user journey of the customer by implementing a fully functioning checkout page, including payment processing with Stripe. You will learn why Stripe is the perfect library for payment processing in any type of e-commerce website, as well as how to integrate it into a Vue.js client application and ASP.NET Core API. You will also learn how to add rich client-side validation to a custom checkout form component, which provides immediate feedback to the user as they start typing in each field.
Chapter 9, Building an Admin Panel, adds the ability to manage the existing product catalog, and add new products to the database. Readers will learn how to reduce duplication by extracting common functionality into a base component and then using component inheritance to extend it. You will build a collection of reusable form input components and then refactor the existing forms to make use of them.
Chapter 10, Deployment, completes the first iteration of the application by deploying it to a production cloud environment. We start by registering for a Microsoft Azure account, before learning how to set up and configure our environment to include an app and database server. Readers will then learn how to prepare the application for deployment, including the configuration of multiple database providers to support SQL servers in production, and PostgreSQL in development. They will also learn how to enable logging within Azure, as well as how to force HTTPS connections to increase the security of the application. Finally, we will enable automated Git deployments to publish the application on every push to a specific Git repository.
Chapter 11, Authentication and Refresh Token Flow, builds on the existing authentication mechanism by adding refresh token support. You will learn how and why this increases the security of the application, as well as how to implement refresh token flow in an ASP.NET Core API. You will then learn how to add a client-side API request interceptor to automatically refresh users' access tokens as and when they expire, allowing them to remain logged in permanently.
Chapter 12, Server-Side Rendering, begins by discussing some of the reasons why you would want to initially render a client-side SPA on the server. It then provides a detailed explanation of how to refactor the application to prepare it for SSR, before showing you how to set up and configure SSR. Finally, it looks at some of the limitations of SSR and how to fix them by conditionally rendering components that are not SSR-compatible, before looking at how to test that everything is working as it should be.
Chapter 13, Continuous Integration and Continuous Deployment, introduces a far more robust way of automating the application build and release pipeline using VSTS rather than the existing Azure Git deployment feature. It discusses the reasons, why you would want to use a CI/CD pipeline, and very briefly why VSTS is the perfect choice when building ASP.NET Core applications hosted within Azure. It walks you through the process of setting up a VSTS account, build and release, as well as enabling triggers to automatically build and deploy the application on every push to the existing Git repository.
It is assumed that you are already a reasonably competent ASP.NET web developer, familiar with building MVC web applications. Although not required, you will appreciate the benefits of Vue.js more if you are also familiar with incorporating a moderate amount of jQuery, or vanilla JavaScript, into your MVC applications. It is also assumed that you are familiar and comfortable with basic CSS and SCSS, with knowledge of the Bootstrap framework being desirable. It is not required to have any pre-existing knowledge of .NET Core or ASP.NET Core, but again, it would be beneficial to have explored ASP.NET Core and how it differs from previous versions of the framework. Finally, it is assumed that you are familiar with source control using Git, and will have access to a cloud-based Git repository to use for deployment in Chapter 10, Deployment, and Chapter 13, Continuous Integration and Continuous Deployment.
All software requirements necessary for completing the sample application are introduced as and when required, including links to instructions on how to install them on your native OS. It is possible to build and run the sample application on any OS supported by ASP.NET Core, including both Windows and macOS. However, the application has only been tested by myself on a Windows machine, as it is assumed that this is what the vast majority of readers will be using, based on the assumption that they are experienced ASP.NET developers.
You can download the example code files for this book from your account at www.packtpub.com. If you purchased this book elsewhere, you can visit www.packtpub.com/support and register to have the files emailed directly to you.
You can download the code files by following these steps:
Log in or register at
www.packtpub.com
.
Select the
SUPPORT
tab.
Click on
Code Downloads & Errata
.
Enter the name of the book in the
Search
box and follow the onscreen instructions.
Once the file is downloaded, please make sure that you unzip or extract the folder using the latest version of:
WinRAR/7-Zip for Windows
Zipeg/iZip/UnRarX for Mac
7-Zip/PeaZip for Linux
The code bundle for the book is also hosted on GitHub at https://github.com/PacktPublishing/Hands-On-ASP.NET-Core-2-and-Vue.js. In case there's an update to the code, it will be updated on the existing GitHub repository.
We also have other code bundles from our rich catalog of books and videos available at https://github.com/PacktPublishing/. Check them out!
There are a number of text conventions used throughout this book.
CodeInText: Indicates code words in text, database table names, folder names, filenames, file extensions, pathnames, dummy URLs, user input, and Twitter handles. Here is an example: "In this case, we return a simple object with a single name property."
A block of code is set as follows:
<style lang="scss">html,body { height: 100vh;}div.app,div.page { height: 100% !important;}</style>
When we wish to draw your attention to a particular part of a code block, the relevant lines or items are set in bold:
vendor: [ "event-source-polyfill", "isomorphic-fetch", "vue", "vue-router",
"bootstrap/dist/css/bootstrap.min.css",
"bootstrap-vue",
"nprogress/nprogress.css"
]
Any command-line input or output is written as follows:
webpack --config webpack.config.vendor.js
Bold: Indicates a new term, an important word, or words that you see onscreen. For example, words in menus or dialog boxes appear in the text like this. Here is an example: "To do so, click on the Resource groups link in the main menu on the left."
Feedback from our readers is always welcome.
General feedback: Email [email protected] and mention the book title in the subject of your message. If you have questions about any aspect of this book, please email us at [email protected].
Errata: Although we have taken every care to ensure the accuracy of our content, mistakes do happen. If you have found a mistake in this book, we would be grateful if you would report this to us. Please visit www.packtpub.com/submit-errata, selecting your book, clicking on the Errata Submission Form link, and entering the details.
Piracy: If you come across any illegal copies of our works in any form on the internet, we would be grateful if you would provide us with the location address or website name. Please contact us at [email protected] with a link to the material.
If you are interested in becoming an author: If there is a topic that you have expertise in and you are interested in either writing or contributing to a book, please visit authors.packtpub.com.
Please leave a review. Once you have read and used this book, why not leave a review on the site that you purchased it from? Potential readers can then see and use your unbiased opinion to make purchase decisions, we at Packt can understand what you think about our products, and our authors can see your feedback on their book. Thank you!
For more information about Packt, please visit packtpub.com.
Many modern web applications are now built as client-rendered Single-Page Applications (SPAs) rather than traditional server-rendered multipage applications. An SPA is a web application that only contains a single physical HTML page. This single page then uses JavaScript within a web browser to dynamically rewrite parts of the HTML, usually based on JSON data that's retrieved from API calls to the server. By doing so, after the initial page load, the application has no need to request full HTML pages from the server, which helps make it as fast and responsive as a native desktop application.
When it comes to building SPAs in 2018, we are absolutely spoiled for choice in frameworks and technologies that we could potentially use to help us build our apps. Regardless of their chosen technology stack, most web developers will probably have extensively used jQuery for their client-side JavaScript needs, and there is no reason why it couldn't be used to build SPAs as well. However, there are far better frameworks that are specifically designed to help us build modern SPAs.
Vue.js is a JavaScript framework for building the view layer of your applications. However, it differs from other large frameworks because it's designed to be incrementally adoptable. That is, with a single CDN script reference, you can plug Vue into a small portion of an existing application in much the same way as you would with jQuery. On the other hand, you could opt to use the modern tooling and supporting libraries in Vue's ecosystem to build a fully-fledged SPA from scratch. Vue really is one of the most simple yet powerful frameworks, with very little compromise in return.
ASP.NET Core is the latest version of Microsoft's ASP.NET web development framework. It has been completely rewritten to be more lightweight and modular, as well as to offer official cross-platform support for the first time. If you are reading this book, it is reasonably safe to assume that you are most likely already an experienced ASP.NET developer, with minimal experience of frontend frameworks and technologies. However, if you already have a basic understanding of Vue.js, then you may be able to skip this chapter, as it will be aimed primarily at those with no experience at all. Regardless of your level of experience with Vue, if you are already familiar with ASP.NET Core, then at the very least you can skip the ASP.NET Core sections near the end of this chapter. That being said, I'll only be focusing on areas where ASP.NET Core differs from previous versions of ASP.NET.
In summary, we'll cover the following topics:
What are components?
How do we compose a UI using components?
Client-side application state
Fundamental Vue concepts such as props, methods, computed properties, and directives
What's new in ASP.NET Core?
What's new in EF Core?
Building web applications using Vue or any other JavaScript SPA framework revolves around the concept of breaking the UI down into the smallest possible chunks of functionality. These chunks are referred to as components, and can be likened to Razor view components, tag helpers, and partial views in ASP.NET Core MVC. However, in most SPAs, you'll end up breaking the UI down into far more pieces than you would in a traditional MVC application.
We can think of components as the building blocks of a UI. Each one is a self-contained piece of functionality, usually combined with a host of other components in a tree-like structure to form the UI of the entire web application. These components are also often reusable, and can be simply dropped into any part of the application where required.
A component in Vue is made up of two fundamental parts: presentation and behavior. The presentation part is simply the HTML template that is used to represent the data we are trying to display in the UI. The behavior part is a JavaScript object containing only the data relevant to that specific component, and any JavaScript functions necessary to manipulate that data and interact with the browser. This interaction includes handling the events raised by the browser, as well as refreshing certain portions of the UI depending on how the data has actually changed. Vue is smart enough to only refresh the parts of the UI that need to be, and doesn't bother refreshing the parts where the data hasn't changed.
In many SPA frameworks, this results in a single component being split into at least two, potentially three, separate physical files; a HTML file for the template; a JavaScript file for the data and behavioral functions; and an optional CSS file for styling the presentation of the component. In Vue, we have the concept of a single file component. We can use a custom file extension that allows us to combine these three aspects into a single file that contains three root elements: template, script, and style. In the following code snippet, we can see an example of a single file component:
<template> <div class="product"> {{ name }} </div></template><script>export default { name: 'product', data () { return { name: 'Hands on ASP.NET Core and Vue.js' } }}</script><style>.product { font-size: 12px; font-weight: bold; color: teal;}</style>
The presentation part of this component, that is, the template and style sections, are incredibly simple. All we do is render a standard div element with a product class, and set the font size, weight, and color of that specific class using CSS. Inside the div element, we're using Vue's standard handlebar syntax to dynamically render a name variable. This variable is declared within the behavior part of the component, which again means the script section. Standard component data properties are declared inside a plain JavaScript object, which must be returned from a function named data. In this case, we return a simple object with a single name property, initialized with the Hands on ASP.NET Core and Vue.js value. This will subsequently be the text rendered inside the div element of template.
Each component should adhere to the SOLID principles of software design, and as such should only have a single responsibility. As soon as any single component starts to become overly complicated and difficult to see at a glance what its purpose is, it's probably time to refactor and extract a new component. Components are more often than not used in parent-child relationships, and Vue provides mechanisms for allowing related components to communicate with one another. Parents can pass data down into their children, and children can notify their parents of changes to their data. These parent-child relationships are the branches of our component tree, and there are many different ways that we could choose to break a UI down into this structure.
Let's look at an example that most web developers will be familiar with. Imagine a web page with the Holy Grail layout—that is Header, Footer, left and right sidebars, and Main Content in the middle. When architecting this layout with components, the obvious composition is to start by creating a component for each major section of this layout:
This is a good start, and in a typical MVC application, we might have done something similar using layout and partial views. However, we already know that a component is the smallest possible chunk of functionality that forms part of the UI. We need to break things down further, and be far more granular with our component boundaries. How we do this will obviously be highly dependent on the type of content we actually have contained within these major page sections. Let's expand on the previous layout with some standard UI features we'd expect in a typical e-commerce product listing page.
The header section would likely contain some kind of branding or Logo, along with a Navigation menu of some sorts and potentially a Search bar. The left sidebar is a common place to find any secondary navigation menus and some Filters to control which products are visible. The main content section will contain our Product List, along with some UI elements above to control the display order and maybe even switch between a grid and list view; there would also usually be a standard Pagination control at the bottom of the page. Finally, the right sidebar can hold a widget that displays a summary of the user's shopping cart contents, a widget to display a set of featured or most popular products, and a newsletter signup form. The following diagram shows how we could start composing this UI into a component tree:
We could—and probably would—still break this down further as we were actually building these components; it's almost impossible to get things right the first time round. However, this is the beauty of component-based architectures. There is no right or wrong way of composing a UI; we simply try it one way, and if it doesn't work, we refactor our component tree until we find a way that does work!
Before we go much further, we really need to understand the basics of Vue, and how we go about using it to define and display our application's data on a web page.
Every Vue application must have at least one root Vue instance, which is created when we pass an options object into the new Vue() constructor. There are a number of properties that we can define on this object, many of which are optional. These properties describe what data the instance has access to, and what kind of actions and manipulations it can do with that data.
If you are only interested in plugging Vue into a handful of pages in a traditional MVC web application, you would define as many root Vue instances as required, attaching each one to a different DOM element. However, when building a full SPA with Vue, you would instead define a single root Vue instance with a nested tree of components underneath it. This single root Vue instance would then be responsible for attaching the entire application to a single DOM element.
We've already discussed what components are at a very high level, but what exactly is a component within the context of a Vue SPA? The answer is simply another Vue instance, albeit this time not a root Vue instance. There are a few subtle differences between a root Vue instance and a non-root Vue instance—most notably that only the root Vue instances define el attributes. This is because nested Vue instances, or components in a component tree, are simply rendered within their parent root Vue instances template. They do not need to be told where to attach themselves.
The other main difference between a root Vue instance and a component Vue instance is that the latter must define their data property as a function rather than an object. We've already seen an example of this when we first looked at the basic structure of a Vue component, but to reiterate, it looked as follows:
<template> <div class="product"> {{ name }} </div></template><script>export default { name: 'product',
data () {
return {
name: 'Hands on ASP.NET Core and Vue.js'
}
}
}</script><style>.product { font-size: 12px; font-weight: bold; color: teal;}</style>
Notice that the data property is a function that returns an object this time. This is because of the fact that every Vue component is a Vue instance. If we use a plain data object rather than a function returning an object, Vue cannot determine which component templates need to be refreshed when that property changes. This is a big issue when we render the same component multiple times when looping over lists of data, and then try and update a single list item's data property.
Now that we've talked about the Vue instance, it's worth talking about reactivity. One of Vue's core concepts is its reactivity system, which is also one of the main differences between building applications with Vue and sticking with jQuery or even plain old JavaScript. With jQuery or plain JavaScript, when a piece of data needs to change, we have to manually ensure that any DOM element which references that data is updated to display its new value. How big a job this is depends entirely on how big the application is, and how well-written it is. However, it's an exceptionally error-prone way of working, regardless of those factors.
In Vue, we bind the DOM to data properties defined in JavaScript, and then when those data properties change, the DOM is automatically updated for us by the reactivity system. The application quite literally becomes reactive to data changes, so it really doesn't matter how big the application is since every DOM element that displays a specific piece of data will automatically refresh when that value changes—no more manual DOM updates!
We've now seen how to define a Vue component, as well as how to declare data properties and render them into the DOM using component templates. However, this is just scratching the surface of what we can do with Vue components. We've already discussed how Vue components have two main aspects to them: presentation and behavior. Let's start to look at what else we can do with the behavior side of a component, starting by expanding on the data function and talking about state.
When talking about the state of an application, what do we actually mean? As soon as we introduce complex client-side logic to a web application, we also introduce multiple meanings of the word state, or rather, we introduce an additional type of state to our application. State can mean different things depending on the type of state we are interested in.
Most backend .NET developers will probably understand state to be based on a snapshot of the applications database at any point in time. In terms of our e-commerce example from earlier, this would include the current list of products and categories that make up our catalog; a list of users or customers who have registered for an account; and a list of orders and associated order items. This form of state is based on the domain of the application, and can be extended to include things that don't necessarily persist into the database, such as authentication, validation, and business rules that control how the application behaves.
The type of state that we care about at the component level is known as UI state. Generally speaking, UI state and domain state are separate things, but it isn't impossible for the two to cross over. For example, keeping track of the current user isn't necessarily a UI concern, but most SPAs will use some form of JWT authentication where the user's tokens, and as such their authentication state, will be tracked by the SPA. Another example is where we display paginated lists of data in an SPA—keeping track of the currently displayed list items is a UI concern, but we are still displaying a subset of the database-persisted items that belong to the domain of the application.
Other examples of UI state include keeping track of the active menu item in a navigation component; controlling the visibility of a modal window or custom drop-down menu; keeping track of which panels are open/closed in an accordion; and showing and hiding loading spinners during AJAX operations. These are fairly simple examples, and there are a lot more complex things that we can do with client-side state such as transitions and animations, but it's enough to demonstrate what we are talking about for now.
Each of our components are only responsible for their own subset of the application UI state. For example, a component that contains the filters that we've applied to a product list is only concerned with the selected values of those filter controls. It isn't—and shouldn't be—concerned with which user is currently logged in, or how many items the user has added to their shopping cart. This is all part of adhering to the single responsibility principle, which makes our components much easier to debug and maintain.
Sooner or later, we're going to come across a situation where a single component is in violation of the SRP, and we want to break that component down into a parent-child relationship instead. A common pattern is where we have a list component as a parent that contains a collection of list-item components as its children. The original component was probably already fetching the data it displays, and it makes sense to leave that responsibility up to the new parent list component; after all, the only alternative is to have each list-item component fetch its own data, which would result in multiple trips to the server instead of just one.
We already know that components are self-contained, so how do the children get access to the data they need to display if the parent owns and controls it? The simple answer to that question is props. Props are a means of parent components passing data down into their children. The child component must explicitly declare the names of the props it expects to receive, and then these props can be referenced in much the same way that we do for any other piece of data that the component owns.
The following code demonstrates how we declare and reference a prop within a child component:
<template> <div class="product"> {{ name }} </div></template><script>export default { name: 'product', props: ['name']}</script>
We can render this child component from within its parent component template as follows:
<template> <div class="product"> <child-component name="Hands on Vue.js and ASP.NET Core" /> </div></template><script>import ChildComponent from './ChildComponent.vue'export default { name: 'parent', components: { ChildComponent }}</script>
At this stage, it is important to understand that this method of sharing data between components is strictly limited to one-way. It is impossible to send data back up the chain from a child to a parent using props. We'll look at how to communicate in the opposite direction later in this chapter.
The final point to mention about props is that Vue provides a means of validating the props being passed to a component. We can perform basic type checking; control whether props are required or optional; configure default values in the event that a prop is not provided; and even write custom validator functions in much the same way as we would with client-side validation libraries. The following code snippet shows an example of some of these validation rules and how we describe them in the component definition:
<script>export default { name: 'validation', props: { name: { type: String, required: true }, description: { type: String, required: true }, price: { type: Number, required: true } }}</script>
If the data we are displaying within our components never changes, it's probably a sign that we really don't need to be using an SPA framework such as Vue. We know that the data in a component is used for things such as showing and hiding modal windows, so how do we actually change the data so that the UI can become reactive? Vue components can declare methods in order to manipulate their data. These methods are standard JavaScript functions, and automatically have their function context (that is, the value of this) bound to the component instance so that they can access its data, props, and computed properties. The following code shows how we can increment a simple counter using a method on a Vue component. We can trigger this method by calling it from a UI element event handler, which we'll look at later in this chapter:
<script>export default { name: 'methods', data () { return { counter: 1 } }, methods: { increment () { this.counter++ } }}</script>
