Book Image

Hands-On Microservices with C# 8 and .NET Core 3 - Third Edition

By : Gaurav Aroraa, Ed Price
Book Image

Hands-On Microservices with C# 8 and .NET Core 3 - Third Edition

By: Gaurav Aroraa, Ed Price

Overview of this book

<p>The microservice architectural style promotes the development of complex applications as a suite of small services based on specific business capabilities. With this book, you'll take a hands-on approach to build microservices and deploy them using ASP .NET Core and Microsoft Azure. </p><p>You'll start by understanding the concept of microservices and their fundamental characteristics. This microservices book will then introduce a real-world app built as a monolith, currently struggling under increased demand and complexity, and guide you in its transition to microservices using the latest features of C# 8 and .NET Core 3. You'll identify service boundaries, split the application into multiple microservices, and define service contracts. You'll also explore how to configure, deploy, and monitor microservices using Docker and Kubernetes, and implement autoscaling in a microservices architecture for enhanced productivity. Once you've got to grips with reactive microservices, you'll discover how keeping your code base simple enables you to focus on what's important rather than on messy asynchronous calls. Finally, you'll delve into various design patterns and best practices for creating enterprise-ready microservice applications. </p><p>By the end of this book, you'll be able to deconstruct a monolith successfully to create well-defined microservices.</p>
Table of Contents (16 chapters)

Exploring monolithic architecture

The monolithic architectural style is a traditional architecture type that has been widely used in the IT industry. The term monolithic is not new and is borrowed from the Unix world. In Unix, most commands exist as a standalone program whose functionality is not dependent on any other program. As seen in the following diagram, we can have different components in the application, including the following:

  • User interface: This handles all of the user interactions while responding with HTML, JSON, or any other preferred data interchange format (in the case of web services).
  • Business logic: This includes all the business rules applied to the input being received in the form of user input, events, and the database.
  • Database access: This houses the complete functionality for accessing the database for the purpose of querying and persisting objects. A widely accepted rule is that it is utilized through business modules and never directly through user-facing components.

Software built using this architecture is self-contained. We can imagine a single .NET assembly that contains various components, as depicted in the following diagram:

As the software is self-contained here, its components are interconnected and interdependent. Even a simple code change in one of the modules may break a major functionality in other modules. This would result in a scenario in which we'd need to test the whole application. With the business depending critically on its enterprise application frameworks, this amount of time could prove to be very critical.

Having all the components tightly coupled poses another challenge: whenever we execute or compile such software, all the components should be available or the build will fail. Refer to the previous diagram, which represents a monolithic architecture and is a self-contained or a single .NET assembly project. However, monolithic architectures might also have multiple assemblies. This means that even though a business layer (assembly, data access layer assembly, and so on) is separated, all of them will come together and run as one process at runtime.

A user interface depends on other components' direct sales and inventory in a manner similar to all other components that depend upon each other. In this scenario, we would not be able to execute this project in the absence of any one of these components. The process of upgrading them would be more complex, as we would have to consider other components that require code changes too. This would result in more development time than is required for the actual change.

Deploying such an application would become another challenge. During deployment, we would have to make sure that every component was deployed properly. If we didn't do this, we may end up facing a lot of issues in our production environments.

If we develop an application using the monolithic architecture style, as discussed previously, we might face the following challenges:

  • Large code base: This is a scenario where the code lines outnumber the comments by a great margin. As components are interconnected, we would have to deal with a repetitive code base.
  • Too many business modules: This is in regard to modules within the same system.
  • Code base complexity: This results in a higher chance of code breaking due to the fix required in other modules or services.
  • Complex code deployment: You may come across minor changes that would require whole system deployment.
  • One module failure affecting the whole system: This is with regard to modules that depend on each other.
  • Scalability: This is required for the entire system and not just the modules in it.
  • Intermodule dependency: This is due to tight coupling. This results in heavy changes if required for an operation of any of the modules.
Tight coupling is a scenario in which one class is intended for many responsibilities, or in other words, when classes (mostly a group of classes) are dependent on each other.
  • Spiraling development time: This is due to code complexity and interdependency.
  • Inability to easily adapt to new technology: In this case, the entire system would need to be upgraded.

