ASP.NET MVC 应用程序:表单重定向到不存在的页面,而不是将数据保存到数据库

问题描述 投票:0回答:1

我正在开发一个 ASP.NET MVC 应用程序,我在其中创建了一个包含所有必要的 MVC 组件(模型、视图、控制器)的产品页面。但是,当用户填写产品页面上的表单并提交时,应用程序不会将新产品保存到数据库中。相反,它会重定向到一个不存在的页面。

我想要实现的目标

在产品页面,用户可以填写表单来创建新产品。目标是在提交表单时将产品详细信息保存到数据库中。

实际发生了什么

应用程序不会将新产品保存到数据库,而是在提交表单后重定向到不存在的页面。

预期行为

提交表单后,新产品应保存到数据库中,并且用户应重定向到确认页面或产品列表。

我尝试过的:

  • 我检查了program.cs中的路由配置并确认路由应该正确映射。
  • 我确认表单方法设置为POST。
  • 我验证了模型并确保其正确。

模型类:

namespace My_Name_Space.Models
{
    public class Product
    {
        [Required]
        [Key]
        public  int Id { get; set; }
        
        [Required]
        public  string Name { get; set; }
        
        [Required]
        public  string Description { get; set; }

        [Required]
        [Range(0, double.MaxValue, ErrorMessage = "Price must be a positive number.")]
        public  string Price { get; set; }

        [Required]
        public  string ImageUrl { get; set; }

        [Required]
        [Range(0, int.MaxValue, ErrorMessage = "Stock must be a non-negative integer.")]
        public int Stock { get; set; }
    }
}

控制器:

public async Task<IActionResult> ManageProducts()
{
    var products = await _context.Products.ToListAsync();
    return View(products);
}

/* Manage Product Create GET*/
public IActionResult CreateProducts()
{
    return View();
}
 
/*  add actions to create, edit, and delete products*/
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> CreateProducts(Product product)
{
    if (ModelState.IsValid)
    {
          _context.Add(product);
          await _context.SaveChangesAsync();
          return RedirectToAction(nameof(ManageProducts));
    }
    else
    {
          // Inspect the ModelState to understand why it's not valid //
          var errors = ModelState.Values.SelectMany(v => v.Errors);
    }

    return View(product);
}

查看:

<form asp-action="CreateProduct" asp-controller="Admin" method="post">
    <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="Price" class="control-label"></label>
        <input asp-for="Price" class="form-control" />
        <span asp-validation-for="Price" class="text-danger"></span>
    </div>
    <div class="form-group">
        <label asp-for="Stock" class="control-label"></label>
        <input asp-for="Stock" class="form-control" />
        <span asp-validation-for="Stock" class="text-danger"></span>
    </div>
    <div class="form-group">
        <label asp-for="ImageUrl" class="control-label"></label>
        <input asp-for="ImageUrl" class="form-control" />
        <span asp-validation-for="ImageUrl" class="text-danger"></span>
    </div>

    <div class="form-group">
        <button type="submit" value="Create" class="btn btn-primary">Create</button>
       
    </div>
</form>
<script>

    <script src="~/js/create-product.js"></script>
</script>

site.js
脚本:

document.addEventListener("DOMContentLoaded", function () {
    // Image URL preview functionality
    const imageUrlInput = document.querySelector('input[name="ImageUrl"]');
    const imagePreview = document.createElement('img');
    imagePreview.id = 'imagePreview';
    imageUrlInput.parentNode.appendChild(imagePreview);

    imageUrlInput.addEventListener("input", function () {
        const url = imageUrlInput.value;
        if (url) {
            imagePreview.src = url;
            imagePreview.style.display = 'block';
        } else {
            imagePreview.style.display = 'none';
        }
    });
});

Program.cs
中映射控制器:

//other essential services

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.MapControllerRoute(
    name:"admin",
    pattern: "{controller=Admin}/{action=ManageProducts}/{id?}");

app.MapControllerRoute(
    name: "login",
    pattern: "Login",
    defaults: new { controller = "Login", action = "Index" });

文件结构:

ProjectName/
     │
     ├── Controllers/
     │   └── ProductController.cs
     │
     ├── Models/
     │   └── Product.cs
     │
     ├── Views/
     │   └── Admin/
     │       ├── CreateProduct.cshtml
     │       └── Index.cshtml
     │
     ├── wwwroot/
     |   ├── css/
     |   |     └── site.css
     │   └── js/
     |       └── create-product.js
     │
     │
     ├── appsettings.json
     └── program.cs

