Home > OS >  How to upload an image from ASP.net MVC to VARBINARY in a database
How to upload an image from ASP.net MVC to VARBINARY in a database

Time:03-16

I've been trying for a while to try to get my project to accept image files and submit them to my database, but to no avail. Everything I see is 10 years old and no longer works. It's just the basic Edit view for MVC, I just beefed up security.

public async Task<IActionResult> Edit([Bind("UserId,Name,Email,Password,Type,EmailConfirm,Pfp")] UserIdentity userIdentity)
        {
            //check if user is logged in for this action
            if (HttpContext.Session.GetInt32("sessionUserID") == null || HttpContext.Session.GetInt32("sessionUserID") <= 0)
            {
                ViewBag.reasonFailed = "You need to log in before doing this!";
                return View("Failed");
            }

            //for use in LINQ queries
            MySchoolDataContext dbContext = new();

            //checks if the user is an admin
            if ((from user in dbContext.UserIdentities where user.UserId == userIdentity.UserId select user.Type).FirstOrDefault().Equals("A"))
            {
                
            }
            else
            {

                //Checking if the userID matches the id in the URL
                if (HttpContext.Session.GetInt32("sessionUserID") != userIdentity.UserId)
                {
                    ViewBag.reasonFailed = "You cannot edit an account that isn't your own!";
                    return View("Failed");
                }

                //checks if the email is confirmed
                if ((from user in dbContext.UserIdentities where user.UserId == HttpContext.Session.GetInt32("sessionUserID") select user.EmailConfirm).FirstOrDefault().Equals("n"))
                {
                    return RedirectToAction("confirmEmail");
                }
            }

            if (userIdentity.UserId != userIdentity.UserId)
            {
                return NotFound();
            }

            if (ModelState.IsValid)
            {
                try
                {
                    _context.Update(userIdentity);
                    await _context.SaveChangesAsync();
                }
                catch (DbUpdateConcurrencyException)
                {
                    if (!UserIdentityExists(userIdentity.UserId))
                    {
                        return NotFound();
                    }
                    else
                    {
                        throw;
                    }
                }
                return RedirectToAction(nameof(Index));
            }
            return View(userIdentity);
        }

The view I'm using:

@model Rideshare.Models.UserIdentity

@{
    ViewData["Title"] = "Edit";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h1>Edit</h1>

<h4>UserIdentity</h4>
<hr />
<div >
    <div >
        <form asp-action="Edit">
            <div asp-validation-summary="ModelOnly" ></div>
            <input type="hidden" asp-for="UserId" />
            <div >
                <label asp-for="Name" ></label>
                <input asp-for="Name"  />
                <span asp-validation-for="Name" ></span>
            </div>
            <div >
                <label asp-for="Email" ></label>
                <input asp-for="Email"  />
                <span asp-validation-for="Email" ></span>
            </div>
            <div >
                <label asp-for="Password" ></label>
                <input asp-for="Password"  />
                <span asp-validation-for="Password" ></span>
            </div>
            <div >
                <label asp-for="Type" ></label>
                <input asp-for="Type"  />
                <span asp-validation-for="Type" ></span>
            </div>
            <div >
                <label asp-for="EmailConfirm" ></label>
                <input asp-for="EmailConfirm"  />
                <span asp-validation-for="EmailConfirm" ></span>
            </div>
            <div >
                <label asp-for="Pfp" ></label>
                <input asp-for="Pfp" type="file"  />
                <span asp-validation-for="Pfp" ></span>
            </div>

            <div >
                <input type="submit" value="Save"  />
            </div>
        </form>
    </div>
</div>

<div>
    <a asp-action="Index">Back to List</a>
</div>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

Thank you for any help you give. This is for a school project and not even my professor knows how to pull it off. I've asked.

Edit: Someone asked for the model that I'm using for it, so here it is.

using System;
using System.Collections.Generic;

#nullable disable

namespace Rideshare.Models
{
    public partial class UserIdentity
    {
        public UserIdentity()
        {
            HistoryDrivers = new HashSet<History>();
            HistoryPasses = new HashSet<History>();
            RatingRaters = new HashSet<Rating>();
            RatingUsers = new HashSet<Rating>();
        }

        public int UserId { get; set; }
        public string Name { get; set; }
        public string Email { get; set; }
        public string Password { get; set; }
        public string Type { get; set; }
        public string EmailConfirm { get; set; }
        public byte[] Pfp { get; set; }

        public virtual ICollection<History> HistoryDrivers { get; set; }
        public virtual ICollection<History> HistoryPasses { get; set; }
        public virtual ICollection<Rating> RatingRaters { get; set; }
        public virtual ICollection<Rating> RatingUsers { get; set; }
    }
}

CodePudding user response:

I'm completly changing this because I was slightly wrong in how I converted the image to a byte array. There is actually a very easy way to do this! It just took a lot of Googling and rabbit holes(also my teacher!). I just used a MemoryStream and IFormFile to because you can convert straight from one to the other.

        public async Task<IActionResult> ChangePfp(IFormFile theFile, [Bind("UserId,Name,Email,Password,Type,EmailConfirm,Pfp")] UserIdentity userIdentity)
        {
            //check file length just in case of null
            if (theFile.Length > 0)
            {
                //converting the image(file) to a byte array(MemoryStream)
                using (MemoryStream mStream = new())
                {
                    theFile.CopyTo(mStream);
                    userIdentity.Pfp = mStream.ToArray();
                }
            }
            else
            {
                return View();
            }

            if (ModelState.IsValid)
            {
                try
                {
                    _context.Update(userIdentity);
                    await _context.SaveChangesAsync();
                }
                catch (DbUpdateConcurrencyException)
                {
                    if (!UserIdentityExists(userIdentity.UserId))
                    {
                        ViewBag.reasonFailed = "Not found";
                        return View("Failed");
                    }
                    else
                    {
                        throw;
                    }
                }
                return RedirectToAction(nameof(Index));
            }
            return View(userIdentity);
        }

This is the code I used to do it, but with the bulk taken out to make it easier to read and make some of it private. It really was just this easy. To convert it back in the view, all you have to do is this in the view you want it in:

@if (Model.Pfp != null)
            {
            <img src="data:image/jpeg;base64,@(Convert.ToBase64String(Model.Pfp))"/>
            }

Thank you to everyone who tried to help!

  • Related