File Upload in a Blazor Web Assembly Application using .Net 7

The previous post covered how to perform CRUD operations in a Blazor Web Assembly-based application. In that post, we create a comprehensive UI-based Employees component. In the demonstration, we saw how to populate the employee list, add new Employees, and perform other activities. The file uploader capability in the Blazor Web Assembly will be covered in this article. We will upload the employee profile picture-related file and then display that information in the Employee List and other associated segments.

Create a Database Structure to store Employee Profile Picture information

Before coding into the Blazor Application, we must implement the Database structure changes related to the employee profile pictures. So, related that create the below table in the database.

CREATE TABLE [dbo].[EmployeeProfilePics]
(
	[Id] [int] IDENTITY(1,1) NOT NULL,
	[EmployeeId] [int] NULL,
	[ImageType] [varchar](50) NULL,
	[Thumbnail] [text] NOT NULL,
	[ImageUrl] [varchar](200) NOT NULL,
	CONSTRAINT [PK_EmployeeProfilePics] PRIMARY KEY CLUSTERED ([Id] ASC) ON [PRIMARY],
	CONSTRAINT [FK_EmployeeProfilePics_Employees] FOREIGN KEY([EmployeeId]) REFERENCES [dbo].[Employees] ([Id])
)
GO

Add Employee Profile Image into the Employee Add/Update Operation

We have already created the Database structure to capture the Employee Profile Information. Now, we first need to make the related model class. So, Add a new class file called EmployeeProfilePic within the Model folder and add the below code into that file.

public class EmployeeProfilePic
{
    public int Id { get; set; }

    [ForeignKey("EmployeeId")]
    [Required]
    public int EmployeeId { get; set; }

    public string ImageType { get; set; }

    public string? Thumbnail { get; set; }

    public string? ImageUrl { get; set; }

    public virtual Employee? EmployeeInfo { get; set; }
}

Now, open the Employee.cs model class from the Model folder and add the below properties at the end related to capturing the profile file information.

[NotMapped]
public int? EmployeeProfilePicId { get;set; }

[NotMapped]
public string? thumbnail { get; set; }

[NotMapped]
public string? ImageType { get; set; }

Now, open the EmployeeInfo.razor component file. In that file, after the Phone, no Section, add the below file uploader-related code.

<div class="row mb-3">
     <label for="inputPhone" class="col-sm-2 col-form-label">Profile Image</label>
     <div class="col-sm-10">
         <InputFile class="form-control" id="empphone" hidden=@ReadOnlyMode OnChange="@OnInputFileChange" />
         <div>
             <img src="@Employee.thumbnail" height="200px" width="200px">
         </div>
     </div>
 </div>

Now, in the same EmployeeInfo.razor file, add the below code into the @code section related to reading the uploaded file, and convert the file information to base64 format.

private async Task OnInputFileChange(InputFileChangeEventArgs e)
{
    IBrowserFile imgFile = e.File;
    var buffers = new byte[imgFile.Size];
    await imgFile.OpenReadStream().ReadAsync(buffers);
    string imageType = imgFile.ContentType;
    string fileName = imgFile.Name;
    Employee.thumbnail = $"data:{imageType};base64,{Convert.ToBase64String(buffers)}";
    Employee.ImageType = imageType;
}

Now, open the EmployeeController.cs File and replace the SaveEmployee() related code with the below one.

[Route("SaveEmployee")]
[HttpPost]
public async Task<IActionResult> SaveEmployee(Employee employee)
{
    try
    {
        if (_dbContext.Employees == null)
        {
            return Problem("Entity set 'AppDbContext.Employee'  is null.");
        }

        if (employee != null)
        {
            _dbContext.Add(employee);
            await _dbContext.SaveChangesAsync();

            if (!string.IsNullOrEmpty(employee.thumbnail) && employee.Id>0)
            {
                EmployeeProfilePic employeeProfilePic = new EmployeeProfilePic();
                employeeProfilePic.Id = Employee.EmployeeProfilePicId > 0 ? (int) Employee.EmployeeProfilePicId : 0;
                employeeProfilePic.ImageType = Employee.ImageType;
                employeeProfilePic.Thumbnail = employee.thumbnail;
                employeeProfilePic.EmployeeId = employee.Id;
                employeeProfilePic.ImageUrl = "localhost";

                _dbContext.Add(employeeProfilePic);
                await _dbContext.SaveChangesAsync();
            }

            return Ok("Save Successfully!!");
        }
    }
    catch (Exception ex)
    {
        throw (ex);
    }

    return NoContent();
}

Now, run the application and create a new Employee with a profile picture.

Retrieve Employee Profile Picture to display in Employee List

We saved the employee profile picture already. We need to display that profile picture on the employee list. First, we must make the code changes below in the GetEmployees() method.

[Route("GetEmployees")]
[HttpGet]
public async Task<IList<Employee>> GetEmployees()
{
    try
    {
        var _data = await (from emp in _dbContext.Employees
                           join pic in this._dbContext.EmployeeProfilePics on emp. Id equals pic.EmployeeId into p
                           from pic in p.DefaultIfEmpty()
                           select new Employee
                           {
                               Id = emp.Id,
                               Code = emp.Code,
                               FullName = emp.FullName,
                               DOB = emp.DOB,
                               Address = emp.Address,
                               City = emp.City,
                               PostalCode = emp.PostalCode,
                               State = emp.State,
                               Country = emp.Country,
                               EmailId = emp.EmailId,
                               PhoneNo = emp.PhoneNo,
                               JoiningDate = emp.JoiningDate,
                               ImageType = pic.ImageType,
                               thumbnail = pic.Thumbnail,
                               EmployeeProfilePicId = pic.Id
                           }).ToListAsync();
        return _data;
    }
    catch (Exception ex)
    {
        throw (ex);
    }
}

