How do I resolve this controller issue when creating new instance of a class in my web app?

Amra Akmadzic 100 Reputation points
2024-08-26T08:14:38.52+00:00

I'm developing an asp.net core MVC app and I have an issue when I try to add a new service. My database is fine because I can create instances of other classes and save them to my database. My build is succesful so I don't get any error messages. When I click the button for my create method in my app, nothing happens except some view's input fields clearing (i.e. the catagory field, the details fields). I think the problem is in my controller.

Here is the code for my controller:


using System;

using Microsoft.AspNetCore.Mvc;

using Microsoft.AspNetCore.Mvc.Rendering;

using Microsoft.EntityFrameworkCore;

using VjencanjeIzSnova_WebApp.Data;

using VjencanjeIzSnova_WebApp.Models;

namespace VjencanjeIzSnova_WebApp.Controllers

{

    public class ServiceController : Controller

    {

        private readonly VjencanjeIzSnovaDbContext _context;

        private readonly IWebHostEnvironment _hostingEnvironment;

        public ServiceController(VjencanjeIzSnovaDbContext context, IWebHostEnvironment hostingEnvironment)

        {

            _context = context;

            _hostingEnvironment = hostingEnvironment;

        }

        // GET: Service

        public async Task<IActionResult> Index()

        {

            var vjencanjeIzSnovaDbContext = _context.Services

                .Include(s => s.Category)

                .Include(s => s.Partner)

                .Include(s => s.Images);

            return View(await vjencanjeIzSnovaDbContext.ToListAsync());

        }

        // GET: Service/Details/5

        public async Task<IActionResult> Details(int? id)

        {

            if (id == null)

            {

                return NotFound();

            }

            var service = await _context.Services

                .Include(s => s.Category)

                .Include(s => s.Partner)

                .Include(s => s.Images)

                .FirstOrDefaultAsync(m => m.ServiceId == id);

            if (service == null)

            {

                return NotFound();

            }

            return View(service);

        }

        // GET: Service/Create

        public IActionResult Create()

        {

            ViewBag.Category = new SelectList(_context.Categories, "CategoryId", "Name");

            ViewBag.Partner = new SelectList(_context.Partners, "PartnerId", "PartnerId");

            return View();

        }

        [HttpPost]

        [ValidateAntiForgeryToken]

        public async Task<IActionResult> Create([Bind("ServiceId,CategoryId,ContactEmail,PriceRange,Details,CompanyInfo,Name,Description,PartnerId")] Service service, List<IFormFile> ImageFiles)

        {

            if (ModelState.IsValid)

            {

                // Concatenate Details inputs with semicolons

                service.Details = string.Join(";", Request.Form["Details[]"]);

                _context.Add(service);

                await _context.SaveChangesAsync();

                foreach (var file in ImageFiles)

                {

                    if (file != null && file.Length > 0)

                    {

                        var fileName = Guid.NewGuid().ToString() + Path.GetExtension(file.FileName);

                        string filePath = Path.Combine(_hostingEnvironment.WebRootPath, "serviceImages", fileName);

                        using (var stream = new FileStream(filePath, FileMode.Create))

                        {

                            await file.CopyToAsync(stream);

                        }

                        var image = new Image

                        {

                            Url = fileName,

                            ServiceId = service.ServiceId

                        };

                        _context.Images.Add(image);

                    }

                }

                await _context.SaveChangesAsync();

                return RedirectToAction(nameof(Index));

            }

            ViewBag.Category = new SelectList(_context.Categories, "CategoryId", "Name", service.CategoryId);

            ViewBag.Partner = new SelectList(_context.Partners, "PartnerId", "PartnerId", service.PartnerId);

            return View(service);

        }

        // GET: Service/Edit/5

        public async Task<IActionResult> Edit(int? id)

        {

            if (id == null)

            {

                return NotFound();

            }

            var service = await _context.Services.FindAsync(id);

            if (service == null)

            {

                return NotFound();

            }

            ViewData["CategoryId"] = new SelectList(_context.Categories, "CategoryId", "CategoryId", service.CategoryId);

            ViewData["PartnerId"] = new SelectList(_context.Partners, "PartnerId", "PartnerId", service.PartnerId);

            return View(service);

        }