深深感谢每一个帮助,请原谅我的菜鸟代码,如果我做错了什么,请告诉我!

c# asp.net-mvc forms entity-framework asp.net-core
1个回答
0
投票

根据您提供的代码和相关项目结构,您的预期行为可以通过

Admincontroller
实现。

应用程序不会将新产品保存到数据库中。 相反,它会重定向到一个不存在的页面。

问题的原因是,在你的表单中,提交的对应方法是

Admincontroller/CreateProduct
,但是在你的项目结构中,你的Controllers中定义的控制器名称是
Productcontroller
,所以表单提交后无法正确匹配方法已提交。您可以将
Productcontroller
更改为
Admincontroller

其次,在控制器方法中,View方法的默认行为

return View();
是返回一个与调用它的action方法同名的视图,因此方法名称需要与视图名称相对应.

例如:如果控制器中的方法名称是

CreateProducts
,那么对应的视图名称也应该是
CreateProducts
,而不是
CreateProduct
。并且表单提交对应的方法应该是
Admincontroller/CreateProducts
而不是
Admincontroller/CreateProduct
。否则,路由将无法正确匹配方法。

并且在你的路由配置中,只为控制器配置了默认的操作方法,即 ManageProducts。如果您有更多自定义路由配置,可以参考此文档进行配置:https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/routing?view=aspnetcore-8.0.

用户应该被重定向到确认页面或列表 产品。

如果您想重定向到像

ManageProducts
这样的单独页面,那么您需要在
Views/Admin
文件夹中创建相应的页面ManageProducts。这是一个完整的示例供您参考:

控制器:

 public class AdminController : Controller
 {
     private readonly ApplicationDbContext _dbContext;
     public AdminController(ILogger<HomeController> logger, ApplicationDbContext dbContext)
     {
         
         _dbContext = dbContext;
     }

     public IActionResult Index()
     {
         return View();
     }
     public async Task<IActionResult> ManageProducts()
     {
         var products = await _dbContext.Products.ToListAsync();
         return View(products);
     }

     /* Manage Product Create GET*/
     public IActionResult CreateProducts()
     {
         return View();
     }

     /*  add actions to create, edit, and delete products*/
     [HttpPost]
     [ValidateAntiForgeryToken]
     public async Task<IActionResult> CreateProducts(Product product)
     {
         if (ModelState.IsValid)
         {
             _dbContext.Products.Add(product);
             await _dbContext.SaveChangesAsync();
             return RedirectToAction("ManageProducts");
         }

         return View(product);
     }
 }

视图/管理/创建产品:

@model Product

<form asp-action="CreateProducts" asp-controller="Admin" method="post">
    <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="Price" class="control-label"></label>
        <input asp-for="Price" class="form-control" />
        <span asp-validation-for="Price" class="text-danger"></span>
    </div>
    <div class="form-group">
        <label asp-for="Stock" class="control-label"></label>
        <input asp-for="Stock" class="form-control" />
        <span asp-validation-for="Stock" class="text-danger"></span>
    </div>
    <div class="form-group">
        <label asp-for="ImageUrl" class="control-label"></label>
        <input asp-for="ImageUrl" class="form-control" />
        <span asp-validation-for="ImageUrl" class="text-danger"></span>
    </div>

    <div class="form-group">
        <button type="submit" value="Create" class="btn btn-primary">Create</button>

    </div>
</form>

查看/管理/管理产品:

@model IEnumerable<Product>

@{
    ViewData["Title"] = "Manage Products";
}

<h2>Manage Products</h2>

<table class="table table-striped">
    <thead>
        <tr>
            <th>Name</th>
            <th>Description</th>
            <th>Price</th>
            <th>Stock</th>
            <th>Image</th>
            <th>Actions</th>
        </tr>
    </thead>
    <tbody>
        @foreach (var product in Model)
        {
            <tr>
                <td>@product.Name</td>
                <td>@product.Description</td>
                <td>@product.Price</td>
                <td>@product.Stock</td>
                <td>
                    <img src="@product.ImageUrl" alt="@product.Name" style="width: 100px; height: auto;" />
                </td>
                <td>
                    <a asp-action="EditProduct" asp-route-id="@product.Id" class="btn btn-warning">Edit</a>
                    <a asp-action="DeleteProduct" asp-route-id="@product.Id" class="btn btn-danger">Delete</a>
                </td>
            </tr>
        }
    </tbody>
</table>

当我提交相关信息时: enter image description here

我们可以看到可以正常重定向到列表页面并保存成功: enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.