asp.net Core 2 Custom Model Binder,复杂模型

时间:2017-10-16 11:56:17

标签: c# asp.net-core model-binding asp.net-core-2.0

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

我有一个构建示例并放在github

我有一个简单的Person类:

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; }
}

当我添加新人时,我可以选择带有HTML选择标记的国家/地区。但是select标签的值是国家标识,我希望绑定器在数据库中查找并将正确的国家/地区放入模型中。

Controller中的create方法如下所示:

    [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;
    }
}

问题是,我怎么能这样做,就像我在Binder的评论中写的那样? 任何想法或最佳实践解决方案?

问候克里斯

1 个答案:

答案 0 :(得分:3)

首先,这是对自定义模型绑定器的错误使用。数据访问应该在控制器中进行,因为这是控制器的责任。第二,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