        // POST: Service/Edit/5

        [HttpPost]

        [ValidateAntiForgeryToken]

        public async Task<IActionResult> Edit(int id, [Bind("ServiceId,CategoryId,ContactEmail,PriceRange,Details,CompanyInfo,Name,Description,PartnerId")] Service service)

        {

            if (id != service.ServiceId)

            {

                return NotFound();

            }

            if (ModelState.IsValid)

            {

                try

                {

                    _context.Update(service);

                    await _context.SaveChangesAsync();

                }

                catch (DbUpdateConcurrencyException)

                {

                    if (!ServiceExists(service.ServiceId))

                    {

                        return NotFound();

                    }

                    else

                    {

                        throw;

                    }

                }

                return RedirectToAction(nameof(Index));

            }

            ViewData["CategoryId"] = new SelectList(_context.Categories, "CategoryId", "CategoryId", service.CategoryId);

            ViewData["PartnerId"] = new SelectList(_context.Partners, "PartnerId", "PartnerId", service.PartnerId);

            return View(service);

        }

        // GET: Service/Delete/5

        public async Task<IActionResult> Delete(int? id)

        {

            if (id == null)

            {

                return NotFound();

            }

            var service = await _context.Services

                .Include(s => s.Category)

                .Include(s => s.Partner)

                .FirstOrDefaultAsync(m => m.ServiceId == id);

            if (service == null)

            {

                return NotFound();

            }

            return View(service);

        }

        // POST: Service/Delete/5

        [HttpPost, ActionName("Delete")]

        [ValidateAntiForgeryToken]

        public async Task<IActionResult> DeleteConfirmed(int id)

        {

            var service = await _context.Services.FindAsync(id);

            if (service != null)

            {

                _context.Services.Remove(service);

            }

            await _context.SaveChangesAsync();

            return RedirectToAction(nameof(Index));

        }

        private bool ServiceExists(int id)

        {

            return _context.Services.Any(e => e.ServiceId == id);

        }

    }

}

Here are my models for Service.cs and Image.cs:


public partial class Service

{

    [Key]

    public int ServiceId { get; set; }

    public int CategoryId { get; set; }

    public string ContactEmail { get; set; } = null!;

    public string? PriceRange { get; set; }

    public string Details { get; set; } = null!;

    public string CompanyInfo { get; set; } = null!;

    public string Name { get; set; } = null!;

    public string? Description { get; set; }

    public int PartnerId { get; set; }

    public virtual Category Category { get; set; } = null!;

    public virtual Partner Partner { get; set; } = null!;

    public virtual ICollection<Reservation> Reservations { get; set; } = new List<Reservation>();

    public virtual ICollection<Image> Images { get; set; } = new List<Image>();

}


public partial class Image

{

    public string Url { get; set; } 

    public int ImageId { get; set; }

    public int ServiceId { get; set; }

    public virtual Service Service { get; set; } 

}

Here is the code for my view:


@model VjencanjeIzSnova_WebApp.Models.Service

@{

    ViewData["Title"] = "Create";

}

<h1>Create</h1>

<h4>Service</h4>

<hr />

