locked
Binding to a complex ViewModel RRS feed

  • Question

  • User1434241939 posted

    I have a model class called linksmvccore.  It's just a link number with IDs pointing to data in 2 other tables

        [Table("linksmvccore")]
        public partial class Linksmvccore
        {
            [Key]
            [Column(TypeName = "int(11)")]
            public int LinkNumber { get; set; }
            [Column("BagID", TypeName = "int(11)")]
            public int? BagId { get; set; }
            [Column("PersonID", TypeName = "int(11)")]
            public int? PersonId { get; set; }
        }
    

    I also have a compound ViewModel

            public class AllLinkViewModel
            {
                public Bagsmvc Bag { get; set; }
                public Peoplemvc Person { get; set; }
                public Linksmvccore Link { get; set; }
                public List<Peoplemvc> People { get; set; }
                public List<Bagsmvc> Bags{ get; set; }
                public List<Linksmvccore> Links { get; set; }
    }

    And here's the edit view

    @model BagContext.AllLinkViewModel
    
    @{
        ViewData["Title"] = "Edit";
    }
    
    <h1>Edit</h1>
    
    <div class="row">
        <div class="col-md-4">
            <form asp-action="Edit">
                <input type="hidden" asp-for="Link.LinkNumber" />
                <div class="form-group">
                    <label asp-for="Link.BagId" class="control-label"></label>
                    <input asp-for="Link.BagId" class="form-control" />
                </div>
                <div class="form-group">
                    <label asp-for="Link.PersonId" class="control-label"></label>
                    <input asp-for="Link.PersonId" class="form-control" />
                </div>
    
                <input type="submit" value="Save" asp-route-everything="@Model" class="btn btn-primary" />
                </div>
            </form>
        </div>
    </div>
    
    
    

    I can pass the model to the Edit controller successfully like this

            [HttpPost]
            [ValidateAntiForgeryToken]
            public async Task<IActionResult> Edit(int id, AllLinkViewModel alvm) {
    
    ...
    
    }

    But I am unable to prevent overbinding

            [HttpPost]
            [ValidateAntiForgeryToken]
            public async Task<IActionResult> Edit(int id,      
                   [Bind("Link.LinkNumber,BagId,Link_PersonId")] AllLinkViewModel alvm)

    I've tried 3 different ways of Binding but none of them will bind with the model.  How can I prevent overbinding here?

    Monday, June 1, 2020 9:24 PM

Answers

  • User711641945 posted

    Hi stevebo,

    It seems you just want to bind the Link data in the AllLinkViewModel,change like below:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Index(int id, [Bind("Link")] AllLinkViewModel alvm)
    {
    }

    After adding `[Bind("Link")]`,you could only receive the data in Link,the other child model in AllLinkViewModel should be null.

    If you also need to specify the received property in Link,add the additional code like below:

    [Bind("PersonId,LinkNumber")]
    [Table("linksmvccore")]
    public partial class Linksmvccore
    {
        [Key]
        [Column(TypeName = "int(11)")]
        public int LinkNumber { get; set; }
        [Column("BagID", TypeName = "int(11)")]
        public int? BagId { get; set; }
        [Column("PersonID", TypeName = "int(11)")]
        public int? PersonId { get; set; }
    }

    Best Regards,

    Rena

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Tuesday, June 2, 2020 2:58 AM

All replies

  • User-474980206 posted

    just define a post back model (don't see the hidden form field required for anti forgery):

    public class LinkPostBack
    {
       public int id {get; set;} // don't really see this in form - make int? if optional
       public Linksmvccore Link { get; set; }   
    }
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Edit(LinkPostBack model) {
    

    Monday, June 1, 2020 9:43 PM
  • User1434241939 posted

    just define a post back model

    That works fine to get the Model into the Controller but I still don't know how to set up the bindings for the subclass.

    Monday, June 1, 2020 11:30 PM
  • User475983607 posted

    That works fine to get the Model into the Controller but I still don't know how to set up the bindings for the subclass.

    Can you clarify?  You are using inheritance?

    Monday, June 1, 2020 11:50 PM
  • User711641945 posted

    Hi stevebo,

    It seems you just want to bind the Link data in the AllLinkViewModel,change like below:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Index(int id, [Bind("Link")] AllLinkViewModel alvm)
    {
    }

    After adding `[Bind("Link")]`,you could only receive the data in Link,the other child model in AllLinkViewModel should be null.

    If you also need to specify the received property in Link,add the additional code like below:

    [Bind("PersonId,LinkNumber")]
    [Table("linksmvccore")]
    public partial class Linksmvccore
    {
        [Key]
        [Column(TypeName = "int(11)")]
        public int LinkNumber { get; set; }
        [Column("BagID", TypeName = "int(11)")]
        public int? BagId { get; set; }
        [Column("PersonID", TypeName = "int(11)")]
        public int? PersonId { get; set; }
    }

    Best Regards,

    Rena

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Tuesday, June 2, 2020 2:58 AM
  • User1434241939 posted

    OMG, thank you that works!  I think I understand binding a little better now.

    But one question about Binding in the model

    [Bind("PersonId,LinkNumber")]

    What if my Create and Edit actions require different fields?  For example"

    [Bind("LinkNumber,BagId,PersonId")]  // Fields that Create can modify
    
    
    [Bind("LinkNumber,BagId")]  // Fields that Edit can modify

    It's not important for what I'm doing now, but someday I might encounter this requirement.

    Thank you for your very helpful response.

    Tuesday, June 2, 2020 12:16 PM
  • User475983607 posted

    See the following blog for different ways to handle over posting.

    https://andrewlock.net/preventing-mass-assignment-or-over-posting-in-asp-net-core/

    Ex.

    public IActionResult Safe1([Bind(nameof(UserModel.Name))] UserModel model)
    {
        return View("Index", model);
    }

    Tuesday, June 2, 2020 1:00 PM