0

I'm looking to create a real estate website. I'm using ASP.NET Core 6 MVC to build my website. I create a Property table and an ImageData table. I used imagesharp for image processing. And I used one to many relationship to store images. I connected those previous mentioned table by using a foreign key. But the problem is, it's not going to store my images. But other information it's storing inside the database table. Only images are not storing in the database.

Can anyone help me to solve this problem. I'm waiting for your answers.

Below is my code.

Property.cs

using CeylonPropertiesVIP.Data;
using System.ComponentModel.DataAnnotations;

namespace CeylonPropertiesVIP.Models
{
    public class Property
    {
        [Key]
        public int Id { get; set; }
        [Required]
        public string? Title { get; set; }
        [Required]
        public string? PropertyType { get; set; }
        [Required]
        public string? Address { get; set; }
        [Required]
        public string? Bedrooms { get; set; }
        [Required]
        public string? Bathrooms { get; set; }
        [Required]
        public string? FloorArea { get; set; }
        [Required]
        public string? NoOfFloors { get; set; }
        [Required]
        public string? CarParkingSpaces { get; set; }
        [Required]
        public string? FurnishingStatus { get; set; }
        [Required]
        public string? AreaOfLands { get; set; }
        [Required]
        public string? Availability { get; set; }
        [Required]
        public string? NearestBusStop { get; set; }
        [Required]
        public string? AgeOfTheProperty { get; set; }
        [Required]
        public string? PropertyDescription { get; set; }
        [Required]
        public string? PropertyFeatures { get; set; }
        public string? PropertyVideo { get; set; }
        public string? GoogleMapLink { get; set; }
        [Required]
        public string? Name { get; set; }
        [Required]
        public string? ContactNumber { get; set; }
        public string? Email { get; set; }

        public List<ImageData>? ImageDatas { get; set; }
    }
}

ImageData.cs

using CeylonPropertiesVIP.Models;

namespace CeylonPropertiesVIP.Data
{
    public class ImageData
    {
        // int Id -> use MD5(MD5(Id)) to proptect against bots.
        public ImageData() => this.Id = Guid.NewGuid();
        public Guid Id { get; set; }
        public string OriginalFileName { get; set; }
        public string OriginalType { get; set; }
        public byte[] OriginalContent { get; set; }
        public byte[] ThumbnailContent { get; set; }
        public byte[] FullscreenContent { get; set; }
        public Property Property { get; set; }
    }
}

Create.cshtml

@model CeylonPropertiesVIP.Models.Property

@{
    ViewData["Title"] = "Create";
}

<section class="py-5">
    <div class="container px-5 my-5">
        <h1>Create</h1>

        <h4>Property</h4>
        <hr />
        @*<div class="row">
            <div class="col-md-4">*@
        <form asp-action="Create" enctype="multipart/form-data">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Title" class="control-label"></label>
                <input asp-for="Title" class="form-control" />
                <span asp-validation-for="Title" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="PropertyType" class="control-label"></label>
                <input asp-for="PropertyType" class="form-control" />
                <span asp-validation-for="PropertyType" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Address" class="control-label"></label>
                <input asp-for="Address" class="form-control" />
                <span asp-validation-for="Address" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Bedrooms" class="control-label"></label>
                <input asp-for="Bedrooms" class="form-control" />
                <span asp-validation-for="Bedrooms" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Bathrooms" class="control-label"></label>
                <input asp-for="Bathrooms" class="form-control" />
                <span asp-validation-for="Bathrooms" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="FloorArea" class="control-label"></label>
                <input asp-for="FloorArea" class="form-control" />
                <span asp-validation-for="FloorArea" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="NoOfFloors" class="control-label"></label>
                <input asp-for="NoOfFloors" class="form-control" />
                <span asp-validation-for="NoOfFloors" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="CarParkingSpaces" class="control-label"></label>
                <input asp-for="CarParkingSpaces" class="form-control" />
                <span asp-validation-for="CarParkingSpaces" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="FurnishingStatus" class="control-label"></label>
                <input asp-for="FurnishingStatus" class="form-control" />
                <span asp-validation-for="FurnishingStatus" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="AreaOfLands" class="control-label"></label>
                <input asp-for="AreaOfLands" class="form-control" />
                <span asp-validation-for="AreaOfLands" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Availability" class="control-label"></label>
                <input asp-for="Availability" class="form-control" />
                <span asp-validation-for="Availability" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="NearestBusStop" class="control-label"></label>
                <input asp-for="NearestBusStop" class="form-control" />
                <span asp-validation-for="NearestBusStop" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="AgeOfTheProperty" class="control-label"></label>
                <input asp-for="AgeOfTheProperty" class="form-control" />
                <span asp-validation-for="AgeOfTheProperty" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="PropertyDescription" class="control-label"></label>
                <input asp-for="PropertyDescription" class="form-control" />
                <span asp-validation-for="PropertyDescription" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="PropertyFeatures" class="control-label"></label>
                <input asp-for="PropertyFeatures" class="form-control" />
                <span asp-validation-for="PropertyFeatures" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="PropertyVideo" class="control-label"></label>
                <input asp-for="PropertyVideo" class="form-control" />
                <span asp-validation-for="PropertyVideo" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="GoogleMapLink" class="control-label"></label>
                <input asp-for="GoogleMapLink" class="form-control" />
                <span asp-validation-for="GoogleMapLink" class="text-danger"></span>
            </div>
            <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="ContactNumber" class="control-label"></label>
                <input asp-for="ContactNumber" class="form-control" />
                <span asp-validation-for="ContactNumber" 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="ImageDatas" class="control-label">Property Images</label>
                <input asp-for="ImageDatas" type="file" multiple="multiple" name="images" class="form-control" />
                <span asp-validation-for="ImageDatas" class="text-danger"></span>
            </div>
            <div class="form-group my-2">
                <input type="submit" value="Create" class="btn btn-primary" />
            </div>
        </form>
        @*</div>
            </div>*@
    </div>
    <div>
        <a asp-action="Index">Back to List</a>
    </div>
