DEV Community

Cover image for How to Load and Save Images in Blazor Image Editor with SQL Server
Calvince Moth for Syncfusion, Inc.

Posted on • Originally published at syncfusion.com on

How to Load and Save Images in Blazor Image Editor with SQL Server

TL;DR: Learn how to load, edit, and save images in a Blazor application using the Blazor Image Editor, a Web API endpoint, and SQL Server for persistent storage. This guide walks through database setup, EF Core modeling, API integration, and using the Image Editor to round‑trip images between the UI and backend.

Many Blazor applications need to store and manage user‑uploaded images such as profile photos, documents, gallery items, product pictures, and more. Developers often struggle with:

  • Converting images to database-friendly formats.
  • Moving image bytes between a Web API and the UI.
  • Persisting edited images.
  • Reopening images in a client-side editor.
  • Handling base64, byte arrays, and stream conversions.

This article shows how to store images as binary data in SQL Server LocalDB, retrieve them with C# and EF Core, and load them into the Syncfusion® Blazor Image Editor for editing. The Syncfusion Blazor Image Editor provides built‑in tools for rotating, flipping, zooming, cropping, and annotating images with text, drawings, and shapes. It also includes filters, fine-tuning controls, keyboard shortcuts, and touch-optimized interactions, making it a complete image-editing component for Blazor.

For storage, SQL Server supports BLOB data through types like VARBINARY(MAX), the recommended option since the older IMAGE type is deprecated.

Let’s get started!

Creating a Blazor application

First, create a Blazor WebApp project and install the following NuGet packages in the project, as these packages are prerequisites for connecting to the database:

  • EntityFramework
  • Microsoft.EntityFrameworkCore
  • Microsoft.EntityFrameworkCore.SqlServer

Creating a database in SQL LocalDB

To create the database for the application, follow these steps:

  1. Open SQL Server Object Explorer: In Visual Studio, go to the View menu and select SQL Server Object Explorer.
  2. Create a new database: In SQL Server Object Explorer, locate the LocalDB server (you may need to expand the node). Right-click on Databases and select Add New Database. Name the new database ImageDB and click OK.
  3. Create a new table in ImageDB: Expand the ImageDB database. Right-click on Tables and select Add New Table.
  4. Define the table schema: Add a new table named ImageCollections with:
Column Type Notes
Id NVARCHAR(50) Primary identifier
Name NVARCHAR(50) Original file name
ImageData VARBINARY(MAX) Image bytes
  1. Save the table using the Update button. This structure stores both metadata and the full image content.

<alt-text>


ImageCollections table schema

<alt-text>


Sample data stored inside the table

Connecting the database to the application

The ImageCollections table in the ImageDB database stores our image records. To connect the Blazor application to this database, copy the connection string from the ImageDB database properties and add it to the appsettings.json file.

Here’s how you can do it in code:

{
    "AllowedHosts": "*",
    "ConnectionStrings": {
        "ImageDbContext": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=ImageDB;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False"
    }
}
Enter fullscreen mode Exit fullscreen mode

Next, create a model class named CustomImageData in the Shared project to represent image data. The class should include properties such as Id for a unique identifier, Name for the image name, Description for a brief description, and ImageData as a byte array to store the image data.

Add this class definition to your project:

public class CustomImageData
{
    public string Id { get; set; }
    public string Name { get; set; }
    public byte[] ImageData { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

Create a DbContext class named ImageDbContext in the Data folder of the Server project. This class should include a DbSet property named ImageCollections that corresponds to the table name in the database, as shown in the code example below.

public class ImageDbContext : DbContext
{
    public ImageDbContext(DbContextOptions<ImageDbContext> options)
        : base(options)
    {
    }

    public DbSet<CustomImageData> ImageCollections { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

At last, register the ImageDbContext in the Program.cs file of the Server project.

// ….
builder.Services.AddControllersWithViews();
builder.Services.AddDbContext<ImageDbContext>(options =>
    options.UseSqlServer(
        builder.Configuration.GetConnectionString("DefaultConnection")
    )
);

// ….
Enter fullscreen mode Exit fullscreen mode

Creating an API Controller

To access and update image data in the database, create an API controller in the Controllers folder of the Server project. Add a new controller class named ImagesController.

This controller exposes two endpoints for managing image data.

  • The GET endpoint (api/Images/{id}) retrieves an image from the ImageCollections table using its unique identifier and returns a NotFound response if the record does not exist.
  • The PUT endpoint uses the same route to update an existing image with the data provided in the request body. If a matching record is found and the IDs match, the image data is updated and saved; otherwise, a new record is added to the database.

Try this in your project:

using Microsoft.AspNetCore.Mvc;
using BlazorAppDB.Data;
namespace BlazorAppDB.Controller;
{
    [Route("api/[controller]")]
    [ApiController]
    public class ImageController : ControllerBase
    {
        private readonly ImageDbContext _dbContext;

        public ImageController(ImageDbContext dbContext)
        {
            _dbContext = dbContext;
        }

        [HttpPost]
        public IActionResult SaveImage([FromForm] string id, [FromForm] IFormFile imageFile)
        {
            if (string.IsNullOrEmpty(id) || imageFile == null || imageFile.Length == 0)
            {
                return BadRequest("Invalid input");
            }

            using (var memoryStream = new MemoryStream())
            {
                // Copy the uploaded file's content into the memory stream
                imageFile.CopyTo(memoryStream);

                // Convert the memory stream into a byte array
                byte[] imageBytes = memoryStream.ToArray();

                // Check if the image already exists
                var existingImage = _dbContext.ImageCollections.FirstOrDefault(i => i.Id == id);
                if (existingImage != null)
                {
                    // Update existing image
                    existingImage.Name = imageFile.FileName;
                    existingImage.ImageData = imageBytes;
                }
                else
                {
                    // Add new image
                    var imageRecord = new CustomImageData
                    {
                        Id = id,
                        Name = imageFile.FileName,
                        ImageData = imageBytes
                    };
                    _dbContext.ImageCollections.Add(imageRecord);
                }

                _dbContext.SaveChanges();
                return Ok("Image saved successfully");
            }
        }

        [HttpGet("{id}")]
        public IActionResult LoadImage(string id)
        {
            var image = _dbContext.ImageCollections.FirstOrDefault(i => i.Id == id);
            if (image == null)
            {
                return NotFound("Image not found");
            }

            // Convert the byte array to a Base64 string
            var base64Image = Convert.ToBase64String(image.ImageData);
            return Ok(base64Image);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

To work with the API controller, set up the configuration below in the Program.cs file.

// ……
builder.Services.AddControllers();
builder.Services.AddControllersWithViews();
builder.Services.AddServerSideBlazor()
    .AddHubOptions(o =>
    {
        o.MaximumReceiveMessageSize = 102400000;
    });

// …..

app.UseRouting();
app.UseAntiforgery();
app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
});
Enter fullscreen mode Exit fullscreen mode

This article was originally published at Syncfusion.com.

Top comments (0)