<div class="row">

    <div class="col-md-4">

        <form asp-action="Create">

            <div class="form-group">

                <label asp-for="CategoryId" class="control-label">Category</label>

                <select asp-for="CategoryId" class="form-control" asp-items="ViewBag.Category"></select>

            </div>

            <div class="form-group">

                <label asp-for="ContactEmail" class="control-label"></label>

                <input asp-for="ContactEmail" class="form-control" />

                <span asp-validation-for="ContactEmail" class="text-danger"></span>

            </div>

            <div class="form-group">

                <label asp-for="PriceRange" class="control-label"></label>

                <input asp-for="PriceRange" class="form-control" />

                <span asp-validation-for="PriceRange" class="text-danger"></span>

            </div>

            <div class="form-group">

                <label asp-for="CompanyInfo" class="control-label"></label>

                <textarea asp-for="CompanyInfo" class="form-control"></textarea>

                <span asp-validation-for="CompanyInfo" class="text-danger"></span>

            </div>

            <div class="form-group">

                <label asp-for="Details" class="control-label"></label>

                <div class="d-flex align-items-center">

                    <div id="details-container" class="flex-grow-1">

                        <input type="text" class="form-control" name="Details[]" multiple />

                    </div>

                    <button type="button" id="add-new-detail" class="btn btn-secondary ml-2">+</button>

                    <span asp-validation-for="Details" class="text-danger"></span>

                </div>

            </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="Description" class="control-label"></label>

                <textarea asp-for="Description" class="form-control"></textarea>

                <span asp-validation-for="Description" class="text-danger"></span>

            </div>

            <div class="form-group">

                <label asp-for="PartnerId" class="control-label"></label>

                <select asp-for="PartnerId" class="form-control" asp-items="ViewBag.Partner"></select>

            </div>

            <div class="form-group">

                <div class="d-flex align-items-center">

                    <label for="Images" class="mr-2">Images: </label>

                    <div id="image-container" class="flex-grow-1">

                        <input type="file" name="Images" class="form-control" multiple />

                    </div>

                    <button type="button" id="add-more-images" class="btn btn-secondary ml-2">+</button>

                </div>

            </div>

            <div class="form-group">

                <input type="submit" value="Create" class="btn btn-primary" />

            </div>

        </form>

    </div>

</div>

<div>

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

</div>

<script>

    document.getElementById('add-new-detail').addEventListener('click', function () {

          var container = document.getElementById('details-container');

          var input = document.createElement('input');

          input.type = 'text';

          input.className = 'form-control';

          input.name = 'Details[]';

          container.appendChild(input);

     });

    document.getElementById('add-more-images').addEventListener('click', function () {

        var container = document.getElementById('image-container');

        var input = document.createElement('input');

        input.type = 'file';

        input.name = 'Images';

        input.className = 'form-control';

        container.appendChild(input);

    });

</script>

@section Scripts {

    @{

        await Html.RenderPartialAsync("_ValidationScriptsPartial");

    }

}

.NET
.NET
Microsoft Technologies based on the .NET software framework.
3,833 questions
ASP.NET Core
ASP.NET Core
A set of technologies in the .NET Framework for building web applications and XML web services.
4,550 questions
{count} votes

