You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core动态加载视图项绑定至控制器的问题求助

Hey there! Let's work through these two issues step by step—they're super common when building dynamic form sections in ASP.NET, so we’ll get this sorted.

1. Fixing Duplicate Indexes in Dynamic Partial Views

The problem here is that every time you load a new partial view, it starts generating form fields with indexes starting at 0. ASP.NET’s model binding gets confused when multiple items have the same index, so we need to make sure each dynamic product entry has a unique index.

Option 1: Manually Manage a Counter

This is straightforward if you want full control:

  • Add a counter variable in your main view’s JavaScript to track the next available index.
  • Pass this index to your partial view via AJAX, then use it to generate unique name attributes for form fields.

Main View JavaScript:

// Initialize counter with the number of existing products (if any)
let productIndex = $('#productsContainer .product-item').length;

$('#addProductBtn').click(function() {
    const selectedCompanyId = $('#CompanyDropdown').val(); // Get your selected company ID
    
    $.ajax({
        url: '/Orders/GetProductPartial',
        type: 'GET',
        data: { 
            companyId: selectedCompanyId,
            index: productIndex 
        },
        success: function(partialHtml) {
            $('#productsContainer').append(partialHtml);
            productIndex++; // Increment counter for next item
        }
    });
});

Partial View (强类型, e.g., _ProductPartial.cshtml):

@model YourApp.Models.ProductViewModel
@{
    int currentIndex = ViewData["Index"] as int? ?? 0;
}

<div class="product-item p-3 mb-2 border">
    <div class="mb-2">
        <label>型号:</label>
        @Html.DropDownListFor(
            m => m.ProductId, 
            ViewBag.ProductOptions as SelectList, 
            "选择型号",
            new { name = $"OrderViewModel.Products[{currentIndex}].ProductId", @class = "form-control" }
        )
    </div>
    <div class="mb-2">
        <label>数量:</label>
        @Html.TextBoxFor(
            m => m.Quantity,
            new { name = $"OrderViewModel.Products[{currentIndex}].Quantity", @class = "form-control" }
        )
    </div>
    <div class="mb-2">
        <label>价格:</label>
        @Html.TextBoxFor(
            m => m.Price,
            new { name = $"OrderViewModel.Products[{currentIndex}].Price", @class = "form-control" }
        )
    </div>
    <button type="button" class="btn btn-danger remove-product">移除</button>
</div>

Option 2: Use BeginCollectionItem (Automatic Unique Indexes)

If you want to avoid manual counter management, use the BeginCollectionItem helper—it generates a unique GUID-based index for each dynamic item, which ASP.NET’s model binding handles perfectly.

  1. Install the package: For ASP.NET Core, install HtmlHelpers.BeginCollectionItem via NuGet.
  2. Update your partial view:
@model YourApp.Models.ProductViewModel
@using HtmlHelpers.BeginCollectionItem

<div class="product-item p-3 mb-2 border">
    @using (Html.BeginCollectionItem("OrderViewModel.Products"))
    {
        <div class="mb-2">
            <label>型号:</label>
            @Html.DropDownListFor(m => m.ProductId, ViewBag.ProductOptions as SelectList, "选择型号", new { @class = "form-control" })
        </div>
        <div class="mb-2">
            <label>数量:</label>
            @Html.TextBoxFor(m => m.Quantity, new { @class = "form-control" })
        </div>
        <div class="mb-2">
            <label>价格:</label>
            @Html.TextBoxFor(m => m.Price, new { @class = "form-control" })
        </div>
        <button type="button" class="btn btn-danger remove-product">移除</button>
    }
</div>

With this, you don’t need to pass an index via AJAX—each new item gets a unique, model-binding-friendly name like OrderViewModel.Products[abc123-guid-456].ProductId.


2. Fixing Model Binding for the Product List

The root cause here is usually incorrect name attributes on form fields. ASP.NET needs specific naming patterns to bind dynamic collections:

  • For manual indexing: OrderViewModel.Products[N].PropertyName (where N is a unique integer)
  • For BeginCollectionItem: OrderViewModel.Products[UniqueGuid].PropertyName

As long as you follow either of the above approaches, your controller will correctly receive the full list of products in the OrderViewModel.

Controller Example:

[HttpPost]
public IActionResult Create(OrderViewModel model)
{
    if (ModelState.IsValid)
    {
        // model.Products will contain all dynamically added items
        _orderService.CreateOrder(model);
        return RedirectToAction("Index");
    }
    // Repopulate dropdowns and return view if invalid
    return View(model);
}

Bonus: Remove Item Logic

Add this JavaScript to handle removing items without breaking model binding (since ASP.NET doesn’t require consecutive indexes):

$(document).on('click', '.remove-product', function() {
    $(this).closest('.product-item').remove();
});

内容的提问来源于stack exchange,提问作者Muhammad Sami

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 20:37:33