Now, also, make the below code changes for the retrieve employee information by the Id method –

[Route("GetEmployee/{id}")]
[HttpGet]
public async Task<Employee> GetEmployee(int id)
{
    try
    {
        var _data = await (from emp in _dbContext.Employees
                           join pic in this._dbContext.EmployeeProfilePics on emp.Id equals pic.EmployeeId into p
                           from pic in p.DefaultIfEmpty()
                           where (emp.Id.Equals(id))
                           select new Employee
                           {
                               Id = emp.Id,
                               Code = emp.Code,
                               FullName = emp.FullName,
                               DOB = emp.DOB,
                               Address = emp.Address,
                               City = emp.City,
                               PostalCode = emp.PostalCode,
                               State = emp.State,
                               Country = emp.Country,
                               EmailId = emp.EmailId,
                               PhoneNo = emp.PhoneNo,
                               JoiningDate = emp.JoiningDate,
                               ImageType = pic.ImageType,
                               thumbnail = pic.Thumbnail,
                               EmployeeProfilePicId = pic.Id
                           }).FirstOrDefaultAsync();

        return _data;
    }
    catch (Exception ex)
    {
        throw (ex);
    }
}

Now, open the EmployeeList.razor view component and add the below code in the HTML section to display the profile image –

@foreach (var employee in employees)
{
    <tr>
        <td width="25%">
            <img src="@employee.thumbnail" alt="" width="32" height="32" class="rounded-circle me-2">
            <a href="@GetEmployeeViewUrl(@employee)">@employee.FullName</a>
        </td>
        <td width="10%">@employee.Code</td>
        <td width="10%">@employee.DOB.ToShortDateString()</td>
        <td width="15%">@employee.State</td>
        <td width="15%">@employee.City</td>
        <td width="10%">@employee.JoiningDate.ToShortDateString()</td>
        <td width="7%">
            <a href="@GetEditEmployeeViewUrl(@employee)" class="btn btn-primary" tabindex="-1" role="button" aria-disabled="true">
                <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-pencil-fill" viewBox="0 0 16 16">
                    <path d="M12.854.146a.5.5 0 0 0-.707 0L10.5 1.793 14.207 5.5l1.647-1.646a.5.5 0 0 0 0-.708l-3-3zm.646 6.061L9.793 2.5 3.293 9H3.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.207l6.5-6.5zm-7.468 7.468A.5.5 0 0 1 6 13.5V13h-.5a.5.5 0 0 1-.5-.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.5-.5V10h-.5a.499.499 0 0 1-.175-.032l-.179.178a.5.5 0 0 0-.11.168l-2 5a.5.5 0 0 0 .65.65l5-2a.5.5 0 0 0 .168-.11l.178-.178z"></path>
                </svg> Edit
            </a>
        </td>
        <td width="8%">
            <a class="btn btn-danger" tabindex="-1" role="button" aria-disabled="true" @onclick="_ => DeleteEmployee(employee)">
                <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-pencil-fill" viewBox="0 0 16 16">
                    <path d="M12.854.146a.5.5 0 0 0-.707 0L10.5 1.793 14.207 5.5l1.647-1.646a.5.5 0 0 0 0-.708l-3-3zm.646 6.061L9.793 2.5 3.293 9H3.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.207l6.5-6.5zm-7.468 7.468A.5.5 0 0 1 6 13.5V13h-.5a.5.5 0 0 1-.5-.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.5-.5V10h-.5a.499.499 0 0 1-.175-.032l-.179.178a.5.5 0 0 0-.11.168l-2 5a.5.5 0 0 0 .65.65l5-2a.5.5 0 0 0 .168-.11l.178-.178z"></path>
                </svg> Delete
            </a>
        </td>
    </tr>
}

Now, run the application to check the employee list data.

Now, click on the Employee Name link to display the employee information in the details view.

Happy coding!

Best and Most Recommended ASP.NET Core 8 Hosting

Fortunately, there are a number of dependable and recommended web hosts available that can help you gain control of your website’s performance and improve your ASP.NET Core 8 web ranking. HostForLIFEASP.NET is highly recommended. In Europe, HostForLIFEASP.NET is the most popular option for first-time web hosts searching for an affordable plan.

Their standard price begins at only € 3.49 per month. Customers are permitted to choose quarterly and annual plans based on their preferences. HostForLIFEASP.NET guarantees “No Hidden Fees” and an industry-leading ’30 Days Cash Back’ policy. Customers who terminate their service within the first thirty days are eligible for a full refund.

By providing reseller hosting accounts, HostForLIFEASP.NET also gives its consumers the chance to generate income. You can purchase their reseller hosting account, host an unlimited number of websites on it, and even sell some of your hosting space to others. This is one of the most effective methods for making money online. They will take care of all your customers’ hosting needs, so you do not need to fret about hosting-related matters.