
Explore building a real-world application with Angular 2 on the client and ASP.NET Core on the server, through a 60-day team-based coding challenge.
Build a real-world app with ASP.NET Core and Angular 2, focusing on CRUD forms, backend APIs, authentication and authorization, cascading dropdowns, filtering, paging, and progress-bar uploads.
Identify prerequisites: three months of Angular 2, ASP.NET MVC 5, and Entity Framework 6 experience; cover Angular components, services, routing, controllers, actions, HTTP verbs, and EF code first.
Design a real-world vehicle dealer app using ASP.NET Core and Angular 2, modeling vehicles with features via a many-to-many relationship, including registration status, owner contact, and photos.
Install dotnet core sdk and vs code, add essential extensions for C# and Angular, and use Yeoman with generator asp.net core spa to scaffold across Windows, Linux, or Mac.
Learn to run SQL Server on macOS or Linux with a Docker image, including pulling, memory config, SA password, port 1433, and connecting with SQL Pro or Linux tools.
Create a new project using Yeoman with the ASP.NET Core SPA template and Angular, then run dotnet run to launch the app at localhost:5000.
Explore the ASP.NET Core and Angular 2 project structure, including the client app folder, dist assets, dub dub dub root public assets, and webpack configuration for bundling.
Explore how ASP.NET Core hosts apps with Kestrel, configures services via dependency injection, and builds a middleware pipeline including MVC and static files for development and production.
Explore ASP.NET Core environments, development, staging, and production, and leverage webpack dev middleware with hot module replacement to auto update client-side changes.
Add dotnet watch to your project to automatically recompile server-side code on changes and restart the server, with brief downtime while it reloads.
Master VS Code debugging for a real-world ASP.NET Core and Angular app by using breakpoints, watches, and the debug panel, with keyboard shortcuts like F5, F9, and stepping actions.
Learn to use the git panel in VS Code to initialize a repository, view diffs, and make the initial commit, with optional terminal commands like git add and git commit.
Learn a systematic, dependency-driven approach to software development from requirements to use cases; implement in order—create vehicles, list them, then filter—with server APIs and a code-first database.
Build an API for vehicle form data with ASP.NET Core, using Entity Framework Core Code First migrations, seeding reference data, and Automapper mapping, within a practical architectural overview.
Compare implementation options for populating makes and models in a real-world ASP.NET Core and Angular app, weighing separate endpoints versus a single endpoint and client-side data loading for small datasets.
Build a simple domain model with make and model classes, each with id and name, and a models collection with a make id foreign key; initialize in the constructor.
Install entity framework core from NuGet using dotnet CLI, restore packages, and install entity framework command line tools; finally, create a dbcontext and add migrations.
Create and configure a DbContext with EF Core, register it via AddDbContext in startup's configure services for dependency injection, and connect to SQL Server using a configured connection string.
Explore how to use the new configuration system in ASP.NET Core by configuring appsettings.json, environment-specific files, and environment variables, and accessing keys with the configuration builder.
Create and evolve a database with code-first migrations in entity framework core. Configure the db context and apply migrations to SQL Server via dotnet CLI or Visual Studio.
Apply constraints to the model by making the name column not nullable with 255 characters using data annotations, rename the table to models, and manage migrations with dotnet f migrations.
Seed the database across environments using code-first migrations, inserting makes and models with sql in an empty migration and enforcing up and down methods for consistency.
Create a makes API by deriving a controller from the base controller, expose HTTP GET at /api/makes, and return an async list of makes with their models using EF Core's Include.
Diagnose common runtime errors in a real-world ASP.NET Core and Angular app, including missing node modules, webpack bundle creation, and database update needs.
Explore how to expose the public interface by mapping domain models to resources at the application boundary, avoiding serialization of internal details and preventing json loops.
learn to map domain models to API resources using Automapper, configure dependency injection, and create mapping profiles with CreateMap to return makes and models.
Connect your vehicle form to the APIs we created in the last section, implement cascading dropdowns and dynamic checkboxes, and discover rapid code generation with Angular CLI and Zen coding.
Create a new Angular component in the client app using Angular CLI, register it in the app module, and configure a route for the component.
Register a new route at vehicles/new using the vehicle form component, update the navigation with a new vehicle link and dash plus icon, and preview a bootstrap form.
Build a bootstrap form using form-group, label, select, and form-control classes, generate markup with zen coding, and connect an Angular client to API-driven cascading dropdowns and dynamic checkboxes.
Create an Angular CLI generated service to consume APIs, inject the Http service, implement a get makes method, map the response to json, and register the provider in app module.
Populate the make dropdown from an observable service in ng on init, then cascade to the models dropdown using ngfor, with debugging steps to handle asynchronous data and UI updates.
Implement cascading dropdowns in Angular by binding the make with ngModel and deriving models from the selected make, handling edge cases and backend calls for large data and dynamic checkboxes.
Display a dynamic features section by fetching features from the database via a feature service, then render a list of checkboxes in the form.
Merge two fine-grained services into one vehicle service with get makes and get features methods to reduce dependencies and simplify unit testing.
Weigh the pros and cons of merging two controllers into a single vehicles controller, considering api contracts, client-server consistency, and maintainability.
Add radio buttons for the vehicle registered status in a form using Bootstrap markup, including labels, ids, and a shared name to group yes and no options, with inline styling.
Learn how to add text boxes to a form to collect contact information, namely name, phone, and email, with proper labels and a submit button using btn and btn-primary classes.
Extend the domain model to introduce a many-to-many relationship, build a CRUD API for vehicles, and explore why two separate API resources arise from domain classes.
Revisit the domain model to add a vehicle class with a many-to-many relation to features, remove vehicle make/model links, infer make from model, and implement a one-to-many model-to-vehicle relation.
Extend the model by adding a vehicle with id and modelId, isRegistered and lastUpdate, and store owner contact as properties name, phone and email, because EF Core lacks complex types.
Implement many-to-many relationships in entity framework core by adding a mapping class, composite keys with fluent API, and proper migrations to connect vehicles and features.
Builds a post endpoint under API/vehicles to create new objects, returning the input as JSON via IActionResult, and testing the endpoint without a database.
Learn how to test a vehicle creation API with postman, bound by API resources that use feature IDs and server-side last update to prevent overposting.
Create a new vehicle resource in the resources folder, add a separate contact resource with email and phone, replace features with integer IDs, and implement mapping from the vehicle class.
Create a map from vehicle resource to the vehicle domain class using a mapping profile, mapping contact name, email, phone, and features to vehicle feature objects with AutoMapper.
Inject the DbContext into the controller, add a Vehicles DbSet, and persist new Vehicle objects with async SaveChanges, then map to a Vehicle resource for the application programming interface output.
Perform server-side validation in asp.net core by validating model state and returning 400 with model state errors, using data annotations for input validation and fluent api for complex domain rules.
Learn to build a put API to update vehicles, load the vehicle from the database, map resources with Automapper while ignoring the key, and address feature collection updates.
Map collections by syncing vehicle features from resource to object: load with include, remove unselected features, add new ones with IDs, and use after-map logic to avoid duplicates.
Refactor vehicle feature handling with Linq, using select and where to filter and project features, simplify add/remove logic, and prepare for unit testing and the API to delete vehicle objects.
Implement a delete vehicle api using http delete with id route, fetch vehicle, remove it, save changes, and return 200 with the deleted id; handle not found for invalid ids.
Build an api endpoint to get a vehicle by id with http get, map it to a vehicle resource, and eagerly load features for the response.
Explore separating api resources into create/update and read representations, using nested model and feature objects to prevent over posting and contract breakage, while tailoring inputs for each action.
Refactor the API to separate resources for vehicle, model, feature, and contact, and map vehicle to vehicle resource with eager loading of related data using EF Core.
Refactor a real-world ASP.NET Core and Angular app by replacing multiple identical resources with a single key value pair resource (ID and name), updating models, mapping profile, and API endpoints.
Change the API return type to a vehicle resource by loading related data (model, make, features) before mapping, using explicit include or a hydration snippet, and refactor to reduce duplication.
Learn how to encapsulate queries with the repository pattern by building a simple vehicle repository in the persistence layer, using a DbContext, the include method, and an async get vehicle.
Decouple the controller from data access by extracting a repository interface, wiring it with scoped dependency injection in ASP.NET Core, and refactoring actions to use the repository.
Decouple the controller from entity framework by replacing db context with a vehicle repository, centralizing data access and easing framework changes through a repository pattern.
Explore why repositories should not include save methods, and implement a unit of work to coordinate multiple repositories, enabling decoupled, testable data access with dependency injection.
Fixes bugs in the vehicle api by correcting include related logic, ensuring related properties are populated for AutoMapper mappings, and preventing null reference errors.
Debunks the false argument of repository over a repository by advocating decoupling through an i repository interface and a single class that encapsulates queries, enabling future replacement via configure services.
Challenge the second false argument by showing replacing the dbcontext with a repository does not add complexity, and that an extra class can encapsulate related fat queries.
The third false argument debates repository use in simple and complex apps. The speaker shows how repositories remove duplicated queries, wrap fat queries, and keep controllers slim and testable.
Explain why repositories are not inherently coupled to entity framework; program to interfaces as contracts, with coupling to entity framework limited to implementations via dependency injection.
Reject the persistence model idea and keep domain classes as plain POCOs mapped to database tables, avoiding unnecessary API resource mappings.
Apply the dependency inversion principle by binding high level modules to abstractions, not concrete repositories; implement interfaces in core and keep persistence implementations interchangeable to reduce change impact.
Clarifies that layers (presentation, business logic, data access) are conceptual, not folders or projects; emphasizes that clean decoupled architecture depends on dependency direction and abstractions, not folder structure.
Connect your form to the API to create, update, and delete vehicles, populate forms with server data, and enable client-side validation, toast notifications, and global error logging.
Bind form inputs to the vehicle object using ngModel, rename make to makeID and model to modelID, and set name attributes. Debug by rendering JSON; server uses model ID only.
Bind dynamic feature checkboxes by managing a features array. Implement onFeatureToggle to push or splice feature IDs based on checkbox state, ensuring features are initialized as an empty array.
Bind textboxes to the vehicle's contact properties with ngModel, initialize the contact property to an empty object, and ensure name, phone, and email fields can be sent to the server.
Apply the submit directive to the form, bind it to the component's submit method, post the vehicle to /api/vehicles via the service, then subscribe and log the response.
Implement client-side validation in a template-driven Angular form using HTML5 required attributes, Bootstrap alerts, and a template variable to access control state, and disable submit until the form is valid.
Demonstrate robust error handling in an ASP.NET Core and Angular app by showing toast notifications via the toastie service for unexpected failures and server-side validation errors via 400 bad request.
Develop a central global error handler by extending Angular's error handler, configure Angular to use app error handler, and display errors via toast notifications with the toasty service.
Explore how angular uses zones to ensure change detection by running code inside NgZone, leveraging zone.js to patch async operations like setTimeout and events, and fix the toasty notifications.
Log errors to the cloud with sentry.io, capture exceptions in your app with raven-js, and view detailed dashboards showing occurrences, stack traces, browser data, and breadcrumbs for reproducing this error.
Use isDevMode to detect development versus production and log exceptions with Raven in production, while Angular runs prod mode and webpack dev middleware manages development.
Implement editing of vehicles by routing to a vehicle edit page using id from activated route parameters, fetch the vehicle via the service, and handle 404 by returning to home.
Learn how to populate a complex vehicle form by sending parallel requests with observables and RxJS forkJoin in Angular, including makes, models, features, and vehicle data.
Map the server vehicle object to a save vehicle resource using a private set vehicle method, and define interfaces for vehicle, model, make, and features to enable IntelliSense.
Develops a private populateModels method to fill the vehicle model dropdown from the selected make, initializes the form via ngOnInit, and binds radio buttons and checkboxes with Angular bindings.
Implement the update flow by adding a vehicle service update method that sends an http put to api/vehicles/{id} and shows a success toast after saving changes.
add a delete button, prevent form submission by using type button, and bind a delete method that confirms before calling the vehicle service to delete the vehicle.
Enhance your list with filtering, sorting, and pagination, and explore refactoring techniques and plugins for rendering tables with built-in filtering, sorting, and pagination.
Review the vehicles list feature in a real-world ASP.NET Core and Angular 2 app, including the vehicles table, edit navigation, a client-side list component, routing, and nav highlights.
Add a reusable filter pattern by binding a dropdown to a filter object with ngModel, implementing onFilterChange without parameters, and supporting multiple filters for client- or server-side filtering.
Implement client-side filtering by loading all vehicles into a separate all vehicles list and applying single or multiple filters, with a reset button to clear filters.
Implement server-side filtering by adding a filter domain and filter resource, mapping them, and building a dynamic query to return vehicles by make id, with client-side query string filters.
Learn how to pass filters to the server as query string parameters, build a reusable query string helper, and enable server-side filtering with make and model IDs.
Learn to implement server-side sorting for vehicles using a query object, adding sort by and sort ascending, renaming filters to vehicle query, and applying order by with ascending or descending.
Refactor by mapping column names to lambda expressions using a dictionary, creating an expression tree that translates to SQL at runtime and makes adding columns reusable.
Refactor a fat method by extracting the ordering logic into private apply ordering method accepting a dictionary of column mappings and a queryable of vehicle, improving readability and enabling reuse.
Transform a vehicle-specific method into a reusable IQueryable extension using generics and an IQueryObject interface. Enable flexible sorting through a query object and column map while handling edge cases.
Click table headers to sort the real-world app data by a chosen column, toggling between ascending and descending orders via a query-based sort filter before refreshing the server data.
Install and use font awesome icons, configure webpack, and render dynamic sort icons for a vehicle list, with ascending and descending states and a quick toggle bug fix.
Learn to render table columns dynamically in an Angular four app, defining a sortable columns array and conditional templates for server-side sorting and paging.
Implement server-side paging by adding page and page size to the vehicle query, apply a reusable paging extension, and ensure paging runs in SQL Server rather than in memory.
Implement a client-side pagination component in an Angular app to navigate vehicle data, using input properties for page size and total items and an output event for page changes.
Define a generic query result with total items and items, expose it via a generic API resource, and update server and client to paginate using the total count.
Fix an edge case in pagination by resetting the page number and page size when filters change, preventing undefined values, and refactoring methods for explicit filter resets and data population.
Learn to add a photo upload feature by building a file upload API, passing file data with Angular, and displaying a Bootstrap progress bar during uploads.
Create a view vehicle page with two bootstrap tabs for vehicle and photos, render vehicle attributes as plain text, leave the photos tab empty, and redirect after create or update.
Demonstrate building a real-world vehicle details page in Angular with view, edit, and delete flows, route-based parameter handling, and a consolidated create/update submission workflow.
Extend the domain model with a photo entity, add a photos collection to vehicles, initialize the collections, create and apply a photos migration, and implement the API.
Create a photos API in ASP.NET Core to upload vehicle photos, store files in uploads, generate secure file names, and persist changes via a repository and unit of work.
Test the API with Postman by posting to http://localhost:5000/apis/vehicles using a valid vehicle ID and a form-data file named file, then review the 200 response, uploads folder, and edge cases.
Validate file uploads by checking null or empty inputs, enforce a 10 megabyte max size, and allow only jpg, jpeg, and png images, returning bad requests for violations.
Refactor photo upload by moving settings to a photo settings section in app settings, using IOptionsSnapshot for max bytes and accepted file types, and encapsulating the support logic.
Develop the client side by wiring a file input to upload a photo using a view child template variable, a photo service, and a post to API/vehicles/{id}/photos with form data.
Render vehicle photos efficiently by loading basic vehicle data first and photos on demand via a dedicated get-photos endpoint, then display and update uploads with a progress bar.
Track upload and download progress in an Angular app with a custom browser xhr, a progress service, and RxJS subject, enabling a future on-page progress bar.
Add a bootstrap progress bar to the upload view and bind its width to the upload progress percentage with Angular style binding, ensuring zone.run updates trigger change detection.
Fix memory leaks in the upload progress by creating a new subject per file, avoiding multiple subscriptions, and automatically unsubscribing on completion.
Display toast notifications for errors and show specific messages, like invalid file type, while handling uploads by clearing inputs and improving user feedback.
Learn to implement authentication and authorization on both client and server using json web tokens and Auth0 to protect api endpoints, secure angular routes, and manage access with user roles.
Protect server APIs with authenticated users in specific roles, and guard client routes by showing or hiding content based on authentication and roles.
Compare authentication architectures for traditional ASP.NET MVC and ASP.NET Core with Angular, from cookies and authentication tickets to JWT tokens with claims, signing, and header-based authentication, plus Auth0 delegation.
Create an Auth0 account, configure a subdomain, enable the API section, and add a new API using RS 256 for secure signing, with a logical identifier and Quickstart steps.
Secure your ASP.NET Core APIs by configuring JWT bearer authentication in startup, specifying authority and audience, and applying authorization to protected actions such as get features.
Inspect a JSON web token using jwt.io's debugger to view its header, payload, and signature, and explore the token structure through the decoder tab.
Learn how to add Auth0 authentication to single page web apps using Angular 2, configure rs256, install auth0-lock and angular2-jwt, and build an authentication service with login and logout.
Add login and logout links to the navigation bar and disable server side pre-rendering. Configure Auth0 allowed origins and callback URLs for localhost:5000 to enable login.
Learn to use hosted login pages to replace the login widget, customize the page’s language, theme, logo, and colors, and securely obtain a token by redirecting back to the app.
Set the audience in the auth flow to issue a valid access token for your API, and learn how OpenID Connect, ID tokens, and local storage enable secure API calls.
Set a timer and take a five-minute walk every 45 minutes to boost focus and productivity, prevent injuries, grab fresh air, and resume the session.
Learn to get the user info after login, store a stringified profile in local storage, handle errors, and reload it on startup.
Add additional signup fields to the sign up form on hosted page, use camel notation for json keys, and display the user name from metadata in the profile via scope.
Use rules as JavaScript functions that run on login to enrich profiles, set names from metadata, assign roles, and modify access tokens while exploring templates.
Explore three ways to assign roles: dashboard, a rule-based approach, and the Auth0 management API; cover user vs app metadata and returning custom claims in the json web token.
Learn to add custom role claims to the access token by namespacing with https://vigor.com/roles, guard against undefined user metadata, and prepare to consume roles on the client to control the UI.
Decode the access token with a JWT helper to extract roles and conditionally render the admin route and navigation link, while highlighting that only the private key signs the token.
Refactor duplicated code in a real-world app by aligning token handling and local storage reads, extracting methods for roles and user data, and centralizing authentication.
Protect routes by implementing an auth guard and an admin guard that check user authentication and role before accessing the admin route, redirecting unauthenticated users to the login page.
Add the Json web token to authorization headers using the angular2/jwt auth http wrapper, update vehicle APIs, register the provider, and address robust progress handling while showing role-based access control.
restrict api endpoints by role using authorization policies in startup, including a require admin role claim from vigo.com/roles, applying to create vehicle, and centralizing policy names in app policies.
Implement authorization across the app by injecting an auth service, conditionally rendering buttons and inputs for authenticated users, and protecting routes in Angular to ensure read-only access for anonymous users.
Install chart.js and angular2-chart.js, configure webpack, import the chart module, and render a pie chart on the admin page by binding a hardcoded data object with labels and datasets.
Improve vehicle list performance by refactoring filtering into a vehicle-specific apply filtering extension, aligning abstraction levels with apply ordering and apply paging, and removing unnecessary eager loading of features.
Fix the bug in the auth workflow by guarding the roles field, decoding the JWT from local storage, and defaulting missing roles to an empty array.
Refactor a large photos upload action into a dedicated iPhoto service to implement an application service layer, separating concerns for file storage and database updates while keeping the controller lightweight.
Implement a pluggable photo storage using the iPhotoStorage interface, with a file system photo storage for development and cloud storage (Azure or Amazon) for production, wired through startup dependency injection.
Learn how to move sensitive data out of source code using dotnet user secrets and the secret manager, and configure startup to load secrets and override with environment variables.
[UPDATE, June 19]: Added a new section to the course.
With over 3,000 students and 300+ positive reviews, this course is Udemy's most popular course for learning ASP.NET Core in the context of a real project!
ASP.NET Core is the next generation of ASP.NET MVC. It's a complete re-write of this framework but in a modular, cloud-optimized and cross-platform way. So it can run on Windows, Linux and Mac. If you're on Mac or Linux and want to build ASP.NET applications without running Windows in a virtual machine, you're going to love ASP.NET Core! You can use Visual Studio Code (VSCode) or your favorite code editor to build ASP.NET Core applications with C#. Say goodbye to VMWare, Parallels, and other virtualization software.
Many companies have already started building their new applications with ASP.NET Core. And they're asking their new interviewees if they are familiar with .NET Core. So, whether you want to stay in the marketplace and get a better job with better pay, or you just love to work with the latest technology, it's time to learn about ASP.NET Core and Entity Framework Core.
In this course, Mosh, author of several highly rated courses on Udemy, teaches you how to build a real-world application with ASP.NET Core, Entity Framework Core and Angular. If you're familiar with ASP.NET MVC 5 and Entity Framework 6 and are looking for a course to quickly get up to speed with .NET core, this is the course for you. Not only will you learn about the changes and the new tooling in ASP.NET Core, you'll also learn how to properly integrate it with Angular to build real-world single page applications (SPAs).
A REAL-WORLD APP
The app you build in this course is for an imaginary vehicle dealer. The features in this app are carefully designed by Mosh to help you master the core skills you need to build real-world apps with ASP.NET Core and Angular.
By the end of watching this course, you'll be able to:
Build APIs with ASP.NET Core
Test APIs with PostMan
Integrate Angular and ASP.NET Core
Implement a clean and decoupled architecture
Understand and apply the Dependency Inversion Principle (DIP)
Properly implement the repository and unit of work patterns
Use the new dependency injection feature in ASP.NET Core
Troubleshoot common runtime errors
Store and retrieve data with Entity Framework Core (code-first workflow)
Use AutoMapper
Implement CRUD operations (including one-to-many and many-to-many relationships)
Implement filtering, sorting and paging data
Handle and logging errors
Display toast notifications
Implement cascading drop-down lists
Implement photo upload with progress bars
Add authentication and authorization with Auth0 (including roles with different privileges)
Display charts
And more...
On top of all these, you'll learn how to write quality code, not just how to build apps. There are a lot of developers out there who can build apps but they write poor quality code. Mosh shows you how to refactor bad code into clean, maintainable and quality code. He also shares his knowledge and 15 years of experience about software design and architecture. So this course is more than just technology. It teaches you how to think like a software engineer.
These are the essential skills that you take with you to nearly every real-world project. Whether you want to get prepared for a job interview or simply want to take your coding skills to the next level, this course is the means to the destination.
TOOLING
There are two ways to build ASP.NET Core applications. You can use Visual Studio 2017 or Visual Studio Code, a light-weight cross-platform code editor. In this course, Mosh uses VSCode and the command-line to build an app, but what you learn can be applied in Visual Studio 2017 as well.
WHO THIS COURSE IS FOR
In order to take this course, you should have at least 3 months experience with ASP.NET MVC 5, Entity Framework 6 and Angular 2 (or higher).
If you need to strengthen your understanding of these frameworks, you can watch Mosh's related courses prior to or in parallel with this course:
Angular 2 with TypeScript for Beginners
The Complete ASP.NET MVC 5 Course
Entity Framework 6 in Depth
60 DAY CHALLENGE PROGRAM
Depending on your level of experience, there are different ways to take this course. You can watch it, section by section, just like other courses. You may prefer to code along with the videos or watch a section first and then code.
But if you like to get out of your comfort zone and take your coding skills to the next level, you should take advantage of the 60 day challenge program that comes with this course.
Imagine you and Mosh are team mates and are working on a real-world project. Every week Mosh gives you a challenge or a task to complete. You have one week to complete this task. The following week he publishes a new section and shows you how he completes that task himself. This is a fantastic learning opportunity for you. You can compare your code with his and find areas for improvement.
WHAT THIS COURSE IS NOT
While you use ASP.NET Core and Entity Framework to build an app, the focus of this course is on application building skills and not a deep overview of ASP.NET Core and Entity Framework. Because in any real-world applications, you use only a subset of the features in any frameworks. So, it's impossible to cover everything about ASP.NET Core and Entity Framework in one app. But you'll learn about the key things that you need to know in order to get the job done.
Also, the following topics are outside the scope of this course:
Complex domains and domain-driven design (DDD)
Design patterns
Continuous integration and deployment
Automated testing
Finally, the application you'll build in this course has a very simple user interface since the focus of this course is on coding not building visually engaging user interfaces.
TAKE YOUR CODING SKILLS TO THE NEXT LEVEL
So, do you want to transition from ASP.NET MVC 5 and learn about the latest stuff happening in .NET Core? Do you want to learn how to build a real-world application with ASP.NET Core and Angular? Then take this course and get started.
This course comes with a 30-day money back guarantee. If you're not satisfied, you can contact Udemy for a full refund. No questions asked.
Join the other 3,000 happy students who have taken this course and start building this app in under 10 minutes!