Connecting C# to Oracle in .NET Blazor Using EF Core
Blazor is a modern frontend web framework built on HTML and C# designed to accelerate web application development. It empowers developers to create reusable, interactive components for visually stunning and highly functional web user interfaces.
Oracle Database is a robust, commercial relational database management system (RDBMS) developed by Oracle Corporation. It offers comprehensive SQL implementation, enterprise-grade scalability, and advanced security features. Being designed for mission-critical applications and large-scale enterprise deployments, it provides built-in high availability, performance optimization, and extensive management tools, making it a preferred choice for large organizations requiring industrial-strength database solutions.
Why dotConnect for Oracle?
dotConnect for Oracle is the ideal data provider for all Oracle-related operations. It provides features such as on-the-fly connector creation, flexible configuration, seamless integration with Visual Studio, and enhanced support for ORM frameworks.
Requirements
- Visual Studio 2022: our IDE of choice. If you do not have it on your computer, go to the official website to download and install it. We will be using the community version, so you can get it as well.
- Blazor: This is a feature of ASP.NET for building interactive web UIs using C# instead of JavaScript. It's real .NET running in the browser on WebAssembly.
- dotConnect for Oracle: a feature-rich ADO.NET provider with Entity Framework, NHibernate, and LinqConnect support.
Download and Activate dotConnect for Oracle
Download and install the trial version of dotConnect for Oracle from Devart's official website. No license key is required for the trial, and you can start exploring the product immediately.
Purchase and Access the Full Version
After purchasing the full version, log in to the Customer Portal and navigate to the Products page. You'll find a list of your licenses, including your dotConnect for Oracle purchase.
Click Details next to your dotConnect for Oracle license. Here, you'll find your license details, including the Activation Key.
Download the Full Version
Click Download product versions to access the list of available product versions. Select the most recent version and download the installer.
Run the downloaded file and follow the on-screen instructions to install dotConnect for Oracle on your computer. This process will install the software and activate all features associated with your license key.
Create a Blazor Web App Project
Open the Visual Studio and click Create New Project.
In the Search Template field, search for Blazor Web App and click it.
Name your project, select .NET 8 as the target framework, leave all the other options as the default values, and click Create; select .NET 8 as the target framework, leave all the other options as the default values, and then click Create.
Install Packages
We will install dotConnect for Oracle to our project via the NuGet Package Manager in Visual Studio. In the taskbar, click Tools, select NuGet Package Manager, and then click Manage NuGet Packages for Solution.
The NuGet Package Manager page opens. Click Browse, and search for Devart.Data.Oracle.EFCore, select your project, and then click Install.
Open the Package Manager Console and run this command:
Install-Package MicrosoftEntityFrameworkCore.Tools
This installs the necessary EFCore tools needed to run the application.
Run the application by pressing F5 to open the scaffolded web page.
Create a Connection Instance
Next, create a new folder called Models and add a new class called Actor.
The Actor class will have the following structure.
public class Actor { [Key] public int ActorId { get; set; } [Required] public string FirstName { get; set; } [Required] public string LastName { get; set; } [Required] public DateTime LastUpdate { get; set; } }
Next, we must scaffold our DBcontext to remain in the Models folder. Create a new class called ActorDbContext and copy this code into it.
public class ActorDbContext : DbContext { public ActorDbContext(DbContextOptions<ActorDbContext> options) : base(options) { } public DbSet<Actor> Actors { get; set; } }
Your project should look like this now.
CREATE Oracle Table
We will have to set up a few things to create a table based on the DbContext we have defined.
First, from your Blazor project, create a class named DataBaseConfiguration and copy the following code into it.
Public static class DataBaseConfiguration { public static string GetConnectionString() { string databasePath = $"Server=127.0.0.1:Port=1521;UserId=TesterUser;Password=TestPassword;Database=test_db; SID=XE;LicenseKey={LicenseKey.licenseKey};"; return databasePath; } }
DatabaseConfiguration has a singular method, GetConnectionString, which returns a concatenated string of the connection string of your Oracle database and the license key for your dotConnect for Oracle.
The Oracle connection string contains:
- Server
- Port
- UserId
- Password
- SID/ServiceName
- Database we created earlier.
PS: This approach is for tutorial purposes only. Ideally, you should store your activation key more securely, i.e., Environment Secrets. Remember to replace UserId and Password with your actual credentials.
Next, create a class called MyDbContextFactory and add the following code.
public class MyDBContextFactory : IDesignTimeDbContextFactory<ActorDbContext> { public ActorDbContext CreateDbContext(string[] args) { var optionsBuilder = new DbContextOptionsBuilder<ActorDbContext>(); string connectionString = DataBaseConfiguration.GetConnectionString(); optionsBuilder.UseOracle(connectionString); return new ActorDbContext(optionsBuilder.Options); }
The MyDbContextFactory class is implementing the IDesignTimeDbContextFactory
So far, your project should look like this.
In Program.cs add these two lines of code so your project knows the correct Database String to reference.
string connectionString = DataBaseConfiguration.GetConnectionString(); builder.Services.AddDbContext<ActorDbContext>(options => options.UseOracle(ConnectionString));
Now that everything has been set up let's create the first migration.
From the Package Manager console, run this piece of code.
Add-Migration InitialCreate -Context ActorDbContext
This command creates a Migrations folder in the project based on the current state of our ActorDbContext.
To finish this process and create the Actor table, we will have to update the database. So run the command below in the Package Manager console as well.
Update-Database
If all goes well, you should get a response like Applying migration 20240910145215_InitialCreate. This means our migration has been applied, and our Actor table has been created.
Before we move on, let's create a Services folder that will act as the hub for most of the business logic.
So, in the Services folder, create an Interface called IActorService and add the following code.
public interface IActorService { Task<List<Actor>> GetActorsAsync(); Task<Actor> GetActorByIdAsync(int actorId); Task AddActorAsync(Actor actor); Task UpdateActorAsync(Actor actor); Task DeleteActorAsync(int actorId); }
Then, still in the Services folder, create a new class to implement that interface. Call it ActorService and copy the following code.
public class ActorService : IActorService { private readonly ActorDbContext _context; public ActorService(ActorDbContext context) { _context = context; } public async Task<List<Actor>> GetActorAsync() { return await _context.Actors.ToListAsync(); } public async Task<Actor> GetActorByIdAsync(int actorId) { var actor = await _context.ActorsFindAsync(actorId); if (actor == null) { throw new Exception("Actor not found"); } return actor; } public async Task AddActorAsync(Actor actor) { actor.LastUpdate = DateTime.Now; _context.Actors.Add(actor); await _context.SaveChangesAsync(); } public async Task UpdateActorAsync(Actor actor) { actor.LastUpdate = DateTime.Now; _context.Entry(actor).State = EntityState.Modified; await _context.SaveChangesAsync(); } public async Task DeleteActorAsync(int acorId) { var actor = await _context.Actors.FindAsync(actorId); if (actor) != null) { _context.Actors.Remove(actor); await _context.SaveChangesAsync(); } } }
Register the interface and its implementation by adding the following code to Program.cs.
builder.Services.AddScoped<IActorService,ActorService>();
INSERT Oracle Data
Let's insert some data into our Actor table. Go to the Components folder in your project, navigate to the Pages folder, and create a Razor Component. Next, call this razor component Actor.Razor.
In the Actor.Razor page, add the following piece of code.
@page "/actor" @rendermode InteractiveServer @inject NavigationManager Navigation <h3>Actor</h3> <button class="btn btn-primary" @onclick="OpenAddActorModal">Add New Actor</button> @code { private void OpenAddActorModal() { Navigation.NavigateTo("/add-actor"); } }
We have created a button that navigates to an add-actor page. So, let's create that.
From the Pages folder under components, add another Razor component called AddActor.Razor and copy this piece of code into it.
@page "/addactor" @rendermode InteractiveServer @using OracleBlazor.Models @inject OracleBlazor.Services.IActorService ActorService @inject NavigationManager Navigation <h3>Add New Actor</h3> <div class=mb-3> <label for=firstName" class="form-label">First Name</label> <input type="text" class="form-control" id="firstName" @bind="newFirstName" /> <div> <div class="mb-3"> <label for="lastName" class="form-label">Last Name</label> <input type="text" class="form-control" id="lastName" @bind="newLastName" /> </div> <button class="btn btn-secondary" @onclick="Cancel">Cancel</button> <button class="btn btn-primary" @onclick="InsertActor">Save</button> @code { private string newFirstName; private string newLastName; private async Task InsertActor() { var newActor = new OracleBlazor.Actor { FirstName = newFirstName, LastName = newLastName, LastUpdate = DateTime.UtcNow }; await ActorService.AddActorAsync(newActor); Navigation.NavigateTo("/actor"); } private void Cancel() { // Close the modal and navigate back to the actor page Navigation.NavigateTo("/actor"); } }
We'll need to add the previous Actor component to the Nav bar to see it.
Navigate to the Components folder, and in the Layouts folder, select NavMenu.Razor.
Replace the code in NavMenu with the one below.
<div class="top-row ps-3 navbar navbar-dark"> <div class="container-fluid"> <a class="navbar-brand" href="">OracleBlazor</a> </div> </div> <input type="checkbox" title="Navigation menu" class="navbar-toggler" /> <div class="nav-scrollable" onclick="document.querySelector('.navbar-toggler').click()"> <nav class="flex-column"> <div class="nav-item px-3"> <NavLink class="nav-link" href="" Match="NavLinkMatch.All"> <span class="bi bi-house-door-fill-nav-menu" aria-hidden="true"></span> Home </NavLink> </div> <div class="nav-item px-3"> <NavLink class="nav-link" href="actor"> <span class="bi bi-list-nested-nav-menu" aria-hidden="true"<>/span<Actors </NavLink> </div> </nav> </div>
Now, run the application, select Actors, and then click Add New Actor.
After adding a new actor and clicking Save, you will be redirected back to the Actor page.
READ Oracle Data
Let's modify our application to see the actor just created.
Replace the code in Actor.Razor with the one displayed below.
@page "/actor" @rendermode InteractiveServer @inject NavigationManager Navigation @inject OracleBlazor.Services.IActorService ActorService <h3>Actor Table</h3> @if (actors == null) { <p><em>Loading...</em></p> } else { <table class="table"> <thead> <tr> <th>ID</th> <th>First Name</th> <th>Last Name</th> <th>Last Update</th> </tr> </thead> <tbody> @foreach (var actor in actors) { <tr> <td>@actor.ActorId</td> <td>@actor.FirstName</td> <td>@actor.LastName</td> <td><actor.LastUpdate</td> </tr< } </tbody> </table> } <button class="btn btn-primary" @onclick="OpenAddActorModal">Add New Actor</button> @code { private List<OracleBlazor.Actor> actors; protected override async Task OnInitializedAsync() { // Load the actors when the component is initialized actors = await ActorService.GetActorsAsync(); } private void OpenAddActorModal() { Navigation.NavigateTo("/add-actor"); } }
Run the application and click Actors. As a result, you'll see the actor displayed.
UPDATE Oracle Data
Let's assume that Seth wants to change his last name. Our application should be able to handle that.
So, from the Pages folder, create a new razor component called Update.razor and add the following code to the file.
@page "/update/{actorId:int}" @rendermode InteractiveServer @using OracleBlazor.Models @inject OracleBlazor.Services.IActorService ActorService @inject NavigationManager Navigation <h3>Update Actor</h3> @if (actor == null) { <p><em>Loading...</em></p> } else { <div class="mb-3"> <label for="firstName" class="form-label">First Name</label> <input type="text" class="form-control" id="firstName" @bind="actor.FirstName" /> </div> <div class="mb-3"> <label for="lastName" class="form-label">Last Name</label> <input type="text" class="form-control" id="lastName" @bind="actor.LastName" /> </div> <button class="btn btn-secondary" @onclick="Cancel">Cancel</button> <button class="btn btn-primary" @onclick="UpdateActor">Save</button> @code { [Parameter] public int actorId { get; set; } private OracleBlazor.Actor actor; protected override async Task OnInitializedAsync() { // Load the actor to be updated actor = await ActorService.GetActorByIdAsync(actorId); } private async Task UpdateActor() { // Update the actor using the service await ActorService.UpdateActorAsync(actor); // Redirect back to the actor list page Navigation.NavigateTo("/actor"); } private void Cancel() { // Navigate back to the actor list page Navigation.NavigateTo("/actor"); } }
Next, in Actor.Blazor modify the Table element within the else block using the following code.
<table class="table"> <thead> <tr> <th>ID</th> <th>First Name</th> <th>Last Name</th> <th>Last Update</th< <th>Actions</th> </tr> </thead> <tbody> @foreach (var actor in actors) { <tr> <td>@actor.ActorId</td> <td>@actor.FirstName</td> <td>@actor.LastName</td> <td>@actor.LastUpdate</td> </td> <button class="btn btn-warning btn-sm" @onclick="() => NavigateToUpdate(actor.ActorId)">Update</button> </td> </tr> } </tbody> </table>
Then, in the @code Block, add this method.
private void NavigateToUpdate(int actorId) { Navigation.NavigateTo($"/update/{actorId}"); }
This will navigate to the page we've just created with the particular Actor ID.
Run the application and navigate to Actors.
Clicking Update opens the Update page with the particular actor, where you can modify its properties.
Click Save to apply the updates to the actor.
DELETE Oracle Data
Let's try to remove an actor from our database.
For reference, we have added a new actor, "Johnny Blaze," that we're going to remove.
In the Actor.Razor page, add the following line of code to the table, placing it below the Update button.
<button class="btn btn-danger btn-sm" @onclick="() => DeleteActor(actor.ActorId)">Delete</button>
Then, add this method to the @code block.
private async Task DeleteActor(int actorId) { await ActorService.DeleteActorAsync(actorId); actors = await ActorService.GetActorsAsync(); }
This method takes that particular actor ID and calls our DeleteActorAsync Service. Run the application and navigate to actors.
To proceed, click Delete to remove the selected actor.
Video tutorial: How to Connect .NET Blazor Application to Oracle Database
Conclusion
In this tutorial, we explored how to establish a connection between a Blazor application and an Oracle database using dotConnect for Oracle. Together, we walked through creating database tables, inserting data, retrieving records, and performing update and delete operations. Thus, the approach covered in this tutorial provides a firm basis for constructing agile, data-focused applications that utilize information and operate in harmony with Oracle databases.