Developing a Car Rental Console Application using SQL Server, Entity Framework Core, and C#

An excellent illustration of how various components of a.NET program interact is a car rental system. User identification, customer management, car availability, rental operations, database connectivity, validation, and session management are all included.

This post will examine how to use C#, Entity Framework Core, SQL Server, and a layered architecture to construct the essential components of a console-based car rental application.

The application divides duties across several tiers. Repositories manage database operations, services execute business logic, and Entity Framework Core facilitates communication with SQL Server.

The application supports features such as:

  • User registration and login
  • Customer management
  • Vehicle management
  • Vehicle rental
  • Vehicle return
  • Rental validation
  • Session management
  • Email sending
  • Entity Framework Core migrations
  • SQL Server database connectivity
  • Console-based menus

Application Architecture

The application follows a layered structure:

The main responsibilities of the layers are:

LayerResponsibility
Console/UIDisplays menus and receives user input
BLLContains application and business rules
DALHandles database operations
Entity Framework CoreMaps C# objects to database tables
SQL ServerStores application data
SharedContains common models, enums, and result objects
UtilitiesContains reusable validation and helper functionality

This separation makes it easier to maintain the application because each layer has a specific responsibility.

Installing Entity Framework Core Packages

The first step is to install the Entity Framework Core packages required by the application.

Using the Package Manager Console, run:

The packages are used for different purposes.

  • Microsoft.EntityFrameworkCore provides the core EF Core functionality.
  • Microsoft.EntityFrameworkCore.SqlServer provides SQL Server support.
  • Microsoft.EntityFrameworkCore.Tools provides commands such as Add-Migration and Update-Database.
  • Microsoft.EntityFrameworkCore.Design provides design-time functionality required by EF Core tooling.

Reading the Database Connection from appsettings.json

Instead of placing the SQL Server connection string directly inside the DbContext, the application can store it in appsettings.json.

The configuration-related packages can be installed using:

The connection string should contain placeholders when publishing an article.

Never publish real database credentials in source code or an article.

The DefaultConnection name is later used by the DbContext to retrieve the connection string.

Creating the AppDbContext

The AppDbContext class inherits from DbContext and represents the database session used by Entity Framework Core.

Each DbSet<T> represents an entity that Entity Framework Core maps to a database table.

For example:

allows the application to query and manage vehicle records through Entity Framework Core.

Configuring Entity Relationships

The application contains relationships between users, customers, vehicles, and rentals.

These relationships can be configured in the OnModelCreating() method.

There are three important relationships here.

User and Customer

A user has a corresponding customer record, creating a one-to-one relationship.

The UserId property is used as the foreign key in the Customer entity.

Customer and Rental

A customer can have multiple rental records.

This creates a one-to-many relationship.

Vehicle and Rental

A vehicle can be associated with multiple rental records over time.

DeleteBehavior.Restrict prevents related records from being automatically deleted when a referenced record is deleted.

Adding Seed Data

Entity Framework Core can also insert initial data into the database through HasData().

For example:

For demonstration purposes, seed data can be useful during development.

However, passwords should never be stored as plain text in a real application. Passwords should be securely hashed before being stored in the database.

Vehicle records can also be seeded:

Creating the Database with EF Core Migrations

Once the DbContext and entities are configured, create the initial migration using:

The migration contains the database schema changes detected by Entity Framework Core.

To apply the migration to SQL Server, run:

This creates or updates the database based on the migration.

The basic workflow is:

Managing User Sessions

Because this is a console application, the application uses a simple session manager to keep track of the currently logged-in user.

When login succeeds, the current user is stored in CurrentUser.

When the user logs out, the value is set to null.

The IsLoggedIn() method can then be used to determine whether the user has an active session.

For a simple console application this approach is straightforward. It should not be treated as a replacement for a proper authentication and authorization mechanism in a web or distributed production application.

Validating Email and Password

The application uses a regular expression to perform basic email validation.

The email validation checks whether the value is empty and whether it follows the expected email pattern.

The password validation in this example only checks whether the password is empty. A production application should use stronger password requirements and secure password hashing.

Creating a Result Wrapper

The application uses a generic Result<T> class to return both the operation status and the associated data.

This provides a consistent structure for service responses.

For example:

Instead of returning only a Boolean value, the service can also provide a meaningful message.

Implementing User Services

The UserServices class contains the business logic related to vehicle rentals and returns.

It depends on repositories for vehicles, customers, and rentals.

The service does not directly perform database queries. Instead, it communicates with repository classes.

This keeps database access separate from business rules.

Getting Available Vehicles

The service can retrieve vehicle records through the vehicle repository.

The method returns a Result<List<Vehicle>>, allowing the caller to determine whether the operation succeeded and retrieve the vehicle list.

If the repository is intended to return only vehicles with available units, that filtering should be implemented explicitly in the repository query.

Renting a Vehicle

The RentVehicleAsync() method contains the main business rules for renting a vehicle.

First, the number of rental days is validated.

Next, the current user is retrieved from the session.

If the customer does not exist, the operation stops.

The selected vehicle is then retrieved.

The application also checks whether the vehicle has available units.

The service then checks the customer’s active rental count.

It also prevents the customer from renting the same vehicle while an existing rental is active.

Once all validations pass, the rental amount is calculated.

A new Rental object is then created.

The available vehicle count is reduced by one:

Finally, both the rental and vehicle are updated.

The method returns a successful result:

Returning a Vehicle

The ReturnVehicleAsync() method handles the return process.

First, the rental is retrieved.