</section>

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

PropertiesCotroller.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using CeylonPropertiesVIP.Data;
using CeylonPropertiesVIP.Models;

namespace CeylonPropertiesVIP.Controllers
{
    public class PropertiesController : Controller
    {
        private readonly ApplicationDbContext _context;

        public PropertiesController(ApplicationDbContext context)
        {
            _context = context;
        }

        // GET: Properties
        public async Task<IActionResult> Index()
        {
              return _context.Property != null ? 
                          View(await _context.Property.ToListAsync()) :
                          Problem("Entity set 'ApplicationDbContext.Property'  is null.");
        }

        // GET: Properties/Details/5
        public async Task<IActionResult> Details(int? id)
        {
            if (id == null || _context.Property == null)
            {
                return NotFound();
            }

            var @property = await _context.Property
                .FirstOrDefaultAsync(m => m.Id == id);
            if (@property == null)
            {
                return NotFound();
            }

            return View(@property);
        }

        // GET: Properties/Create
        public IActionResult Create()
        {
            return View();
        }

        // POST: Properties/Create
        // To protect from overposting attacks, enable the specific properties you want to bind to.
        // For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Create([Bind("Id,Title,PropertyType,Address,Bedrooms,Bathrooms,FloorArea,NoOfFloors,CarParkingSpaces,FurnishingStatus,AreaOfLands,Availability,NearestBusStop,AgeOfTheProperty,PropertyDescription,PropertyFeatures,PropertyVideo,GoogleMapLink,Name,ContactNumber,Email")] Property @property)
        {
            if (ModelState.IsValid)
            {
                _context.Add(@property);
                await _context.SaveChangesAsync();
                return RedirectToAction(nameof(Index));
            }
            return View(@property);
        }

        // GET: Properties/Edit/5
        public async Task<IActionResult> Edit(int? id)
        {
            if (id == null || _context.Property == null)
            {
                return NotFound();
            }

            var @property = await _context.Property.FindAsync(id);
            if (@property == null)
            {
                return NotFound();
            }
            return View(@property);
        }

        // POST: Properties/Edit/5
        // To protect from overposting attacks, enable the specific properties you want to bind to.
        // For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Edit(int id, [Bind("Id,Title,PropertyType,Address,Bedrooms,Bathrooms,FloorArea,NoOfFloors,CarParkingSpaces,FurnishingStatus,AreaOfLands,Availability,NearestBusStop,AgeOfTheProperty,PropertyDescription,PropertyFeatures,PropertyVideo,GoogleMapLink,Name,ContactNumber,Email")] Property @property)
        {
            if (id != @property.Id)
            {
                return NotFound();
            }

            if (ModelState.IsValid)
            {
                try
                {
                    _context.Update(@property);
                    await _context.SaveChangesAsync();
                }
                catch (DbUpdateConcurrencyException)
                {
                    if (!PropertyExists(@property.Id))
                    {
                        return NotFound();
                    }
                    else
                    {
                        throw;
                    }
                }
                return RedirectToAction(nameof(Index));
            }
            return View(@property);
        }

