Telerik blogs

Object orientation is an essential paradigm for web developers. Learn the four pillars of object-oriented programming through an example ASP.NET Core app.

Object orientation is vital in developing robust and scalable applications in ASP.NET Core. By adopting object-oriented principles, developers can structure their code to be modular and reusable, promoting greater cohesion and less coupling between components, resulting in a more flexible and maintainable architecture.

This post will discuss the four pillars of object orientation and demonstrate how to implement each in an ASP.NET Core application. That way, you can safely develop an object-oriented application and understand each concept of this paradigm.

What is Object-Oriented Programming?

Object-oriented programming (OOP) is a paradigm that emerged in the 1960s, but became popular mainly in the ’90s and became the basis for the creation of several programming languages such as C#, Java, C++, Python, Lua and PHP, among others. OOP teaches a special way of writing computer programs, where real-world ideas are abstracted into software through blocks called “objects.”

An object is an abstraction of some real-world event or entity, with attributes that represent its characteristics or properties, and methods that emulate its behavior.

Think of it like LEGO toys. Each LEGO brick is like an object and you can fit these pieces together to build bigger and more complex things. Likewise, in OOP, you create objects that have their own characteristics (attributes) and actions they can do (methods).

For example, if you are writing a program about library books, you could create an object called “Book.” This object would have information about the book (attributes), such as title, author and year of publication, as well as actions related to it (methods), such as loan, return and late fees.

The big idea of OOP is to break a complex program into smaller, more manageable parts. This makes programming more organized and helps with code reuse, like using different LEGO bricks to build multiple creations.

Looking at it from an imaginary angle, we can say that object-oriented programming is like playing with virtual LEGO pieces on the computer, where you create objects with specific characteristics and actions to build more efficient and flexible programs with reusable parts.

The 4 Basic Principles of OOP

These four basic concepts are fundamental to object-oriented programming and help to create more organized, reusable and understandable code, making the development process more efficient:

oop principles diagram: abstraction, encapsulation, inheritance and polymorphism

1. Abstraction

Abstraction means focusing only on the most important information about an object, ignoring less relevant details. In programming, abstraction allows you to create simple and clear models of objects, hiding complex details and abstractly representing a system.

2. Encapsulation

Encapsulation means that you put your data (attributes) and actions (methods) inside a class and control who can access them. This helps prevent parts of your code from unduly interfering with other parts, making your program more organized and secure.

3. Inheritance

Inheritance is like passing traits from one thing to another, like parents passing traits on to their children. In programming, you can create a new class based on another existing class, called a parent class or superclass. The new class inherits the attributes and methods of the parent class, being able to add new things or customize the behavior. This helps reuse code and create object hierarchies.

4. Polymorphism

We can understand polymorphism as an object that acts in different ways depending on the context, like a key that can fit in different types of locks. In programming, polymorphism allows different classes to share the same method name, but each class implements that method in a specific way. This allows for treating different objects uniformly, making the code more flexible and adaptable.

OOP in ASP.NET Core

ASP.NET Core uses the C# programming language, which is an object-oriented language and has all the necessary features to implement the four principles of OOP.

Next, we will create a simple ASP.NET Core application and implement each of these principles.

Prerequisites

To create the example application, you need to have installed a recent version of .NET. Version 7 will be used in the post, but .NET 8 is now available.

You also need an Integrated Development Environment (IDE). This post will use Visual Studio Code, which can be used on Windows, macOS or Linux.

The source code of the application can be accessed here: LibraryManager source code.

The example application will be a Web API to manage books in a library. To create the base of the application, use the command below in the IDE terminal:

dotnet new web -o LibraryManager

Implementing the Abstraction

Since our application is a library, the perfect example of an abstraction is a book—it’s a real-life object, with associated attributes and actions, that we will replicate in code.

We will define a class called “Book” as the main entity of the application. In C#, a class is a data structure that can contain data members and function members like properties, methods and events, among others.

Usually, classes created to represent entities are called “Model” classes, and by convention, they are located inside a folder called “Models” or “Entities.”

So, in the root of the project create a new folder called “Models” and inside it add the class below:

  • Book
namespace LibraryManager.Models;

public class Book
{
  public Guid Id { get; set; }
  public string? Title { get; set; }
  public string? Author { get; set; }
  public string? Gender { get; set; }
  public DateTime ReleaseDate { get; set; }
}

Note that in the Book class created above, we are abstracting the Book entity that has the same properties as the real-life book, such as title, author, gender and release date.

oop abstraction shows a book, a real-life object, abstracted in code as a class with properties title, author, gender, release date

