Asp.net core 为什么Bind属性似乎破坏了嵌套对象的模型绑定?

Asp.net core 为什么Bind属性似乎破坏了嵌套对象的模型绑定?,asp.net-core,asp.net-core-mvc,Asp.net Core,Asp.net Core Mvc,有人能帮我解决这个问题吗。我试图用bind param操作限制过度发布,但它似乎根本不起作用。当我删除Bind关键字时,一切都开始像符咒一样起作用 以下是代码示例: 查看模型: public class ProductCreateViewModel { public Product Product { get; set; } public ICollection<IFormFile> Images { get; set; } } [HttpPost] [Valida

有人能帮我解决这个问题吗。我试图用bind param操作限制过度发布,但它似乎根本不起作用。当我删除Bind关键字时,一切都开始像符咒一样起作用

以下是代码示例:

查看模型:

public class ProductCreateViewModel
{
    public Product Product { get; set; }
    public ICollection<IFormFile> Images { get; set; }
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Product.Id,Product.CategoryId,Product.Description,Product.Title")] ProductCreateViewModel productVM)
{
    if (ModelState.IsValid)
    {
        _context.Add(productVM.Product);
        await _context.SaveChangesAsync();
        return RedirectToAction("Index");
    }
    ViewData["CategoryId"] = new SelectList(_context.Categories.Include(c => c.Categories).Where(c => c.ParentCategoryId == null), "Id", "Name", productVM.Product.CategoryId);
    return View(productVM);
}
@model CatalogWebApp.Models.ProductsViewModels.ProductCreateViewModel

@{
    ViewData["Title"] = "Add Product";
    ViewData["BigPageTitle"] = "Products";
    ViewData["PageBoxTitle"] = "Add New Product";
}

<form asp-action="Create">
    <div class="form-horizontal">
        <div asp-validation-summary="ModelOnly" class="text-danger"></div>
        <div class="form-group">
            <label asp-for="Product.CategoryId" class="col-md-2 control-label"></label>
            <div class="col-md-10">
                <select name="Product.CategoryId" class ="form-control">
                    @foreach(Category item in (ViewBag.CategoryId as SelectList).Items)
                    {
                        <option value="@item.Id">@item.Name</option>
                        if (item.Categories != null && item.Categories.Count > 0)
                        {
                            foreach (var subCat in item.Categories)
                            {
                                <option value="@subCat.Id">--@subCat.Name</option>
                            }
                        }
                    }
                </select>
            </div>
        </div>
        <div class="form-group">
            <label asp-for="Product.Description" class="col-md-2 control-label"></label>
            <div class="col-md-10">
                <input asp-for="Product.Description" class="form-control" />
                <span asp-validation-for="Product.Description" class="text-danger" />
            </div>
        </div>
        <div class="form-group">
            <label asp-for="Product.Title" class="col-md-2 control-label"></label>
            <div class="col-md-10">
                <input asp-for="Product.Title" class="form-control" />
                <span asp-validation-for="Product.Title" class="text-danger" />
            </div>
        </div>
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
</form>

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

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
公共类ProductCreateViewModel
{
公共产品产品{get;set;}
公共ICollection映像{get;set;}
}
行动:

public class ProductCreateViewModel
{
    public Product Product { get; set; }
    public ICollection<IFormFile> Images { get; set; }
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Product.Id,Product.CategoryId,Product.Description,Product.Title")] ProductCreateViewModel productVM)
{
    if (ModelState.IsValid)
    {
        _context.Add(productVM.Product);
        await _context.SaveChangesAsync();
        return RedirectToAction("Index");
    }
    ViewData["CategoryId"] = new SelectList(_context.Categories.Include(c => c.Categories).Where(c => c.ParentCategoryId == null), "Id", "Name", productVM.Product.CategoryId);
    return View(productVM);
}
@model CatalogWebApp.Models.ProductsViewModels.ProductCreateViewModel

@{
    ViewData["Title"] = "Add Product";
    ViewData["BigPageTitle"] = "Products";
    ViewData["PageBoxTitle"] = "Add New Product";
}

<form asp-action="Create">
    <div class="form-horizontal">
        <div asp-validation-summary="ModelOnly" class="text-danger"></div>
        <div class="form-group">
            <label asp-for="Product.CategoryId" class="col-md-2 control-label"></label>
            <div class="col-md-10">
                <select name="Product.CategoryId" class ="form-control">
                    @foreach(Category item in (ViewBag.CategoryId as SelectList).Items)
                    {
                        <option value="@item.Id">@item.Name</option>
                        if (item.Categories != null && item.Categories.Count > 0)
                        {
                            foreach (var subCat in item.Categories)
                            {
                                <option value="@subCat.Id">--@subCat.Name</option>
                            }
                        }
                    }
                </select>
            </div>
        </div>
        <div class="form-group">
            <label asp-for="Product.Description" class="col-md-2 control-label"></label>
            <div class="col-md-10">
                <input asp-for="Product.Description" class="form-control" />
                <span asp-validation-for="Product.Description" class="text-danger" />
            </div>
        </div>
        <div class="form-group">
            <label asp-for="Product.Title" class="col-md-2 control-label"></label>
            <div class="col-md-10">
                <input asp-for="Product.Title" class="form-control" />
                <span asp-validation-for="Product.Title" class="text-danger" />
            </div>
        </div>
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
</form>

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

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
[HttpPost]
[ValidateAntiForgeryToken]
公共异步任务创建([Bind(“Product.Id,Product.CategoryId,Product.Description,Product.Title”)]ProductCreateViewModel productVM)
{
if(ModelState.IsValid)
{
_添加(productVM.Product);
wait_context.SaveChangesAsync();
返回操作(“索引”);
}
ViewData[“CategoryId”]=新的选择列表(_context.Categories.Include(c=>c.Categories)。其中(c=>c.ParentCategoryId==null),“Id”,“Name”,productVM.Product.CategoryId);
返回视图(productVM);
}
查看:

public class ProductCreateViewModel
{
    public Product Product { get; set; }
    public ICollection<IFormFile> Images { get; set; }
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Product.Id,Product.CategoryId,Product.Description,Product.Title")] ProductCreateViewModel productVM)
{
    if (ModelState.IsValid)
    {
        _context.Add(productVM.Product);
        await _context.SaveChangesAsync();
        return RedirectToAction("Index");
    }
    ViewData["CategoryId"] = new SelectList(_context.Categories.Include(c => c.Categories).Where(c => c.ParentCategoryId == null), "Id", "Name", productVM.Product.CategoryId);
    return View(productVM);
}
@model CatalogWebApp.Models.ProductsViewModels.ProductCreateViewModel

@{
    ViewData["Title"] = "Add Product";
    ViewData["BigPageTitle"] = "Products";
    ViewData["PageBoxTitle"] = "Add New Product";
}

<form asp-action="Create">
    <div class="form-horizontal">
        <div asp-validation-summary="ModelOnly" class="text-danger"></div>
        <div class="form-group">
            <label asp-for="Product.CategoryId" class="col-md-2 control-label"></label>
            <div class="col-md-10">
                <select name="Product.CategoryId" class ="form-control">
                    @foreach(Category item in (ViewBag.CategoryId as SelectList).Items)
                    {
                        <option value="@item.Id">@item.Name</option>
                        if (item.Categories != null && item.Categories.Count > 0)
                        {
                            foreach (var subCat in item.Categories)
                            {
                                <option value="@subCat.Id">--@subCat.Name</option>
                            }
                        }
                    }
                </select>
            </div>
        </div>
        <div class="form-group">
            <label asp-for="Product.Description" class="col-md-2 control-label"></label>
            <div class="col-md-10">
                <input asp-for="Product.Description" class="form-control" />
                <span asp-validation-for="Product.Description" class="text-danger" />
            </div>
        </div>
        <div class="form-group">
            <label asp-for="Product.Title" class="col-md-2 control-label"></label>
            <div class="col-md-10">
                <input asp-for="Product.Title" class="form-control" />
                <span asp-validation-for="Product.Title" class="text-danger" />
            </div>
        </div>
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
</form>

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

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
@model CatalogWebApp.Models.ProductsViewModels.ProductCreateViewModel
@{
ViewData[“Title”]=“添加产品”;
ViewData[“BigPageTitle”]=“产品”;
ViewData[“PageBoxTitle”]=“添加新产品”;
}
@foreach(中的类别项目(ViewBag.CategoryId作为SelectList)。项目)
{
@项目名称
如果(item.Categories!=null&&item.Categories.Count>0)
{
foreach(项目类别中的变量子类别)
{
--@子类别名称
}
}
}
返回列表
@节脚本{
@{wait Html.RenderPartialAsync(“_validationScript”);}
}

有人能指出我是否有问题,或者这只是一个已知的asp.net核心问题吗?

您需要以
参数字符串[]
的形式传递值,而不是以逗号分隔的单个
字符串的形式传递值:

[Bind("Product.Id","Product.CategoryId","Product.Description","Product.Title")]

请参见

我不太清楚您为什么在您的案例中使用
Bind

只需创建sepate
ViewModel
,只需使用
ProductCreateStort
等属性即可

然后在控制器签名中使用此
ViewModel
,并从中继承主模型


这样,您就不会弄乱
Bind
,也不会在POST上限制您的参数虽然我自己对ASP.NET Core还是相当陌生(并且晚了7个月才开始讨论这个问题),但我遇到了同样的问题。我认为这里的关键是,您必须绑定“产品”才能考虑它。单独绑定“Product.Id”似乎不够好。因此,这应该是可行的:

[Bind("Product,Product.Id,Product.CategoryId,Product.Description,Product.Title")]
当然,如果所有绑定属性都位于嵌套对象上,那么Hamid Mosalla的注释是一个更好的选择(这让人想知道为什么首先需要视图模型)。在我的例子中,我有一个嵌套对象和一个局部属性,所以使用“前缀”解决方案不是正确的做法


不管怎样,希望这对其他人有所帮助。

视图模型不应包含属于数据模型的属性。您查看的模型应包含属性
ID
CategoryId
说明
等-即您只需要在视图中查看。正确使用视图模型时,不需要使用
[Bind]
属性,也不需要为每个属性添加前缀,只需使用:
[Bind(“Id”、“CategoryId”、“Description”、“Title”、prefix=nameof(ProductCreateViewModel.Product))]
@StephenMuecke:我在阅读MS的原始文章后添加了DRY(不要重复)原则。但是发现文件上传有问题,因为它没有包含在帖子中,所以我添加了一个带有模型和IFromFile集合的VM。欲了解更多信息,请访问此处的帖子:谢谢,但我对阅读不好的文章不感兴趣:)创建该工具的作者写了这篇文章!这是多么糟糕。不管怎样,我从那里学到了很多东西。它们都很好用。无论如何,感谢您提供Prefix=nameof(ProductCreateViewModel.Product)参数!