Accepted answer
  1. JasonPan - MSFT 5,466 Reputation points Microsoft Vendor
    2024-08-26T11:26:04.0033333+00:00

    Hi @Amra Akmadzic,

    Create.cshtml

    @model VjencanjeIzSnova_WebApp.Models.Service
    @{
        ViewData["Title"] = "Create";
    }
    <h1>Create</h1>
    <h4>Service</h4>
    <hr />
    <div class="row">
        <div class="col-md-4">
            <form asp-action="Create" method="post" enctype="multipart/form-data">
                @Html.AntiForgeryToken()
                <div class="form-group">
                    <label asp-for="CategoryId" class="control-label">Category</label>
                    <select asp-for="CategoryId" class="form-control" asp-items="ViewBag.Category"></select>
                    <span asp-validation-for="CategoryId" class="text-danger"></span>
                </div>
                <div class="form-group">
                    <label asp-for="ContactEmail" class="control-label"></label>
                    <input asp-for="ContactEmail" class="form-control" />
                    <span asp-validation-for="ContactEmail" class="text-danger"></span>
                </div>
                <div class="form-group">
                    <label asp-for="PriceRange" class="control-label"></label>
                    <input asp-for="PriceRange" class="form-control" />
                    <span asp-validation-for="PriceRange" class="text-danger"></span>
                </div>
                <div class="form-group">
                    <label asp-for="CompanyInfo" class="control-label"></label>
                    <textarea asp-for="CompanyInfo" class="form-control"></textarea>
                    <span asp-validation-for="CompanyInfo" class="text-danger"></span>
                </div>
                <div class="form-group">
                    <label asp-for="Details" class="control-label"></label>
                    <div class="d-flex align-items-center">
                        <div id="details-container" class="flex-grow-1">
                            <input type="text" class="form-control" name="Details[]" />
                        </div>
                        <button type="button" id="add-new-detail" class="btn btn-secondary ml-2">+</button>
                    </div>
                    <span asp-validation-for="Details" 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="Description" class="control-label"></label>
                    <textarea asp-for="Description" class="form-control"></textarea>
                    <span asp-validation-for="Description" class="text-danger"></span>
                </div>
                <div class="form-group">
                    <label asp-for="PartnerId" class="control-label">Partner</label>
                    <select asp-for="PartnerId" class="form-control" asp-items="ViewBag.Partner"></select>
                    <span asp-validation-for="PartnerId" class="text-danger"></span>
                </div>
                <div class="form-group">
                    <div class="d-flex align-items-center">
                        <label for="Images" class="mr-2">Images: </label>
                        <div id="image-container" class="flex-grow-1">
                            <input type="file" name="ImageFiles" class="form-control" multiple />
                        </div>
                        <button type="button" id="add-more-images" class="btn btn-secondary ml-2">+</button>
                    </div>
                </div>
                <div class="form-group">
                    <input type="submit" value="Create" class="btn btn-primary" />
                </div>
            </form>
        </div>
    </div>
    <div>
        <a asp-action="Index">Back to List</a>
    </div>
    @section Scripts {
            <script>
                document.getElementById('add-new-detail').addEventListener('click', function () {
                    var container = document.getElementById('details-container');
                    var input = document.createElement('input');
                    input.type = 'text';
                    input.className = 'form-control';
                    input.name = 'Details[]';
                    container.appendChild(input);
                });
                document.getElementById('add-more-images').addEventListener('click', function () {
                    var container = document.getElementById('image-container');
                    var input = document.createElement('input');
                    input.type = 'file';
                    input.name = 'ImageFiles';
                    input.className = 'form-control';
                    container.appendChild(input);
                });
            </script>
        @{
            await Html.RenderPartialAsync("_ValidationScriptsPartial");
        }
    }
    

    After adding var errors = ModelState.Values.SelectMany(v => v.Errors); like below, and I found the error message "The Partner field is required." "The Category field is required.".

            [HttpPost]
            [ValidateAntiForgeryToken]
            public async Task<IActionResult> Create(Service service, List<IFormFile> ImageFiles)
            {
                if (ModelState.IsValid)
                {
                    // Concatenate Details inputs with semicolons
                    service.Details = string.Join(";", Request.Form["Details[]"]);
                    _context.Add(service);
                    await _context.SaveChangesAsync();
                    if (ImageFiles != null && ImageFiles.Count > 0)
                    {
                        foreach (var file in ImageFiles)
                        {
                            if (file != null && file.Length > 0)
                            {
                                var fileName = Guid.NewGuid().ToString() + Path.GetExtension(file.FileName);
                                string filePath = Path.Combine(_hostingEnvironment.WebRootPath, "serviceImages", fileName);
                                using (var stream = new FileStream(filePath, FileMode.Create))
                                {
                                    await file.CopyToAsync(stream);
                                }
                                var image = new Image
                                {
                                    Url = fileName,
                                    ServiceId = service.ServiceId
                                };
                                _context.Images.Add(image);
                            }
                        }
                        await _context.SaveChangesAsync();
                    }
                    return RedirectToAction(nameof(Index));
                }
                else {
                    var errors = ModelState.Values.SelectMany(v => v.Errors);
                }
                ViewBag.Category = new SelectList(_context.Categories, "CategoryId", "Name", service.CategoryId);
                ViewBag.Partner = new SelectList(_context.Partners, "PartnerId", "PartnerName", service.PartnerId);
                return View(service);
            }
    

    Then I back to /Models/Service.cs and change Partner and Category like below.

        public virtual Category? Category { get; set; } = null!;
        public virtual Partner? Partner { get; set; } = null!;
    

    Then we can make ModelState.IsValid = true .


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    Best regards,

    Jason

    1 person found this answer helpful.

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.