Implementing Encapsulation

Encapsulation in OOP means hiding the internal details of a class and allowing controlled access to its members (attributes and methods) through access modifiers. C# has the following access modifiers:

  • public: Public members are accessible from anywhere, both inside and outside the class.
  • private: Private members are accessible only within the class in which they were declared.
  • protected: Protected members are accessible within the class that declares them and in derived classes (subclasses).
  • internal: Internal members are accessible within the same assembly (.dll or .exe file).
  • protected internal: This combination allows access within the same assembly and also in derived classes, even if they are in different assemblies.

To implement encapsulation in the application, let’s create a class to add some methods. Still inside the “Models” folder, create a new class called “Library” and put the code below in it:

using System.Text.Json;

namespace LibraryManager.Models;

public class Library
{
    private List<Book> books;
    private readonly string libraryFilePath;

    public Library(string libraryFilePath)
    {
        this.libraryFilePath = libraryFilePath;
        LoadData();
    }

    private void LoadData()
    {
        if (File.Exists(libraryFilePath))
        {
            string jsonData = File.ReadAllText(libraryFilePath);
            books = JsonSerializer.Deserialize<List<Book>>(jsonData);
        }
        else
            books = new List<Book>();
    }

    private void SaveData()
    {
        string jsonData = JsonSerializer.Serialize(books);
        File.WriteAllText(libraryFilePath, jsonData);
    }

    public void AddBook(Book book)
    {
        if (book is EBook ebook)
            books.Add(ebook);
        else
            books.Add(book);
            
        SaveData();    
    }

    public void RemoveBook(Guid bookId)
    {
        Book book = books.FirstOrDefault(b => b.Id == bookId);
        if (book != null)
        {
            books.Remove(book);
            SaveData();
        }
    }

    public IEnumerable<Book> GetBooks()
    {
        return books;
    }
}

Note that in the above code, we are declaring several access modifiers, in local variables (books and filePathBook) and methods (LoadData(), AddBook(), etc.).

The LoadData() and SaveData() methods are declared as private because there is no need to access them externally. Instead, they are accessed only by the class that implements them. In contrast, the methods AddBook(), RemoveBook() and GetBooks() are declared as public, as they need to be accessed by external members.

In this way, we are implementing the principle of encapsulation, through access modifiers.

oop encapsulation diagram shows external member is able to access public methods, but not private ones. Private methods can only be accessed by members of the class where it is implemented.

Implementing Inheritance

The concept of inheritance in OOP refers to the fact that objects can inherit characteristics and behaviors from other objects.

To implement inheritance in the application, let’s create a new model class called “EBook” that will have all the characteristics of the “Book” class plus two exclusive properties of the book’s digital format. In this case, the “EBook” class will “inherit” from “Book” class.

Inside the “Models” folder, create a new class called “EBook” and put the code below in it:

public class EBook : Book
{
  public string? Format { get; set; }
  public double SizeInMB { get; set; }
}

To implement inheritance in C#, we put a colon in front of the class that will receive the inheritance (EBook). And after the colon, we put the class that will be inherited (Book), as you can see in the code above. In this way, the EBook class has the same properties as the Book class, such as ID, Title, Author, etc.

oop inheritance shows that the Ebook class inherits the properties of the Book class

Implementing Polymorphism

Polymorphism allows methods to be implemented by different classes and in different ways, which facilitates reuse and code organization.

In this example, we have two main entities, the “Book” class and the “EBook” class. So far, we’ve only created methods for the “Book” class. Through polymorphism, we can reuse the methods of the Book class for the EBook class.

To do this, add the following code in the “Library” class:

public IEnumerable<EBook> GetEBooks()
{
  return books.OfType<EBook>();
}

In the example above, the GetEbooks() method returns only the EBooks present in the library, using the OfType<Ebook>() method. This is possible thanks to polymorphism, which allows treating derived objects (such as EBook) as base objects (such as Book), as long as inheritance is correctly configured.

oop polymorphism deomonstrated with the line return books OfType Ebook. This treats derived objects as base objects

Running the Application

Now that we understand the concepts of the four pillars of OOP, let’s run the application and see in practice how the code we built is fully functional.

So first install the Swagger NuGet packages via the terminal by running the commands below:

dotnet add package Microsoft.OpenApi
dotnet add package Swashbuckle.AspNetCore

Finally, in the “Program.cs” file, replace the existing code with the code below:

using LibraryManager.Models;

var filePath = "book.json"; // Specify the path to JSON file

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddSingleton<Library>(_ => new Library(filePath));