As discussed earlier, if we want to reduce development time, ease deployment, and improve the maintainability of software for enterprise applications, we should avoid traditional or monolithic architecture. Therefore, we will look at SOA.

Service-oriented architecture

In the previous section, we discussed the monolithic architecture and its limitations. We also discussed why it does not fit into our enterprise application requirements. To overcome these issues, we should take a modular approach where we can separate the components so that they come out of the self-contained or single .NET assembly. A system that uses a service or multiple services in the fashion depicted in the previous diagram is called a service-oriented architecture (SOA).

The main difference between SOA and monolithic architecture is not one or multiple assemblies. As the service in SOA runs as a separate process, SOA scales better in comparison.

Let's discuss modular architecture, that is, SOA. This is a famous architectural style where enterprise applications are designed as a collection of services. These services may be RESTful or ASMX web services. To understand SOA in more detail, let's discuss services first.

Understanding services

Services, in this case, are an essential concept of SOA. They can be a piece of code, a program, or software that provides functionality to other system components. This piece of code can interact directly with the database or indirectly through another service. Furthermore, it can be consumed by clients directly, where the client may be a website, desktop app, mobile app, or any other device app. The following diagram shows that services can be consumed by various clients via the web, desktop, mobile, or any other devices. Services can be with or without database support at the backend:

A service refers to a type of functionality exposed for consumption by other systems (generally referred to as clients/client applications). As mentioned earlier, this can be represented by a piece of code, a program, or software. Such services are exposed over the HTTP transport protocol as a general practice. However, the HTTP protocol is not a limiting factor, and a protocol can be picked as deemed fit for the scenario.

In the following diagram, Service - direct selling is directly interacting with the Database and three different clients, namely, Web, Desktop, and Mobile, are consuming the service. On the other hand, we have clients consuming Service - partner selling, which is interacting with Service - channel partners for database access.

A product selling service is a set of services that interact with client applications and provide database access directly or through another service, in this case, Service – Channel partners. In the case of Service – direct selling, shown in the following diagram, it is providing the functionality to a web store, a desktop application, and a mobile application. This service is further interacting with the database for various tasks, namely, fetching and persisting data.

Normally, services interact with other systems via a communication channel, generally the HTTP protocol. These services may or may not be deployed on the same or single servers:

In the previous diagram, we have projected an SOA example scenario. There are many fine points to note here, so let's get started. First, our services can be spread across different physical machines. Here, Service - direct selling is hosted on two separate machines. It is possible that instead of the entire business functionality, only a part of it will reside on Server 1 and the remaining part on Server 2. Similarly, Service - partner selling appears to have the same arrangement on Server 3 and Server 4. However, it doesn't stop Service - channel partners from being hosted as a complete set on both Server 5 and Server 6.

We will discuss SOA in detail in the following sections.

Let's recall monolithic architecture. In this case, we did not use it because it restricts code reusability; it is a self-contained assembly, and all the components are interconnected and interdependent. For deployment, in this case, we will have to deploy our complete project after we select the SOA (refer to the previous diagram and the subsequent discussion). Now, because of the use of this architectural style, we have the benefit of code reusability and easy deployment. Let's examine this in the light of the previous diagram:

  • Reusability: Multiple clients can consume the service. This can also be simultaneously consumed by other services. For example, OrderService is consumed by web and mobile clients. OrderService can now also be used by the Reporting Dashboard UI.
  • Stateless: Services do not persist in any state between requests from the client. This means that the service doesn't know or care that the subsequent request has come from the client that has/hasn't made the previous request.
  • Contract-based: Interfaces make any service technology-agnostic on both sides of implementation and consumption. They also serve to make it immune to the code updates in the underlying functionality.
  • Scalability: A system can be scaled up, and the SOA can be individually clustered with the appropriate load balancing.
  • Upgradeability: It is very easy to roll out new functionalities or introduce new versions of the existing functionality. The system doesn't stop you from keeping multiple versions of the same business functionality.

This section covered SOA, and we have also discussed the concept of services and how they impact architecture. Next, we will move on to learn all about microservice architecture.