Using Entity Framework in Console Application

In this post, we shall learn how to use Entity Framework in a Console application in the .NET Core. We shall scaffold the existing database and then leverage Generic HostBuilder to register the DBContext objects in the IoC container and then use it to perform CRUD operation on the database.

We shall also see consuming DBContext objects without Dependency injection (DI).

Today in this article, we will cover below aspects,

We already looked at how to Use a generic host builder for Dependency injection in .NET Core console applications. 

Let’s look into how to use generic HostBuilder to create DI Container and inject the required dependency within the Console app .NET Core application.

Getting started

Here I am using .NET Core 3.1 Console application,

Similar to the already discussed article in the previous post on DI here is the project structure we shall be dealing with is same. I shall be using the same sample and performing DI but we will be using .NET Core 3.1.

The early structure will give you an idea of what we will achieve towards the end of this article.

For complete sample code for the above application kindly refer below article,

Creating Generic HostBuilder

The HostBuilder class is available from the following namespace,

using Microsoft.Extensions.Hosting;

HostBuilder implements the IHostBuilder interface.

Please install the NuGet package from Nuget Package manager or PMC,

PM> Install-Package Microsoft.Extensions.Hosting -Version 3.1.1

Create DI Container and Initialize Host

Please create Generic HosBuilder and register the dependencies that need to inject. These changes can be implemented in the Main() method.

 var builder = new HostBuilder()
                .ConfigureServices((hostContext, services) =>
                {

                     services.AddLogging(configure => configure.AddConsole())
                     .AddTransient<MyApplication>()
                     .AddScoped<IBusinessLayer, BusinessLayer>()
                     .AddSingleton<IDataAccessLayer, CDataAccessLayer>()
                     .AddDbContext<EmployeeContext>(options =>
                     {
                         options.UseSqlServer("Server=localhost\\SQLEXPRESS;Database=master;Trusted_Connection=True;");
                     });
                }).UseConsoleLifetime();

            var host = builder.Build();

MyApplication class as the entry point for all business functionalities.

EmployeeContext is generated using EntityFrameworkCore scaffolding tool which is discussed below.

We shall be consuming EmployeeContext within DataAccess Layer but if you don’t have another module, you can use it using Constructor injection in any class of your choice.

Creating EmployeeContext using EFCore Tools

EFCore Package Manager Console Tool can be installed by using below Nuget package within the project directory,

PM> Install-Package Microsoft.EntityFrameworkCore.Tools
blank

Please install below additional Nuget packages in the application,

  • “Microsoft.EntityFrameworkCore”
  • “Microsoft.EntityFrameworkCore.Design”
  • “Microsoft.EntityFrameworkCore.SqlServer”

Create Scaffolding for Database

Below is the database schema we shall be using for performing CRUD operation,

blank

blank

Use the below commands to scaffold the database as below

PM>  Scaffold-DbContext  "Server=localhost\SQLEXPRESS;Database=master;Trusted_Connection=True;"  Microsoft.EntityFrameworkCore.SqlServer 

The above commands shall add all the required scaffolding including DbContext and model entities to the applications.

You can Create the scaffolding for one or multiple tables depending on the requirements.

Using EmployeeContext within Repository or Data Access Layer

EmployeeContext can be initialized within the Data Access Layer using Constructor injections.

Below shows a Create method where we are inserting a record to the database. On a similar line, you can add other CRUD methods as required.

 public class CDataAccessLayer : IDataAccessLayer
    {
        private readonly ILogger _logger;
        private readonly EmployeeContext _employeeContext;

        public CDataAccessLayer()
        {
        }

        public CDataAccessLayer(ILogger<CDataAccessLayer> logger, EmployeeContext context)
        {
            _logger = logger;
            _employeeContext = context;
        }

        public void Create(EmployeeDb employeeDB)
        {
            try
            {
                _logger.LogInformation("DataAccessLayer {DataAccessLayerEvent} at {dateTime}", "Started", DateTime.UtcNow);

                //Perform CRUD operation here

                _employeeContext.EmployeeDb.Add(employeeDB);
                _employeeContext.SaveChangesAsync();

                _logger.LogInformation("DataAccessLayer {DataAccessLayerEvent} at {dateTime}", "Ended", DateTime.UtcNow);

            }
            catch (Exception ex)
            {
                //Log technical exception 
                _logger.LogError(ex.Message);
                string error = ex.Message;
                //Return Business exception repsponse here
                throw new Exception("Error Invalid oepration performed {error}");

            }

        }
}

Initialize the CreateScope

Please add below code in the Main() method,

 using (var serviceScope = host.Services.CreateScope())
            {
                var services = serviceScope.ServiceProvider;

                try
                {
                    var myService = services.GetRequiredService<MyApplication>();
                    await myService.Run();

                    Console.WriteLine("Success");
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Error Occured");
                }
            }

Below is the class MyApplication executing the business workflow.

We are injecting logger and business objects as defined and registered in the scope using the HostBuilder DI container.

public class MyApplication
    {
        private readonly ILogger _logger;
        private readonly IBusinessLayer _business;
        public MyApplication(ILogger<MyApplication> logger, IBusinessLayer business)
        {
            _logger = logger;
            _business = business;
        }

        internal async Task Run()
        {
            _logger.LogInformation("Application {applicationEvent} at {dateTime}", "Started", DateTime.UtcNow);

            _business.PerformBusiness();

            _logger.LogInformation("Application {applicationEvent} at {dateTime}", "Ended", DateTime.UtcNow);

            Console.WriteLine("PRESS <ENTER> TO EXIT");
            Console.ReadKey();
        }
    }

Using DBContext without Dependency Injection

Above IoC usage of DBContext takes care of creating DBContext as and when needed. Framework based IoC containers also dispose of those objects when their usage is done.

If you do not want to use DI, it pretty straight forward to use DBContext anywhere in the project.

In fact, EmployeeContext becomes accessible in your module by adding below the line of code. Please add the required using references.

blank

Let’s execute the application and capture the event and action,

blank

That’s all! Happy coding

Summary

In this post, we learned how to use Entity Framework Core in a Console application in the .NET Core. We learned how to scaffold the existing database and then leverage Generic HostBuilder to register the DBContext objects in the IoC container. We also looked at how to use DBContext objects in a Console application without Dependency Injection.



Please bookmark this page and share it with your friends. Please Subscribe to the blog to receive notifications on freshly published(2024) best practices and guidelines for software design and development.



2 thoughts on “Using Entity Framework in Console Application

  1. Hi,

    I’ve tried creating a scope to resolve a concurrency issue with the DbContext in “MyApplication”, but it still has the same issue with collisions in the context as it’s not thread safe.

    Am I right in saying that I would need to create a scope per thread? I would require quite a restructure of my app to make that change so that’s why I haven’t tested it yet!

    Cheers
    Dave

    1. Hey Dave- Thanks for your query. Please make sure services that use DBCOntext vis DI also has the same lifespan as of DBContext or vice versa. Yes, DBContext is not thread-safe and an instance can be used per scope as per my understanding by proper lifespan using DI. Would be a great help if you can update once you are able to resolve the issue with the approach you following .References

Leave a Reply

Your email address will not be published. Required fields are marked *