Home > Back-end >  c# How to recieve two models and send a form with one model?
c# How to recieve two models and send a form with one model?

Time:03-01

First of all, this is a simplified version of my problem.

I have two models:

  • Person
  • Category

The problem is that I need two models. I have a form where I show the categories in a select input to then create a new Person.

In .cshtml i have:

@using WebApiClient.Models
@model dynamic

<h1> Form: add a person with a category</h1>

<form asp-action="formMultiple" enctype="multipart/form-data" method="post">
    <label [email protected] >Name</label>
    <input asp-for="@Model.Person.Name"  value= "@Model.Person.Name" />

    <label asp-for="Category" >Category</label>
    <select asp-for="Category">
    @foreach (var item in Model.Category){
        <option value="Category">@item.NameCategory</option>
    }
    </select>
    <input type="submit" value="Add person"  />
</form>

And i have in controller:

public async Task<IActionResult> formMultiple()
        {
            dynamic d = new ExpandoObject();
            var categories = await _client.GetCategoriesAsync();
            d.categories = categories;
            d.person = new Person();
            return View(d);
        }
public async Task<ActionResult> formMultiple(Person person);

Any ideas how to solve this problem? Thank you <3

CodePudding user response:

Based on a comment above:

CS1963 An expression tree may not contain a dynamic operation

Don't rely on dynamic for your view models. It's trivial to create classes which give you all of the static type safety that C# generally expects. dynamic can be a useful tool, but is not a drop-in replacement for anywhere you don't want to create a class.

Your view model could be as simple as (I'm guessing on a reasonable name):

public class CreatePersonVM
{
    public IEnumerable<Category> Categories { get; set; }
    public Person Person { get; set; }
}

Then you'd expect that type in the view:

@model CreatePersonVM

And supply it from the controller:

var model = new CreatePersonVM();
model.Categories = await _client.GetCategoriesAsync();
model.Person = new Person();
return View(model);

Just ensure that the elements in the <form> still create a Person object and that form can still post the values for that object to the POST action.

CodePudding user response:

There are couple of options

  1. Use a ViewModel with two properties (One for Person and One for Categories) - Best and Recommended option
  2. Use a ValueTuple with two items (One for Person and One for Categories) - It should be used for small amount of data
  3. Send Person Model to the view and have Categories in ViewBag or ViewData
  4. Send Person Model to the view and have an ajax call to fill the Categories dropdown

So I can give you sample for the second approach

Controller

public async Task<IActionResult> formMultiple()
{
    var categories = await _client.GetCategoriesAsync();
    var person = new Person();
    var model = (person, categories);
    return View(model );
}

View

@using WebApiClient.Models
@model (Person person, List<Category> categories)

<h1> Form: add a person with a category</h1>

<form asp-action="formMultiple" enctype="multipart/form-data" method="post">
    <label asp-for=person.Name >Name</label>
    <input asp-for="person.Name"  />

    <label asp-for="person.Category" >Category</label>
    <select asp-for="person.Category">
    @foreach (var item in Model.categories){
        <option value="@item.IdCategory">@item.NameCategory</option>
    }
    </select>
    <input type="submit" value="Add person"  />
</form>
If you can share your Person and Category model, then I can provide more precise code

  • Related