var app = builder.Build();
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.MapGet("/books", (Library library) =>
{
    var books = library.GetBooks();
    return Results.Ok(books);
});

app.MapGet("/books/{id}", (Guid id, Library library) =>
{
    var book = library.GetBooks().FirstOrDefault(b => b.Id == id);
    if (book == null)
        return Results.NotFound();
    return Results.Ok(book);
});

app.MapPost("/books", (Book book, Library library) =>
{
    library.AddBook(book);
    return Results.Created($"/books/{book.Id}", book);
});

app.MapDelete("/books/{id}", (Guid id, Library library) =>
{
    library.RemoveBook(id);
    return Results.NoContent();
});

app.Run();

Now, run the command dotnet run in the application terminal. Then in your browser access: http://localhost:5202/swagger/index.html.

That way you can execute the CRUD functions and see that they are working perfectly as shown in the GIF below:

Running the app

You can use this JSON example to perform the POST request:

{
  "id": "c1d1a1b1-5678-1234-9abc-567890123456",
  "title": "The Great Gatsby",
  "author": "F. Scott Fitzgerald",
  "gender": "Classic",
  "releaseDate": "1925-04-10T00:00:00"
}

It is important to note that in this example scenario, we are using a JSON file that will store the data. In this case, the books.OfType<EBook>(); method will not work, as the JSON deserializer cannot distinguish a sub-class (EBook) from the base class (Book). For this to work, you need to use an ORM like EF Core or Dapper and implement a repository that accesses the database.

As the purpose of the post is to demonstrate the use of OOP, a database scenario will not be covered, but if you wish, you can use this post: Building a CRUD API with Dapper to implement the connection to a real database.

Going Beyond the Basics

In addition to the four pillars of OOP, ASP.NET Core has some elements essential for object-oriented development.

OOP ASP.NET Core: Interfaces, constructors and destructors, methods and properties, static classes, namespace, object-oriented design patterns

  • Interfaces

Interfaces define contracts that classes must implement. They let you define a common set of methods that different classes can implement in different but compatible ways.

Example:

public interface ILibraryService
{
 public List<Book> FindAllBooks();
}
  • Methods and Properties

In ASP.NET Core, methods and properties are used to define the behavior and characteristics of classes. Methods perform actions, and properties provide access to internal data.

Example:

//Method 
public void AddBook(Book book)
    {
        if (book is EBook ebook)
            books.Add(ebook);
        else
            books.Add(book);
            
        SaveData();    
    }

//Properties
public Guid Id { get; set; }
public string? Title { get; set; }
public string? Author { get; set; }
  • Constructors and Destructors

Constructors are unique methods used to initialize objects when they are created. In contrast, destructors are used to release resources associated with an object when it is destroyed.

Example:

//Constructor
public class Library
{
    private List<Book> books;
    private readonly string libraryFilePath;

    public Library(string libraryFilePath)
    {
        this.libraryFilePath = libraryFilePath;;
    }
}

//Destructor
~Library()
{
     _ = this.libraryFilePath;
}
  • Static Classes

Static classes contain static members that can be accessed without creating an instance of the class. This is useful for providing shared functionality across the entire application.

Example:

public static class Helper
{
    public static string ValidateBookName(string bookName)
    {
        if (string.IsNullOrEmpty(bookName))
            return "Error: Book name is mandatory";
        else
            return string.Empty;
    }
}
  • Namespace

Namespaces are used to organize and group related classes into a hierarchy. They help to avoid name conflicts and to modularize the code.

Example:

namespace LibraryManager.Models;
  • Object-Oriented Design Patterns

ASP.NET Core often employs object-oriented design patterns such as MVC (Model-View-Controller) to separate business logic, presentation and user interaction.

Example:

MVC Pattern- library manager includes folders for controllers, models, views

Conclusion

Object orientation is a paradigm that allows developers to create robust and modular applications, facilitating scalability and maintenance.

ASP.NET Core uses the C# programming language, which implements the four paradigms of OOP (abstraction, encapsulation, inheritance and polymorphism) in addition to others such as interfaces, constructors, methods and object-oriented design patterns.

In this blog post, we saw how to implement each of the four OOP paradigms in an ASP.NET Core application and how these paradigms relate to each other.

Whenever creating an application or functionality, consider using OOP resources.


assis-zang-bio
About the Author

Assis Zang

Assis Zang is a software developer from Brazil, developing in the .NET platform since 2017. In his free time, he enjoys playing video games and reading good books. You can follow him at: LinkedIn and Github.

Related Posts

Comments

Comments are disabled in preview mode.