        // GET: Properties/Delete/5
        public async Task<IActionResult> Delete(int? id)
        {
            if (id == null || _context.Property == null)
            {
                return NotFound();
            }

            var @property = await _context.Property
                .FirstOrDefaultAsync(m => m.Id == id);
            if (@property == null)
            {
                return NotFound();
            }

            return View(@property);
        }

        // POST: Properties/Delete/5
        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> DeleteConfirmed(int id)
        {
            if (_context.Property == null)
            {
                return Problem("Entity set 'ApplicationDbContext.Property'  is null.");
            }
            var @property = await _context.Property.FindAsync(id);
            if (@property != null)
            {
                _context.Property.Remove(@property);
            }
            
            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        }

        private bool PropertyExists(int id)
        {
          return (_context.Property?.Any(e => e.Id == id)).GetValueOrDefault();
        }
    }
}

  • What is the implementation of your controller that handles the Form? By the way, non-sequential guilds like Guid.NewGuid() are terrible primary keys because of how they force the index to behave. – Crowcoder Jun 01 '22 at 12:46
  • Okay, I can upload my controller too. – Rivindhu Geeneth Jun 01 '22 at 12:59
  • You are not handling the File input part of the multipart/formdata. See if [this helps](https://stackoverflow.com/questions/5357982/asp-net-mvc-how-to-create-action-method-that-accepts-and-multipart-form-data) – Crowcoder Jun 01 '22 at 13:14

1 Answers1

0

You can try to remove the name in <input asp-for="ImageDatas" .../>,use List<IFormFile> to get the data from form,and add ImageDatas into [Bind]: Property:

public class Property
    {
        [Key]
        public int Id { get; set; }
        [Required]
        public string? Title { get; set; }
        [Required]
        public string? PropertyType { get; set; }
        [Required]
        public string? Address { get; set; }
        [Required]
        public string? Bedrooms { get; set; }
        [Required]
        public string? Bathrooms { get; set; }
        [Required]
        public string? FloorArea { get; set; }
        [Required]
        public string? NoOfFloors { get; set; }
        [Required]
        public string? CarParkingSpaces { get; set; }
        [Required]
        public string? FurnishingStatus { get; set; }
        [Required]
        public string? AreaOfLands { get; set; }
        [Required]
        public string? Availability { get; set; }
        [Required]
        public string? NearestBusStop { get; set; }
        [Required]
        public string? AgeOfTheProperty { get; set; }
        [Required]
        public string? PropertyDescription { get; set; }
        [Required]
        public string? PropertyFeatures { get; set; }
        public string? PropertyVideo { get; set; }
        public string? GoogleMapLink { get; set; }
        [Required]
        public string? Name { get; set; }
        [Required]
        public string? ContactNumber { get; set; }
        public string? Email { get; set; }

        public List<IFormFile> ImageDatas { get; set; }=new List<IFormFile>();
    }

Create.cshtml:

<section class="py-5">
    <div class="container px-5 my-5">
        <h1>Create</h1>

        <h4>Property</h4>
        <hr />
        @*<div class="row">
            <div class="col-md-4">*@
        <form asp-action="Create" enctype="multipart/form-data">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Title" class="control-label"></label>
                <input asp-for="Title" class="form-control" />
                <span asp-validation-for="Title" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="PropertyType" class="control-label"></label>
                <input asp-for="PropertyType" class="form-control" />
                <span asp-validation-for="PropertyType" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Address" class="control-label"></label>
                <input asp-for="Address" class="form-control" />
                <span asp-validation-for="Address" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Bedrooms" class="control-label"></label>
                <input asp-for="Bedrooms" class="form-control" />
                <span asp-validation-for="Bedrooms" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Bathrooms" class="control-label"></label>
                <input asp-for="Bathrooms" class="form-control" />
                <span asp-validation-for="Bathrooms" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="FloorArea" class="control-label"></label>
                <input asp-for="FloorArea" class="form-control" />
                <span asp-validation-for="FloorArea" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="NoOfFloors" class="control-label"></label>
                <input asp-for="NoOfFloors" class="form-control" />
                <span asp-validation-for="NoOfFloors" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="CarParkingSpaces" class="control-label"></label>
                <input asp-for="CarParkingSpaces" class="form-control" />
                <span asp-validation-for="CarParkingSpaces" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="FurnishingStatus" class="control-label"></label>
                <input asp-for="FurnishingStatus" class="form-control" />
                <span asp-validation-for="FurnishingStatus" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="AreaOfLands" class="control-label"></label>
                <input asp-for="AreaOfLands" class="form-control" />
                <span asp-validation-for="AreaOfLands" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Availability" class="control-label"></label>
                <input asp-for="Availability" class="form-control" />
                <span asp-validation-for="Availability" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="NearestBusStop" class="control-label"></label>
                <input asp-for="NearestBusStop" class="form-control" />
                <span asp-validation-for="NearestBusStop" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="AgeOfTheProperty" class="control-label"></label>
                <input asp-for="AgeOfTheProperty" class="form-control" />
                <span asp-validation-for="AgeOfTheProperty" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="PropertyDescription" class="control-label"></label>
                <input asp-for="PropertyDescription" class="form-control" />
                <span asp-validation-for="PropertyDescription" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="PropertyFeatures" class="control-label"></label>
                <input asp-for="PropertyFeatures" class="form-control" />
                <span asp-validation-for="PropertyFeatures" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="PropertyVideo" class="control-label"></label>
                <input asp-for="PropertyVideo" class="form-control" />
                <span asp-validation-for="PropertyVideo" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="GoogleMapLink" class="control-label"></label>
                <input asp-for="GoogleMapLink" class="form-control" />
                <span asp-validation-for="GoogleMapLink" class="text-danger"></span>
            </div>
            <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="ContactNumber" class="control-label"></label>
                <input asp-for="ContactNumber" class="form-control" />
                <span asp-validation-for="ContactNumber" 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="ImageDatas" class="control-label">Property Images</label>
                <input asp-for="ImageDatas" type="file" multiple="multiple"  class="form-control" />
                <span asp-validation-for="ImageDatas" class="text-danger"></span>
            </div>
            <div class="form-group my-2">
                <input type="submit" value="Create" class="btn btn-primary" />
            </div>
        </form>
        @*</div>
            </div>*@
    </div>
    <div>
        <a asp-action="Index">Back to List</a>
    </div>
</section>

action:

[HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Edit(int id, [Bind("Id,Title,PropertyType,Address,Bedrooms,Bathrooms,FloorArea,NoOfFloors,CarParkingSpaces,FurnishingStatus,AreaOfLands,Availability,NearestBusStop,AgeOfTheProperty,PropertyDescription,PropertyFeatures,PropertyVideo,GoogleMapLink,Name,ContactNumber,Email,ImageDatas")] Property @property)
        {
            if (id != @property.Id)
            {
                return NotFound();
            }

            if (ModelState.IsValid)
            {
                try
                {
                    _context.Update(@property);
                    await _context.SaveChangesAsync();
                }
                catch (DbUpdateConcurrencyException)
                {
                    if (!PropertyExists(@property.Id))
                    {
                        return NotFound();
                    }
                    else
                    {
                        throw;
                    }
                }
                return RedirectToAction(nameof(Index));
            }
            return View(@property);
        }

Then you can try to convert List<IFormFile> to List<ImageData> in Create action.Here is a sample

List<ImageData> filedatas = new List<ImageData>();
        if (property.ImageDatas.Count() > 0) {
            foreach (var item in @property.ImageDatas)
            {
                using (var ms = new MemoryStream())
                {
                    item.CopyTo(ms);
                    var fileBytes = ms.ToArray();
                    filedatas.Add(new ImageData { OriginalFileName=item.FileName, OriginalContent=fileBytes });
                    
                }
            }
            //add filedatas to database
        }
Yiyi You
  • 16,875
  • 1
  • 10
  • 22
  • Thank you for your answer. But I'm getting an error. "The entity type 'List' requires a primary key to be defined. If you intended to use a keyless entity type, call 'HasNoKey' in 'OnModelCreating'. For more information on keyless entity types, see https://go.microsoft.com/fwlink/?linkid=2141943." – Rivindhu Geeneth Jun 03 '22 at 06:23