2

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 class="row">
    <div class="col-md-4">
        <form asp-action="Edit">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <input type="hidden" asp-for="UserId" />
            <div class="form-group">
                <label asp-for="Name" class="control-label"></label>
                <input asp-for="Name" class="form-control" />
                <span asp-validation-for="Name" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Email" class="control-label"></label>
                <input asp-for="Email" class="form-control" />
                <span asp-validation-for="Email" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Password" class="control-label"></label>
                <input asp-for="Password" class="form-control" />
                <span asp-validation-for="Password" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Type" class="control-label"></label>
                <input asp-for="Type" class="form-control" />
                <span asp-validation-for="Type" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="EmailConfirm" class="control-label"></label>
                <input asp-for="EmailConfirm" class="form-control" />
                <span asp-validation-for="EmailConfirm" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Pfp" class="control-label"></label>
                <input asp-for="Pfp" type="file" class="form-control" />
                <span asp-validation-for="Pfp" class="text-danger"></span>
            </div>

            <div class="form-group">
                <input type="submit" value="Save" class="btn btn-primary" />
            </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; }
    }
}
8
  • I know you said it's for a school project, but in production systems you generally don't want to store large binaries (like images or files in general) inside database tables. You'd use the file-system directly or something like S3/Azure Blob Storage, and thesedays: by treating files as immutable blobs with a content-addressable file-name scheme such as their SHA-256 hash. Good luck! Commented Mar 13, 2022 at 22:58
  • You need to show us your view-model class. Also, I hope you're not using an EF entity class as a read/write view-model? (That's a recipe for disaster...) Commented Mar 13, 2022 at 22:59
  • @Dai I edited it with the model I'm using with it. I forgot to add it, sorry. Commented Mar 13, 2022 at 23:15
  • In asp.net core, it allows upload file and receive with type IFormFile. So you need change byte[] Pfp to IFormFile Pfp. If you want to save to database, you can replace Pfp input with <input name="file" type="file" class="form-control" /> and receive the value by HttpContext.Request.Form["file"] and try to convert it to byte array. Commented Mar 14, 2022 at 3:20
  • Don't forget to ensure your <form> has enctype="multipart/form-data too. Commented Mar 14, 2022 at 3:41

1 Answer 1

2

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!

Sign up to request clarification or add additional context in comments.

1 Comment

As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.