如何使用BindProperty绑定HTML select的复杂Currency属性并重建对象
问题描述
我有如下模型:
public class MyModel { public MyModel(Guid id, string name, string description, Currency currency) { Id = id; Name = name; Description = description; Currency = currency; } public Guid Id { get; set; } public string Name { get; set; } public string Description { get; set; } public Currency Currency { get; set; } }
Currency类型定义如下:
public class Currency { public Currency(string numericCode, string code, string name) { NumericCode = numericCode; Code = code; Name = name; } public string NumericCode { get; set; } public string Code { get; set; } public string Name { get; set; } } // 使用示例 var currency = new Currency("978", "EUR", "Euro");
在我的Razor页面模型类中,我定义了:
[BindProperty] public MyModel MyModel { get; set; } [BindProperty] public IEnumerable<Currency> AllCurrencies { get; set; }
据此我可以在视图中渲染如下select元素:
<select class="form-select" asp-for="MyModel.Currency"> @foreach (var currency in Model.AllCurrencies) { if (currency.Code == Model.MyModel.Currency.Code) { <option value="??????" data-numericcode="@currency.NumericCode" data-code="@currency.Code" data-name="@currency.Name" selected="" @currency.Name</option> } else { <option value="??????" data-numericcode="@currency.NumericCode" data-code="@currency.Code" data-name="@currency.Name" @currency.Name</option> } } </select>
请问是否有办法指示模型绑定器,在客户端选择不同选项时重建Currency对象?
解决方案
当然可以,有几种实用方式实现这个需求:
1. 自定义模型绑定器
为Currency类型编写自定义模型绑定器,让ASP.NET Core在绑定阶段自动根据提交的值重建完整的Currency对象。
实现步骤:
- 创建绑定器类:
public class CurrencyModelBinder : IModelBinder { public Task BindModelAsync(ModelBindingContext bindingContext) { if (bindingContext == null) throw new ArgumentNullException(nameof(bindingContext)); // 获取提交的货币代码(对应option的value值) var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); if (valueProviderResult == ValueProviderResult.None) return Task.CompletedTask; bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult); var code = valueProviderResult.FirstValue; // 从服务或数据源中获取所有货币列表,这里示例用依赖注入获取 var allCurrencies = bindingContext.HttpContext.RequestServices.GetService<IEnumerable<Currency>>(); var currency = allCurrencies?.FirstOrDefault(c => c.Code == code); if (currency == null) { bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, "无效的货币选项"); return Task.CompletedTask; } bindingContext.Result = ModelBindingResult.Success(currency); return Task.CompletedTask; } }
- 给
Currency类标记绑定器特性:
[ModelBinder(BinderType = typeof(CurrencyModelBinder))] public class Currency { // 原类代码保持不变 }
- 修改视图中的option值为货币Code:
<option value="@currency.Code" data-numericcode="@currency.NumericCode" data-code="@currency.Code" data-name="@currency.Name" @(currency.Code == Model.MyModel.Currency.Code ? "selected" : "")> @currency.Name </option>
2. 后台手动重建(无需自定义绑定器)
如果不想编写绑定器,可在Post请求处理中手动根据提交的Code重建Currency对象:
- 视图中同样将option的value设为
@currency.Code - 在页面模型的Post方法中处理:
public async Task<IActionResult> OnPostAsync() { if (!ModelState.IsValid) { AllCurrencies = GetAllCurrencies(); // 重新加载货币列表 return Page(); } // 根据提交的Code匹配完整的Currency对象 var selectedCurrency = AllCurrencies.FirstOrDefault(c => c.Code == MyModel.Currency.Code); if (selectedCurrency != null) { MyModel.Currency = selectedCurrency; } else { ModelState.AddModelError("MyModel.Currency", "无效的货币选项"); AllCurrencies = GetAllCurrencies(); return Page(); } // 后续业务逻辑处理 return RedirectToPage("/Success"); }
3. 用asp-items简化视图渲染
可以借助ASP.NET Core的标签助手简化select的渲染代码:
- 在页面模型中生成
SelectList:
[BindProperty] public MyModel MyModel { get; set; } public SelectList CurrencySelectList { get; set; } public void OnGet() { var allCurrencies = GetAllCurrencies(); CurrencySelectList = new SelectList(allCurrencies, "Code", "Name", MyModel.Currency.Code); }
- 视图中直接使用标签助手:
<select class="form-select" asp-for="MyModel.Currency.Code" asp-items="Model.CurrencySelectList"> <option value="">请选择货币</option> </select>
提交后MyModel.Currency.Code会被自动赋值,之后按照方案2的逻辑在Post方法中重建完整的Currency对象即可。
内容的提问来源于stack exchange,提问作者Mammt
相关产品推荐
相关产品推荐

