29,99 €
Building production-ready enterprise applications can be a challenging task due to the overabundance of tools and their different versions that make app development complex. This book simplifies the process with an end-to-end road map for building enterprise applications from scratch using the latest features of .NET Core 6 and C# 10.
Throughout the book, you'll work on creating an enterprise app, adding a key component to the app with each chapter, before ?nally getting it ready for testing and deployment. You'll learn concepts relating to advanced data structures, the Entity Framework Core, parallel programming, and dependency injection. As you progress, you'll cover various authentication and authorization schemes provided by .NET Core to make your apps and APIs secure. The book then shows you how the latest Microsoft Visual Studio and C# 10 help you simplify developer tasks and shares tips and tricks in Visual Studio to improve your productivity. You'll discover various testing techniques, such as unit testing and performance testing, as well as di?erent methods to deploy enterprise apps.
By the end of this book, you’ll be able to create enterprise apps using the powerful features of .NET 6 and deploy them to the cloud while working with various cloud components using Azure.
Das E-Book können Sie in Legimi-Apps oder einer beliebigen App lesen, die das folgende Format unterstützen:
Seitenzahl: 549
Veröffentlichungsjahr: 2022
Become a professional .NET developer by learning expert techniques for building scalable applications
BIRMINGHAM—MUMBAI
Copyright © 2022 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 authors, 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.
Group Product Manager: Richa Tripathi
Publishing Product Manager: Kunal Sawant
Senior Editor: Ruvika Rao
Technical Editor: Pradeep Sahu
Copy Editor: Safis Editing
Project Coordinator: Deeksha Thakkar
Proofreader: Safis Editing
Indexer: Manju Arasan
Production Designer: Sinhayna Bais
Marketing Coordinator: Sonakshi Bubbar
Business Development Executive: Kriti Sharma
First published: March 2021
Second edition: June 2022
Production reference: 1310522
Published by Packt Publishing Ltd.
Livery Place
35 Livery Street
Birmingham
B3 2PB, UK.
ISBN 978-1-80323-297-3
www.packt.com
To my wife, Srividya, and my son, Vaarush, for their love and support.
– Ravindra Akella
To my family for their love and support.
– Arun Kumar Tamirisa
To my parents, Rajaiah and Mahalakshmi, for their love, endless support, and encouragement.
– Suneel Kumar Kunani
To my parents, Mrs. Geetha Rani and Mr. Muthiyalu, for inspiration. To my wife, Aparna, and my children, Tarak and Yashvak, for their continued support and love. To my sister, Janani, for encouragement throughout the long process of writing this book.
– Bhupesh Guptha Muthiyalu
Ravindra Akella works as a senior software engineer at Microsoft and has more than 15 years of software development experience, specializing in .NET and web-related technologies. He has led software architecture, design, development, and delivery of large complex solutions using the Azure cloud and related technologies. He is a tech-savvy developer who is passionate about embracing new technologies.
I want to thank the people who have been close to me and supported me, especially my wife, Srividya, and my parents. Also, thanks to the editors and the team at Packt for their help and support throughout the process.
Arun Kumar Tamirisa is a senior consultant currently working at Microsoft with over 16 years' experience in IT, designing and developing highly scalable and reliable, large, and complex applications using the Microsoft .NET and Azure technology stack. He has extensive experience working with both client-side and server-side technologies and is passionate about learning and solving complex problems.
I want to express my gratitude to my family members for their unconditional love and support. My sincere thanks to the Packt team for their continuous support throughout the journey of writing this book.
Suneel Kumar Kunani is a passionate developer who strives to learn something new every day. With over 16 years of experience in .NET and Microsoft technologies, he works on architecting and building mission-critical, highly scalable, and secure solutions at Microsoft. He loves to teach and evangelize about the best practices in building distributed cloud solutions.
I would like to first and foremost thank my family for their support, patience, and encouragement throughout the long process of writing this book. I would like to extend my thanks to the Packt team, the co-authors, and the technical reviewers who made the journey of writing this book so pleasant. I am thankful to my managers and colleagues who supported and encouraged me in writing this book.
Bhupesh Guptha Muthiyalu is a Microsoft Certified Professional and works at the company as a software engineering manager. He has over 17 years of software development experience on the .NET technology stack. His current role involves designing systems that are resilient to the iterations and changes required by businesses, validating architectural innovations, delivering solutions with high quality, managing the end-to-end ownership of products, and building diverse teams with the capabilities to fulfill customer objectives. He is passionate about creating reusable components and identifying opportunities to make a product better.
I would like to first and foremost thank my family for their support, patience, and encouragement throughout the long process of writing this book. I would like to extend my thanks to the Packt team, the co-authors, and the technical reviewers for the great partnership and collaboration. I am thankful to my managers and peers who supported and inspired me to write this book.
Vibhu Banga is currently a portfolio architect for a healthcare company in Hyderabad, India. His previous job for more than 10 years was as a developer/architect for Microsoft where he had delivered projects for customers on the Microsoft tech stack. He has been an active member in the open source dotnet community. He is a Microsoft Certified Azure Architect and DevOps Expert. Vibhu has contributed to open source projects related to building ERP solutions for retailers, brands, and the automobile industry under the free Apache license, all of which were developed in .NET 6.0.
I am deeply indebted to my friend, Ravindra, who was confident that I could take on this heavy job of being a technical reviewer, as this is my first book. I am also thankful to my parents and my loving wife for providing me all the support I need and tolerating my busy schedule and still standing by my side. I had no time to take my wife out for vacations or celebrations, but she still supported me and has always been the strongest pillar for me.
.NET 6 is an open source, free, and full stack framework to write applications targeting any platform. The framework offers you the opportunity to write applications with ease, including for the cloud. As software developers, we are entrusted with the responsibility of building complex enterprise applications. In this book, we will learn about various advanced architectures and concepts for building enterprise applications using C# 10 and .NET 6.
This book can be used as a reference while building an enterprise application using .NET 6. Complete with step-by-step explanations of essential concepts, practical examples, and self-assessment questions, you will get in-depth coverage of and exposure to every important component of .NET 6 required to build a professional enterprise application.
This book is for intermediate to expert-level developers who are already familiar with .NET classic or .NET Core and C#.
Chapter 1, Designing and Architecting the Enterprise Application, first discusses commonly-used enterprise architectures and design patterns, and then covers designing and architecting an enterprise application into a three-tier application consisting of a UI layer, service layer, and database.
Chapter 2, Introducing .NET 6 Core and Standard, talks about the new features in C# 10, which was released with .NET 6.
Chapter 3, Introducing C# 10, starts from our awareness that runtime is where your code runs. In this chapter, you will learn about the core and advanced concepts of .NET 6 runtime components.
Chapter 4, Threading and Asynchronous Operations, helps you learn about threads, thread pools, tasks, and async/await in detail and how .NET allows you to build asynchronous applications.
Chapter 5, Dependency Injection in .NET 6, helps us to understand what dependency injection is and why every developer is flocking toward it. We will learn how dependency injection works in .NET 6 and list the other options that are available.
Chapter 6, Configuration in .NET 6, teaches you how to configure .NET 6 and use the configuration and settings in your applications. You will also learn about extending the .NET 6 configuration to define your own sections, handlers, providers, and so on.
Chapter 7, Logging in .NET 6, discusses the events and logging APIs in .NET 6. We will also take a deep dive into logging using Azure and Azure components and learn how to do structured logging.
Chapter 8, All You Need to Know about Caching, discusses the caching components available in .NET 6 and the best industry patterns and practices.
Chapter 9, Working with Data in .NET 6, discusses two possible data providers: SQL and databases such as RDBMS. We will also discuss at a high level how NoSQL databases can be used for storage and data handling using .NET 6. This chapter will discuss .NET Core's interface with files, folders, drives, databases, and memory.
Chapter 10, Creating an ASP.NET Core 6 Web API, develops the service layer of our enterprise application by using an ASP.NET 6 Web API template.
Chapter 11, Creating an ASP.NET Core 6 Web Application, develops the web layer of our enterprise application by using an ASP.NET 6 MVC web application template and Blazor.
Chapter 12, Understanding Authentication, discusses the most common authentication patterns in the industry and how you could implement them using .NET 6. We will also cover implementing custom authentication.
Chapter 13, ImplementingAuthorization in .NET 6, discusses the different methods of authorization and how ASP.NET 6 lets you handle it.
Chapter 14, Health and Diagnostics, discusses the importance of monitoring the health of an application, building a HealthCheck API for .NET apps, and Azure applications for capturing the telemetry and diagnosing the problem.
Chapter 15, Testing, discusses the importance of testing. Testing is an essential part of development, and no application can be shipped without proper testing, so we will also discuss how we can unit test our code. We will also learn how to measure the performance of an application.
Chapter 16, Deploying the Application in Azure, discusses the deployment of applications in Azure. We will check-in our code to the source control of our choice, and then the CI/CD pipeline will kick in and deploy the application in Azure.
You need to have the .NET 6 SDK installed on your system; all the code samples have been tested using Visual Studio 2022/Visual Studio Code on the Windows OS. It is recommended to have an active Azure subscription to further deploy the enterprise application. A free account can be created at https://azure.microsoft.com/en-in/free/.
If you are using the digital version of this book, we advise you to type the code yourself or access the code from the book's GitHub repository (a link is available in the next section). Doing so will help you avoid any potential errors related to the copying and pasting of code.
You can download the example code files for this book from GitHub at https://github.com/PacktPublishing/Enterprise-Application-Development-with-C-10-and-.NET-6-Second-Edition. If there's an update to the code, it will be updated in the 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!
We also provide a PDF file that has color images of the screenshots and diagrams used in this book. You can download it here: https://static.packt-cdn.com/downloads/9781803232973_ColorImages.pdf.
There are a number of text conventions used throughout this book.
Code in text: 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: "WriteMinimalPlainText will just emit the overall status of the health check services."
A block of code is set as follows:
app.UseEndpoints(endpoints =>{ endpoints.MapControllerRoute( name: "default", pattern: "{controller=Products}/{action=Index}/{id?}");When we wish to draw your attention to a particular part of a code block, the relevant lines or items are set in bold:
app.UseEndpoints(endpoints =>{ "{controller=Products}/{action=Index}/{id?}");endpoints.MapHealthChecks("/health");});Any command-line input or output is written as follows:
dotnet new classlib -o MyLibrary
Bold: Indicates a new term, an important word, or words that you see onscreen. For instance, words in menus or dialog boxes appear in bold. Here is an example: "Let's add a custom event tracking when the user clicks on the Add to Cart button on the Product Details page."
Tips or Important Notes
Appear like this.
Feedback from our readers is always welcome.
General feedback: If you have questions about any aspect of this book, email us at [email protected] and mention the book title in the subject of your message.
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/support/errata and fill in the form.
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.
Once you've read Enterprise Application Development with C# 10 and .NET 6, we'd love to hear your thoughts! Please click here to go straight to the Amazon review page for this book and share your feedback.
Your review is important to us and the tech community and will help us make sure we're delivering excellent quality content.
In this part, we will learn about the advanced concepts of C# 10 and .NET 6's fundamental components.
This part comprises the following chapters:
Chapter 1, Designing and Architecting the Enterprise ApplicationChapter 2, Introducing .NET 6 Core and StandardChapter 3, Introducing C# 10Enterprise applications are software solutions designed to solve large and complex problems for enterprise organizations. They enable Order-to-Fulfillment capabilities for enterprise customers in the IT, government, education, and public sectors. They empower them to digitally transform their businesses with capabilities such as product purchasing, payment processing, automated billing, and customer management. When it comes to enterprise applications, the number of integrations is quite high, and the volume of users is also very high as, typically, applications are targeted at a global audience.
To ensure that enterprise systems remain highly reliable, highly available, and highly performant, getting the design and architecture right is very important. Design and architecture form the foundation of any good software. They form the basis of the rest of the software development life cycle; therefore, it is very important to, first, get the right design to avoid any rework later, which could prove very expensive, depending on the changes required. So, you need a flexible, scalable, extensible, and maintainable design and architecture.
In this chapter, we will cover the following topics:
A primer on common design principles and patternsUnderstanding common enterprise architecturesIdentifying enterprise application requirements (business and technical)Architecting an enterprise applicationSolution structuring for an enterprise applicationBy the end of this chapter, you will be able to start designing and architecting enterprise applications.
Every piece of software in the world solves at least one real-world problem. As time goes by, things change, including what we expect from any specific software. To manage this change and deal with various aspects of software, engineers have developed several programming paradigms, frameworks, tools, techniques, processes, and principles. These principles and patterns, proven over time, have become guiding stars for engineers to build quality software.
Principles are high-level abstract guidelines to be followed while designing. They are applicable regardless of the programming language being used. They do not provide implementation guidelines.
Patterns are low-level specific implementation guidelines that are proven, reusable solutions for recurring problems. First, let's start with design principles.
Techniques become principles if they are widely accepted, practiced, and proven to be useful in any industry. Those principles become solutions to make software designs more understandable, flexible, and maintainable. In this section, we will cover the SOLID, KISS, and DRY design principles.
The SOLID principles are a subset of the many principles promoted by an American software engineer and instructor, Robert C. Martin. These principles have become the de facto standard principles in the OOP world and have become part of the core philosophy for other methodologies and paradigms.
SOLID is an acronym for the following five principles:
Single-responsibility principle (SRP): An entity or software module should only have a single responsibility. You should avoid granting multiple responsibilities to one entity.Figure 1.1 – SRP
Open-closed principle (OCP): Entities should be designed in such a way that they are open for extension but closed for modification. This means the regression testing of existing behaviors can be avoided; only extensions need to be tested.Figure 1.2 – OCP
Liskov substitution principle (LSP): Parent or base class instances should be replaceable with instances of their derived classes or subtypes without altering the sanity of the program.Figure 1.3 – LSP
Interface segregation principle (ISP): Instead of one common large interface, you should plan multiple, scenario-specific interfaces for better decoupling and change management:Figure 1.4 – ISP
Dependency inversion principle (DIP): You should avoid having any direct dependency on concrete implementations. High-level modules and low-level modules should not depend on each other directly. Instead, both should depend on abstractions as much as possible. Abstractions should not depend on details, and details should depend on abstractions.Figure 1.5 – DIP
With DRY, a system should be designed in such a way that the implementation of a feature or a pattern should not be repeated in multiple places. This would result in maintenance overhead, as a change in requirements would result in modifications being needed at multiple places. If you fail to make a necessary update in one place by mistake, the behavior of the system will become inconsistent. Rather, the feature should be wrapped into a package and should be reused in all places. In the case of a database, you should look at using data normalization to reduce redundancy.
Figure 1.6 – DRY
This strategy helps in reducing redundancy and promoting reuse. This principle helps an organization's culture too, encouraging more collaboration.
With KISS, a system should be designed as simply as possible, avoiding complicated designs, algorithms, new untried technologies, and more. You should focus on leveraging the right OOP concepts and reusing proven patterns and principles. Include new or non-simple things only if it is necessary and adds value to the implementation.
When you keep it simple, you will be able to do the following better:
Avoid mistakes while designing/developing.Keep the train running (there is always a team whose job is to maintain the system, even though they are not the team that developed the system in the first place).Read and understand your system code (your system code needs to be understandable to people who are new to it or for people who will use it in the future).Do better and less error-prone change management.With this, we are done with our primer on common design principles; we have learned about SOLID, DRY, and KISS. In the next section, we'll look at some common design patterns in the context of real-world examples to help you understand the difference between principles and patterns and when to leverage which pattern—a skill that's essential for good design and architecture.
While following design principles in the OOP paradigm, you might see the same structures and patterns repeating over and again. These repeating structures and techniques are proven solutions to common problems and are known as design patterns. Proven design patterns are easy to reuse, implement, change, and test. The well-known book, Design Patterns: Elements of Reusable Object-Oriented Software, comprising what is known as the Gang of Four (GOF) design patterns, is considered the bible of patterns.
We can categorize the GOF patterns as follows:
Creative: Helpful in creating objectsStructural: Helpful in dealing with the composition of objectsBehavioral: Helpful in defining the interactions between objects and distributing responsibilityLet's look at these patterns with some real-life examples.
Let's take a look at some creational design patterns, along with relevant examples, in the following table:
Table 1.1 – Creational design patterns
The following table includes some examples of structural design patterns:
Table 1.2 – Structural design patterns
The following table includes some examples of behavioral design patterns:
Table 1.3 – Behavioral design patterns
Sometimes, you can become overwhelmed by all these patterns being inside the table. But really, any design is a good design until it violates the basic principles. One rule of thumb that we can use is to go back to the basics, and in design, principles are the basics.
Figure 1.7 – Patterns versus principles
With this, we are done with our primer on common design principles and patterns. By now, you should have a good understanding of the different principles and patterns, where to use them, and what it takes to build a great solution. Now, let's spend some time looking at common enterprise architectures.
There are a few principles and architectures that are commonly practiced when designing enterprise applications. First and foremost, the goal of any architecture is to support business needs at the lowest cost possible (costs being time and resources). A business wants software to enable it rather than act as a bottleneck. In today's world, availability, reliability, and performance are the three KPIs of any system.
In this section, first, we will look at the issues with monolithic architectures, and then we will see how to avoid them by using widely adopted and proven architectures for developing enterprise applications.
Consider a classical monolithic e-commerce website application, such as the one shown in the following diagram, with all the business providers and functionality in a single app and data being stored in a classical SQL database:
Figure 1.8 – A monolithic app
The monolithic architecture was widely adopted 15–20 years ago, but plenty of problems arose for software engineering teams when systems grew and business needs expanded over time. Let's look at some of the common issues with this approach.
Let's take a look at the scaling issues:
In a monolithic app, the only way to horizontally scale is by adding more compute to the system. This leads to higher operational costs and unoptimized resource utilization. Sometimes, scaling becomes impossible due to conflicting needs in terms of resources.As all the features mostly use single storage, there is the possibility of locks leading to high latency, and there will also be physical limits as to how far a single storage instance can scale.Here is a list of issues associated with availability, reliability, and performance:
Any changes in the system will require the redeployment of all components, leading to downtime and low availability.Any non-persistent state, such as sessions stored in a web app, will be lost after every deployment. This will lead to the abandonment of all workflows that were triggered by users.Any bugs in a module, such as memory leaks or security bugs, make all the modules vulnerable and have the potential to impact the whole system.Due to the highly coupled nature and sharing of resources within modules, there will always be unoptimized use of resources, leading to high latency in the system.Lastly, let's see what the impact on the business and engineering teams is:
The impact of a change is difficult to quantify and requires extensive testing. Hence, it slows down the rate of delivery to production. Even a small change will require the entire system to be deployed again.In a single highly coupled system, there will always be physical limits on collaborations across teams to deliver any features.New scenarios such as mobile apps, chatbots, and analysis engines will take more effort as there are no independent reusable components or services.Continuous deployment is almost impossible.Software should be divided into components or modules based on the kind of work it performs where every module or component owns a single responsibility from the entire software's responsibility. Interaction between components happens via interfaces or messaging systems. Let's look at the n-tier and microservices architecture and how the separation of concerns is taken care of.
N-tier architecture divides the application of a system into three (or n) tiers:
Presentation (known as the UX layer, the UI layer, or the work surface)Business (known as the business rules layer or the services layer)Data (known as the data storage and access layer)Figure 1.9 – N-tier architecture
These tiers can be owned/managed/deployed separately. For example, multiple presentation layers, such as the web, mobile, and bot layers, can leverage the same business and data tier.
Microservices architecture consists of small, loosely coupled, independent, and autonomous services. Let's see their benefits:
Services can be deployed and scaled independently. An issue in one service will have a local impact and can be fixed by just deploying the impacted service. There is no compulsion to share technology or frameworks.Services communicate with each other via well-defined APIs or messaging systems such as the Azure service bus.Figure 1.10 – Microservices architecture
As you can see in the preceding diagram, a service can be owned by independent teams and have its own cycle. Services are responsible for managing their own data stores. Scenarios demanding lower latency can be optimized by bringing in a cache or high-performance NoSQL stores.
Services should not have any state. State and data should be managed independently from services, that is, externally through a data store such as a distributed cache or a database. By delegating the state externally, services will have the resources to serve more requests with high reliability. The following diagram shows an example of stateful services on the left-hand side. Here, state is maintained in each service through an in-memory cache or session provider, whereas a stateless service, as shown on the right-hand side, manages state and data externally.
Figure 1.11 – Stateful (left) versus stateless (right)
Session affinity should not be enabled as it leads to sticky session issues and will stop you from getting the benefits of load balancing, scalability, and the distribution of traffic.
The main features of event-driven architectures are listed as follows:
In an event-driven architecture, communication, which is generally known as publisher-subscriber communication, between modules, is primarily asynchronous and achieved via events. Producers and consumers are totally decoupled from each other. The structure of the event is the only contract that is exchanged between them.There can be multiple consumers of the same event taking care of their specific operations; ideally, they won't even be aware of each other. Producers can continuously push events without worrying about the availability of consumers.Publishers publish events via a messaging infrastructure such as queues or a service bus. Once an event has been published, the messaging infrastructure is responsible for sending the event to eligible subscribers.Figure 1.12 – Event-driven architecture
This architecture is best suited for scenarios that are asynchronous in nature. For example, long-running operations can be queued for processing. A client might poll for status or even act as a subscriber for an event.
As the communication between components increases, so does the possibility of failures. A system should be designed to recover from any kind of failure. We will cover a few strategies for building a fault-tolerant system that can heal itself in the case of failures.
If you are familiar with Azure, you'll know that applications, services, and data should be replicated globally in at least two Azure regions for planned downtime and unplanned transient or permanent failures, as shown in the following screenshot. In these scenarios, choosing Azure App Service to host web applications, using REST APIs, and choosing a globally distributed database service, such as Azure Cosmos DB, is wise. Choosing Azure paired regions will help in business continuity and disaster recovery (BCDR), as at least one region in each pair will be prioritized for recovery if an outage affects multiple regions.
Figure 1.13 – Resiliency architecture
Now, let's see how to tackle different types of faults.
Transient faults can occur in any type of communication or service. You need to have a strategy to recover from transient faults, such as the following:
Identify the operation and type of transient fault. Then, determine the appropriate retry count and interval.Avoid anti-patterns such as endless retry mechanisms with a finite number of retries or circuit breakers.If a failure is not transient, you should respond to the failure gracefully by choosing some of the following options:
Failing overCompensating for any failed operationsThrottling/blocking the bad client/actorUsing a leader election to select a leader in the case of a failureHere, telemetry plays a big role; you should have custom metrics to keep a tab on the health of any component. Alerts can be raised when a custom event occurs or a specific metric reaches a certain threshold.
With this, we are done with our coverage of common enterprise architectures. Next, we will look at the requirements of enterprise applications and their different architectures through the lens of the design principles and common architectures that we learned about earlier.
In the next few chapters, we will build a working e-commerce application. It will be a three-tier application consisting of a UI layer, a service layer, and a database. Let's look at the requirements for this e-commerce application.
The solution requirements are the capabilities to be implemented and made available in the product to solve a problem or achieve an objective.
The business requirements are simply the end customer's needs. In the IT world, business, generally, refers to customers. These requirements are collected from various stakeholders and documented as a single source of truth for everyone's preference. Eventually, this becomes the backlog and scope of work to be completed.
The technical requirements are the technology-related aspects that a system should implement, such as reliability, availability, performance, and BCDR. These are also known as quality-of-service (QoS) requirements.
Let's break the typical business requirements for an e-commerce application site down into the following categories: Epic, Feature, and User Story.
The following screenshot, from Azure DevOps, shows a summary of the backlog of our business requirements. You can see the different features that are expected in our application along with the user stories.
Figure 1.14 – Requirement backlog from Azure DevOps
Having seen the business requirements, let's now go through the technical requirements:
The e-commerce application should be highly available, that is, available for 99.99% of the time during any 24-hour period.The e-commerce application should be highly reliable, that is, reliable for 99.99% of the time during any 24-hour period.The e-commerce application should be highly performant, that is, 95% of operations should take less than or be equal to 3 seconds during any 24-hour period.The e-commerce application should be highly scalable: It should automatically scale up/down based on the varying load.The e-commerce application should have monitoring and alerts: An alert should be sent to a support engineer in the case of any system failures.Here are the technical aspects and requirements that have been identified for the e-commerce application:
We are now done with the requirements of the enterprise application. Next, we will look at how to architect an enterprise application.
The following architectural diagram depicts what we are building. We need to bear in mind all of the design principles, patterns, and requirements that we have seen in this chapter when we are architecting and developing the application. The following diagram shows the proposed architecture for our e-commerce enterprise application:
Figure 1.15 – The e-commerce application's three-tier architecture
Separation of concerns/SRP has been taken care of at each tier. The presentation tier, containing the UI, is separated from the services tier containing the business logic. This is again separated from the data access tier containing the data store.
The high-level components are unaware of the low-level components consuming them. The data access tier is unaware of the services consuming it, and the services are unaware of the UX tier consuming them.
Each service is separated based on the business logic and functionality it is supposed to perform.
Encapsulation has been taken care of at the architecture level and should be taken care of during development, too. Each component in the architecture will be interacting with other components through well-defined interfaces and contracts. We should be able to replace any component in the diagram without having to worry about its internal implementation and whether it adheres to the contracts.
The loosely coupled architecture here also helps with faster development and faster deployment to the market for customers. Multiple teams can work, in parallel, on each of their components independently. They share the contracts and timelines for integration testing at the start, and once the internal implementation and unit tests are done, they can start with integration testing.
Refer to the following diagram:
Figure 1.16 – The eCommerce application's three-tier architecture with highlighted chapters
From the preceding diagram, we can identify the chapters in which different parts of the e-commerce application that we will build will be covered. They can be explained as follows:
Creating an ASP.NET web application (our e-commerce portal) will be covered in Chapter 11, Creating an ASP.NET Core 6 Web Application.Authentication will be covered in Chapter 12, Understanding Authentication.The order processing service and the invoice processing service are the two core services for generating orders and invoicing. They will be the heart of the e-commerce application as they are the ones that are responsible for the revenue. Creating an ASP.NET Core web API will be covered in Chapter 10, Creating an ASP.NET Core 6 Web API, and cross-cutting concerns will be covered in Chapter 5, Dependency Injection in .NET 6, Chapter 6, Configuration in .NET 6, and Chapter 7, Logging in .NET 6, respectively. The DRY principle will be taken care of by reusing core components and cross-cutting concerns instead of repeating implementations.Caching will be covered as part of the product pricing service in Chapter 8, All You Need to Know about Caching. Caching will help us to improve the performance and scalability of our system, with temporary copies of frequently accessed data being available in memory.Data storage, access, and the number of providers will be covered as part of the data access layer in Chapter 9, Working with Data in .NET 6. The kind of architecture that we have adopted, where data and access to it are separate from the rest of the application, gives us better maintenance. Azure Cosmos DB is our choice to scale throughput and storage elastically and independently across any number of Azure regions worldwide. Additionally, it is secure by default and enterprise-ready.This concludes our discussion on architecting our enterprise application. Next, we will look at the solution structure for our enterprise application.
To keep things simple, we will go with a single solution for all our projects, as shown in the following screenshot. The other approach of having separate solutions for the UI, shared components, and web APIs can also be considered when the number of projects in the solution explodes and causes maintenance issues. The following screenshot shows our application's solution structure:
Figure 1.17 – The solution structure of the e-commerce application
Here, we have adopted separation of concerns by having separate folder structures and projects for UX, Service, Data, Core, and Testing.
In this chapter, we learned about common design principles such as SOLID, DRY, and KISS. Also, we looked at various design patterns with real-world examples. Then, we looked at different enterprise architectures, identified the requirements for the e-commerce application that we are going to build, and applied what we learned to architect our e-commerce application. You can now apply what you have learned here when you design any application.
In the next chapter, we will learn about .NET 6 Core and Standard.
a. Base class instances should be replaceable with instances of their derived type.
b. Derived class instances should be replaceable with instances of their base type.
c. Designing for generics that can work with any data type.
Answer: a
What is SRP?a. Instead of one common large interface, plan for multiple scenario-specific interfaces for better decoupling and change management.
b. You should avoid taking a direct dependency approach on concrete implementation. Instead, you should depend on abstractions as much as possible.
c. An entity should only have a single responsibility. You should avoid empowering one entity with multiple responsibilities.
d. Entities should be designed in such a way that they should be open for extension but closed for modification.
Answer: c
What is OCP?a. Entities should be open to modification but closed for extension.
b. Entities should be open to extension but closed for modification.
c. Entities should be open to composition but closed for extension.
d. Entities should be open to abstraction but closed for inheritance.
Answer: b
Which pattern is used to make two incompatible interfaces work together?a. Proxy
b. Bridge
c. Iterator
d. Adapter
Answer: d
Which principle ensures that services can be deployed and scaled independently and that an issue in one service will have a local impact, which can be fixed by just redeploying the impacted service?a. The domain-driven design principle
b. The single-responsibility principle
c. The stateless service principle
d. The resiliency principle
Answer: b
.NET is a developer platform that offers libraries and tools for building many different types of applications, such as web, desktop, mobile, games, Internet of Things (IoT), and cloud applications. Using .NET, we can develop applications targeting many operating systems, including Windows, macOS, Linux, Android, iOS, and so on, and it supports processor architectures such as x86, x64, ARM32, and ARM64.
.NET also supports application development using multiple programming languages, such as C#, Visual Basic, and F#, using popular integrated development environments (IDEs) such as Visual Studio, Visual Studio Code, and Visual Studio for Mac.
After .NET 5, .NET 6 is now a major release that includes C# 10 and F# 6, adds many language features, and includes many performance improvements.
The following topics are covered in this chapter:
Introducing .NET 6Understanding the core components of .NET 6Setting up the development environmentUnderstanding the CLIWhat is .NET Standard?Understanding .NET 6 cross-platform and cloud application supportThis chapter will help us understand a few core components, libraries, and tools that are included in .NET for developing the applications.
A Windows, Linux, or Mac machine is required and install the respective SDK from https://dotnet.microsoft.com/download/dotnet/6.0.
In 2002, Microsoft released the first version of .NET Framework, a development platform to develop web and desktop applications. .NET Framework offers many services, including managed code execution, a vast set of APIs via a base class library, memory management, a common type system, language interoperability, and development frameworks such as ADO.NET, ASP.NET, WCF, WinForms, and Windows Presentation Framework (WPF). Initially, it was released as a separate installer, but it was later integrated and shipped with the Windows operating system. .NET Framework 4.8 is the latest version of .NET Framework.
In 2014, Microsoft announced an open source, cross-platform implementation of .NET called .NET Core. .NET Core was built from scratch to make it cross-platform and it is currently available on Linux, macOS, and Windows. .NET Core is fast and modular and offers support side by side so that we can run different versions of .NET Core on the same machine without affecting other applications.
.NET 6 is an open source, cross-platform implementation of .NET with which you can build applications that can run on Windows, macOS, and Linux operating systems. With .NET 6, Microsoft's unified platform to develop browser, cloud, desktop, IoT, and mobile applications in order to use the same .NET libraries and share code easily.
To learn more about new features in .NET 6, you can visit https://docs.microsoft.com/en-us/dotnet/core/whats-new/dotnet-6.
Note
.NET 6 is a long-term support (LTS) release; it is supported for 3 years from the generally available date. It is recommended to migrate, particularly .NET 5 apps to .NET 6. For more details, you can visit https://dotnet.microsoft.com/en-us/platform/support/policy/dotnet-core.
Next, let's understand the core features of .NET.
The following are a couple of the core features of .NET that we will understand more in depth:
Open source: .NET is a free (with no licensing costs, including for commercial use) and open source developer platform that offers many development tools for Linux, macOS, and Windows. Its source code is maintained by Microsoft and the .NET community on GitHub. You can access the .NET repositories at https://github.com/dotnet/core/blob/master/Documentation/core-repos.md.Cross-platform: .NET applications run on many operating systems, including Linux, macOS, Android, iOS, tvOS, watchOS, and Windows. They also run consistently across processor architectures, such as x86, x64, ARM32, and ARM64.With .NET, we can build the following types of applications:
Table 2.1 – Application types
Programming languages: .NET supports multiple programming languages. Code written in one language is accessible in other languages. The following table shows the supported languages:Table 2.2 – Supported Languages
IDEs: .NET supports multiple IDEs. Let's understand each one:a. Visual Studio is a feature-rich IDE available on the Windows platform to build, debug, and publish .NET applications. It is available in three editions: Community, Professional, and Enterprise. Visual Studio 2022 Community Edition is free for students, individual developers, and organizations contributing to open source projects.
b. Visual Studio for Mac is free and available for macOS. It can be used to develop cross-platform applications and games for iOS, Android, and the web using .NET.
c. Visual Studio Code is a free, open source, lightweight yet powerful code editor available on Windows, macOS, and Linux. It has built-in support for JavaScript, TypeScript, and Node.js and, with extensions, you can add support for many popular programming languages.
d. Codespaces is a cloud development environment powered by Visual Studio Code and hosted by GitHub to develop .NET applications.
Deployment models: .NET supports two modes of deployment:a. Self-contained: When a .NET application is published in self-contained mode, the published artifact contains the .NET runtime, libraries, and the application and its dependencies. Self-contained applications are platform-specific, and the target machine need not have the .NET runtime installed. The machine uses the .NET runtime shipped along with the application to run the application.
b. Framework-dependent: When a .NET application is published in framework-dependent mode, the published artifact contains only the application and its dependencies. The .NET runtime must be installed on the target machine to run the application.
Next, let's understand the application frameworks offered by .NET.
.NET simplifies application development by offering many application frameworks. Each application framework contains a set of libraries to develop targeted applications. Let's understand each in detail:
ASP.NET Core: This is an open source and cross-platform application development framework that lets you build modern, cloud-based, internet-connected applications, such as web, IoT, and API applications. ASP.NET Core is built on top of .NET Core, hence you can build and run across platforms, such as Linux, macOS, and Windows.Blazor: This is an application framework to build interactive client-side web UI using C# instead of JavaScript. Blazor applications can re-use code and libraries from the server side and run in the browser using WebAssembly or handle Client UI events on the server using SignalR.WPF: This is a UIframework that lets you create desktop applications for Windows. WPF uses Extensible Application Markup Language (XAML), a declarative model for application development.Entity Framework (EF) Core: This is an open source, cross-platform, lightweight, object-relational mapping (ORM) framework to work with databases using .NET objects. It supports LINQ queries, changes tracking, and schema migrations. It works with popular databases, such as SQL Server, SQL Azure, SQLite, Azure Cosmos DB, MySQL, and many more.Language-Integrated Query (LINQ): This adds query capabilities to .NET programming languages. LINQ allows you to query data from a database, XML, in-memory arrays, and collections with the same API..NET MAUI: The .NET Multi-platform App UI is a cross-platform framework to create native mobile and desktop applications using C# and XAML. Using .NET MAUI, you can develop applications targeting Android, iOS, macOS, and Windows using the same code base.Note
.NET MAUI is currently in preview, and is not recommended for production use. For more information, you can refer to https://docs.microsoft.com/en-us/dotnet/maui/what-is-maui.
In the next section, let's understand the core components of .NET.
.NET has two major components: a runtime and base class libraries. The runtime includes a garbage collector (GC) and the just-in-time (JIT) compiler, which manages the execution of .NET applications and base class libraries (BCLs), also known as runtime libraries or framework libraries, which contain the fundamental building blocks for .NET applications.
The .NET SDK is available for download at https://dotnet.microsoft.com/download/dotnet/6.0. It contains a set of libraries and tools to develop and run .NET applications. You can choose to install either the SDK or the .NET runtime. To develop .NET applications, you should install the SDK on the development machine and the .NET runtime to run .NET applications. The .NET runtime is included in the .NET SDK, hence you don't have to install the .NET runtime separately if you have already installed the .NET SDK.
Figure 2.1 – Visualization of the .NET SDK
The .NET SDK contains the following components:
Common Language Runtime (CLR): CLR executes the code and manages memory allocation. .NET applications, when compiled, produce an intermediate language (IL). CLR uses a JIT compiler to convert compiled code to machine code. It is a cross-platform runtime that is available for Windows, Linux, and macOS.Memory management: The GC manages the allocation and release of memory for .NET applications. For every new object created, memory is allocated in the managed heap and when there is not enough free space available, GC checks for objects in the managed heap and removes them if they are no longer used in the application. For more information, you can refer to https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection.JIT: When .NET code is compiled, it is converted to IL. IL is platform- and language-independent, so when the runtime runs the application, JIT converts IL into machine code that the processor understands.Common type system: This defines how types are defined, used, and managed in CLR. It enables cross-language integrations and ensures type safety.Base class library: This contains implementations for primitive types such as System.String and System.Boolean, collections such as List<T> and Dictionary<Tkey, Tvalue>, and utility functions to perform I/O operations, HTTP, serialization, and many more. It simplifies .NET application development.Roslyn compilers: Roslyn is an open source C# and Visual Basic compiler with rich code analysis APIs. It enables building code analysis tools with the same API used by Visual Studio.MSBuild: This is a tool to build .NET applications. Visual Studio uses MSBuild to build .NET applications.NuGet: This is an open source package manager tool with which you can create, publish, and reuse code. A NuGet package contains compiled code, its dependent files, and a manifest that includes package version number information.In the next section, let's understand how to set up the development environment to create and run .NET applications.
Setting up a development environment is very easy. You will need the .NET SDK to build and run .NET applications. Optionally, you can choose to install IDEs that support .NET application development. You need to perform the following steps to set up the .NET SDK on your machine:
Note
.NET 6 is supported by Visual Studio 2022 and Visual Studio 2022 for Mac. It is not supported on earlier versions of Visual Studio. Visual Studio Community Edition is free for individual developers, classroom learning, and for unlimited users in organizations contributing to research or open source projects. It offers the same features as Professional Edition, but for advanced features such as advanced debugging and diagnostics tools, testing tools, and more, you need to have Enterprise Edition. To compare features, you can visit https://visualstudio.microsoft.com/vs/compare.
On a Windows machine, download and install Visual Studio 17.0 or later from https://visualstudio.microsoft.com.In the installation options, from Workloads, you can select ASP.NET and web for web/API applications, Azure development, Mobile development with .NET for iOS, Android, windows, and .NET desktop development for windows applications, as shown in the following screenshot:Figure 2.2 – Visual Studio installation, workload selection
Confirm the selection and proceed to complete the installation. This will install Visual Studio and the .NET 6 SDK on your machine.Note
Azure development workload includes SDKs and tools to develop and support applications targeting Azure Services. It includes tools for Container development, Azure resource manager, Azure Cloud Services, Service Fabric, Azure Data Lake and Stream Analytics, Snapshot Debugger, and many more.
Alternatively, you can also perform the following steps to set it up:
Download and install the .NET 6 SDK for Windows, macOS, and Linux from https://dotnet.microsoft.com/download/dotnet/6.0. .NET Core supports side-by-side execution, and hence we can install multiple versions of .NET Core SDKs on a development machine.From Command Prompt, run the dotnet --version command to verify the installed version, as shown in the following screenshot:
Figure 2.3 – Command-line output of the dotnet command
Optionally, you can download and install Visual Studio Code from https://code.visualstudio.com to use it to develop the .NET application.Now that we understand how to set up a development environment for .NET, in the next section, let's understand what the .NET CLI is and how it helps to create, build, and run .NET applications from the command line.
To set up an e-commerce application, you can refer to https://github.com/PacktPublishing/Enterprise-Application-Development-with-C-10-and-.NET-6-Second-Edition/blob/main/README.md.
The .NET CLI is a cross-platform, command-line interface tool available to develop, build, run, and publish .NET applications. It is included in the .NET SDK.
The CLI command structure contains command driver (dotnet), command, command-arguments, and options, and this is a common pattern for most CLI operations. Refer to the following command pattern:
driver command <command-arguments> <options>
For instance, the following command creates a new console application. dotnet is the driver, new is the command, and console is a template name as an argument:
