asp.net 具有复杂模型的 Core 2 自定义模型绑定器

asp.net Core 2 Custom Model Binder with complex model

我在 asp.net 核心 2 中构建 Custom-Model-Binder 时遇到问题。 我读了这个 Tutorial 但这不是我需要的。

我有一个构建示例并穿上 github

我有一个像这样的简单人 Class:

public class Person
{
    public int ID { get; set; }

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

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

    [Required]
    [DisplayFormat(DataFormatString = "{0:dd.MMM.yyyy}")]
    public DateTime DateOfBirth {get;set;}

    [Required]
    public Country Country { get; set; }
} 

public class Country
{
    public int ID { get; set; }

    public string Name { get; set; }

    public string Code { get; set; }
}

当我添加一个新人时,我可以 select 带有 HTML select 标签的国家。但是 select 标签的值是国家 ID,我希望活页夹在数据库中查找并将正确的国家放入模型中。

控制器中的创建方法如下所示:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Create([Bind("ID,Firstname,Surename,DateOfBirth")] Person person, int Country)
    {
        ViewData["Countries"] = _context.Countries.ToList();

        if (ModelState.IsValid)
        {
            _context.Add(person);
            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        }
        return View(person);
    }

我还实现了一个 IModelBinder 来绑定数据:

 public class PersonEntityBinder : IModelBinder
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (bindingContext == null)
        {
            throw new ArgumentNullException(nameof(bindingContext));
        }

        // here goes the fun

        // looking for the countryId in the bindingContext

        // binding everything else except the CountryID

        // search the Country by countryID and put it to the model


        return Task.CompletedTask;
    }
}

问题是,我怎样才能像我在活页夹的评论中写的那样做到这一点? 有人有想法或最佳实践解决方案吗?

问候克里斯

首先,这是对自定义模型活页夹的错误使用。数据访问应该发生在控制器中,因为这是控制器的责任。第二,don't use [Bind]。喜欢认真。只是不要。太可怕了,它会杀死小猫。

像这样创建一个视图模型:

public class PersonViewModel
{
    public string FirstName { get; set; }
    public string Surname { get; set; }
    public DateTime DateOfBirth { get; set; }
    public int CountryID { get; set; }
}

那么,你有没有接受这个(不再需要[Bind]):

public async Task<IActionResult> Create(PersonViewModel model)

然后,在您的操作中,将发布的值映射到 Person 的新实例并通过从数据库中查找来填充 Country 属性:

 var person = new Person
 {
     FirstName = model.FirstName,
     Surname = model.Surname,
     DateOfBirth = model.DateOfBirth,
     Country = db.Countries.Find(model.CountryID)
 }

然后,照常保存 person