I build an online store as an ASP.NET Core 7 MVC application. I used areas to separate different parts of it.
My home index is outside the Areas
folders. This home index page displays products. Each product has an <a/>
tag to redirect to a detail page.
This detail page is put in a subfolder of the Areas
folder. For some reason I don't understand, I'm correctly redirected to my detail page but it is completely dark. I thought I put all the necessary attributes in the <a/>
and I don't find a solution for this.
Would you see my code below in order to identify how to fix the problem please?
This is how my folders are organized:
wwwroot
Areas
- Admin
- Identity
- ProductDetails
- Views
- Product
- Details.cshtml
- ProductDetailsController.cs
Pages
- Index.cshtml
Program.cs
This is the ProductDetails/ProductDetailsController.cs
:
using AutoMapper;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using TheCarHub.Areas.Admin.DTO.Read;
using TheCarHub.Data;
namespace TheCarHub.Areas.ProductDetails
{
[Area("ProductDetails")]
public class ProductDetailsController : Controller
{
private readonly ApplicationDbContext _context;
private readonly IMapper _mapper;
public ProductDetailsController(ApplicationDbContext context, IMapper mapper)
{
_context = context;
_mapper = mapper;
}
// GET: ProductDetails/Product/Details/5
public async Task<IActionResult> Details(int? id)
{
if (id == null || _context.Car == null)
{
return NotFound();
}
var car = await _context.Car
.Where(c => c.Id == id)
.Include(x => x.CarDetails)
.Include(x => x.CarDetails.CarMakes)
.Include(x => x.CarDetails.CarModel)
.Include(y => y.CarImages)
.FirstOrDefaultAsync();
if (car == null)
{
return NotFound();
}
var carObject = (car, car.CarImages.First(), car.CarDetails);
CarDtoRead carDtoRead = _mapper.Map<CarDtoRead>(carObject);
return View(carDtoRead);
}
}
}
This is the Pages/Index.cshtml
page, first attempt:
@page
@model IndexModel
@{
ViewData["Title"] = "Home page";
Layout = "~/Pages/Shared/_Layout.cshtml";
}
<div>
@foreach (var item in Model._carDtoReadList)
{
<figure>
<a asp-controller="ProductDetails" asp-action="Details" asp-route-id="@item.Id">
<img src="@Url.Content(item.UrlImage.Replace("wwwroot", "~"))" alt="@item.Name" />
<figcaption>
<p>
@Html.DisplayFor(modelItem => item.Name)
</p>
<p>
@Html.DisplayFor(modelItem => item.Year)
</p>
<p>
@Html.DisplayFor(modelItem => item.Description)
</p>
<p>
@Html.DisplayFor(modelItem => item.SellingPrice)
</p>
</figcaption>
</a>
</figure>
}
</div>
For that first result:
And my second attempt:
@page
@model IndexModel
@{
ViewData["Title"] = "Home page";
Layout = "~/Pages/Shared/_Layout.cshtml";
}
<div>
@foreach (var item in Model._carDtoReadList)
{
<figure>
<a asp-area="ProductDetails" asp-controller="ProductDetails" asp-action="Details" asp-route-id="@item.Id">
<img src="@Url.Content(item.UrlImage.Replace("wwwroot", "~"))" alt="@item.Name" />
<figcaption>
<p>@Html.DisplayFor(modelItem => item.Name)</p>
<p>@Html.DisplayFor(modelItem => item.Year)</p>
<p>@Html.DisplayFor(modelItem => item.Description)</p>
<p>@Html.DisplayFor(modelItem => item.SellingPrice)</p>
</figcaption>
</a>
</figure>
}
</div>
And here's the result for the second attempt:
I'm not sure how your area routing is configured, but from the structure and url you provided, it looks like your configuration is incorrect.
I made a simple example, you can use it as a reference.
Models:
public class Car
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public CarDetail CarDetails { get; set; }
}
public class CarDetail
{
public int Id { get; set; }
public int CarId { get; set; }
public string Description { get; set; }
public Car Cars { get; set; }
}
ApplicationDbContext:
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<Models.Car> Car { get; set; }
public DbSet<Models.CarDetail> CarDetails { get; set; }
}
Index.cshtml.cs:
public class IndexModel : PageModel
{
private readonly ApplicationDbContext _context;
public IndexModel(ApplicationDbContext context)
{
_context = context;
}
public List<Car> carDtoReadList { get; set; }
public IActionResult OnGet()
{
carDtoReadList = _context.Car.ToList();
return Page();
}
}
Index.cshtml:
@page
@model IndexModel
@{
ViewData["Title"] = "Home page";
}
<div>
@foreach (var item in Model.carDtoReadList)
{
<div>
<figure>
<a asp-area="ProductDetails" asp-controller="ProductDetails" asp-action="Details" asp-route-id="@item.Id">
<figcaption>
<p>
@Html.DisplayFor(modelItem => item.Name)
</p>
<p>
@Html.DisplayFor(modelItem => item.Description)
</p>
</figcaption>
</a>
</figure>
</div>
}
</div>
Area structure:
ProductDetailsController:
[Area("ProductDetails")]
public class ProductDetailsController : Controller
{
private readonly ApplicationDbContext _context;
public ProductDetailsController(ApplicationDbContext context)
{
_context = context;
}
public IActionResult Index()
{
return View();
}
public async Task<IActionResult> Details(int? id)
{
if (id == null || _context.Car == null)
{
return NotFound();
}
var car = await _context.Car
.Where(c => c.Id == id)
.Include(x => x.CarDetails)
.FirstOrDefaultAsync();
if (car == null)
{
return NotFound();
}
return View(car);
}
}
Details.cshtml:
@model TestApp.Models.Car
<div>
<h1>Details</h1>
<div>
<label>@Html.DisplayNameFor(modelItem => Model.Name) :</label>
<span>@Html.DisplayFor(modelItem => Model.Name)</span>
</div>
<div>
<label>@Html.DisplayNameFor(modelItem => Model.Description) :</label>
<span>@Html.DisplayFor(modelItem => Model.Description)</span>
</div>
<div>
<label>@Html.DisplayNameFor(modelItem => Model.CarDetails.Description) :</label>
<span>@Html.DisplayFor(modelItem => Model.CarDetails.Description)</span>
</div>
</div>
Program.cs:
//...
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
//...
app.MapControllerRoute(
name: "MyArea",
pattern: "{area:exists}/{controller=ProductDetails}/{action=Index}/{id?}");
app.MapRazorPages();
app.Run();
Test Result:
Index:
Details:
For more details about Areas, you can check this document: Areas in ASP.NET Core.