The application then checks whether the rental is still active.

The rental is marked as returned.

The associated vehicle is retrieved and its available unit count is increased.

Finally, the rental record is updated.

This keeps the rental status and vehicle availability synchronized.

Viewing Customer Rentals

The current customer’s rentals can be retrieved using the session information.

The current user’s ID is obtained from SessionManager, and the corresponding customer record is then used to retrieve rental history.

Creating the Console Menu

The Program.cs file controls the main application flow.

The application first checks whether a user is logged in.

For users who are not logged in, the application provides options such as login, registration, and quitting the application.

After successful authentication, the application can display different options based on the user’s role.

A regular user can access operations such as:

An administrator can be provided with administrative operations according to the application’s requirements.

Adding Console UI Packages

The application can use Spectre.Console for a more structured console interface.

Install it using:

For example:

The package can also be used to create selection menus.

This provides a menu-based interface instead of requiring the user to enter numeric choices manually.

Sending Email Notifications

The application defines an interface for email sending:

An implementation can use SMTP to send the email.

For example:

Credentials should never be hard-coded in source code. In a real application, SMTP settings should be stored securely using configuration, environment variables, or a suitable secret-management solution.

Application Workflow

The main vehicle rental workflow can be summarized as follows:

  1. Start the console application.
  2. Display the public menu.
  3. Register a new user or log in.
  4. Store the authenticated user in the session manager.
  5. Display user-specific options.
  6. Retrieve available vehicles from the database.
  7. Select a vehicle and rental duration.
  8. Validate the rental request.
  9. Create a rental record.
  10. Reduce the available vehicle count.
  11. Return the vehicle when the rental is completed.
  12. Update the rental status.
  13. Increase the vehicle’s available unit count.
  14. Log out when the session is finished.

Important Production Considerations

The supplied implementation demonstrates the core application flow, but some areas require additional work before using a similar design in a production system.

Password Security

Passwords should never be stored as plain text. Use a secure password hashing mechanism and never include real passwords in seed data or source control.

Database Transactions

The rental operation changes more than one piece of data. Both the rental record and vehicle availability should be updated consistently. A database transaction can be considered to prevent one operation from succeeding while the other fails.

Connection String Security

Database usernames and passwords should not be committed to source control or published in articles.

Authorization

Checking whether a user is an administrator should be backed by proper authorization rules at the service or application boundary.

Error Handling

The current examples primarily handle expected validation failures. Production applications should also handle database exceptions, connection failures, and unexpected errors.

Date and Time Handling

The example uses DateTime.Now. Applications that operate across different time zones should consider a consistent date and time strategy, such as storing UTC timestamps where appropriate.

Common Problems and Troubleshooting

Migration Command Is Not Recognized

Make sure the Entity Framework Core tools package is installed:

Then rebuild the project and run:

Connection String Not Found

Verify that:

  • appsettings.json exists.
  • The file is copied to the application’s output directory when required.
  • The connection string is named DefaultConnection.
  • The connection string contains valid database settings.

Database Connection Fails

Check the SQL Server instance name, database name, authentication credentials, and network connectivity.

Vehicle Availability Becomes Incorrect

Rental and return operations update AvailableUnits. These changes should be performed consistently and, for concurrent applications, should be protected against conflicting updates.

Advantages

This architecture provides several benefits:

  • Separates business logic from database access.
  • Makes the application easier to maintain.
  • Uses Entity Framework Core for database operations.
  • Provides reusable service and repository classes.
  • Supports asynchronous database operations.
  • Centralizes session information.
  • Provides reusable result objects.
  • Allows the console interface to be changed without moving business rules into the UI layer.

Disadvantages

There are also some limitations:

  • The current session manager is suitable mainly for a simple console application.
  • Direct object creation of repositories and services makes dependency injection more difficult.
  • Error handling needs to be expanded for production use.
  • Password handling needs stronger security.
  • Database transactions should be considered for operations that update multiple records.
  • Some validation is performed only at the application level and should also be enforced where appropriate at the database or service level.

Conclusion

A vehicle rental system is a useful example for understanding how a C# application can be divided into multiple layers. In this implementation, the console application handles user interaction, the business layer contains rental rules, repositories handle data access, Entity Framework Core communicates with SQL Server, and the session manager keeps track of the logged-in user.

The application also demonstrates several common .NET concepts, including Entity Framework Core migrations, database relationships, seed data, asynchronous methods, validation, generic result wrappers, and repository-based data access.

The implementation provides a foundation for a vehicle rental application. Before using the same approach in a production system, additional attention should be given to password hashing, secure configuration, authorization, transaction handling, error handling, and concurrency.

Recommendation for ASP.NET 10.0 Hosting

A solid base for developing online services and applications is ASP.NET. Before creating an ASP.NET web application, you must be proficient in JavaScript, HTML, CSS, and C#. There are thousands of web hosting providers offering ASP.NET hosting on the market. However, there are relatively few web hosting providers that offer top-notch ASP.NET hosting.

ASP.NET is the best development language in Windows platform, which is released by Microsoft and widely used to build all types of dynamic Web sites and XML Web services. With this article, we’re going to help you to find the best ASP.NET Hosting solution in Europe based on reliability, features, price, performance and technical support. After we reviewed about 30+ ASP.NET hosting providers in Europe, our Best ASP.NET Hosting Award in Europe goes to HostForLIFE.eu, one of the fastest growing private companies and one of the most reliable hosting providers in Europe.

You may also like...

Popular Posts

Skip to toolbar Log Out