25

I catch post request from 3rd-side static page (generated by Adobe Muse) and handle it with MVC action.

<form method="post" enctype="multipart/form-data">
   <input type="text" name="Name">
   ...
</form>

Routing for empty form action:

app.UseMvc(routes => routes.MapRoute(
   name: "default",
   template: "{controller=Home}/{action=Index}"));

But in according action I have model with every property is empty

Action:

[HttpPost]
public void Index(EmailModel email)
{
   Debug.WriteLine("Sending email");
}

Model:

public class EmailModel
{
    public string Name { get; set; }
    public string Email { get; set; }
    public string Company { get; set; }
    public string Phone { get; set; }
    public string Additional { get; set; }
}

Request.Form has all values from form, but model is empty

[0] {[Name, Example]}
[1] {[Email, [email protected]]}
[2] {[Company, Hello]}
[3] {[Phone, Hello]}
[4] {[Additional, Hello]}
4
  • 1
    Why do you use enctype="multipart/form-data"? You don't need to specify this because your model doesn't contain any file upload. Probably your problem causes from this. Remove and try. Commented Oct 21, 2016 at 8:54
  • 1
    @ademcaglin removed enctype attribute. Doesn't help. Still Request.Form has all values, but model is empty. Commented Oct 21, 2016 at 9:01
  • Did you use any javascript code to send form? Commented Oct 21, 2016 at 9:02
  • @ademcaglin no, just pure form submit Commented Oct 21, 2016 at 9:10

10 Answers 10

58

Be careful not to give an action parameter a name that is the same as a model property or the binder will attempt to bind to the parameter and fail.

public async Task<IActionResult> Index( EmailModel email ){ ... }

public class EmailModel{ public string Email { get; set; } }

Change the actions parameter 'email' to a different name and it will bind as expected.

public async Task<IActionResult> Index( EmailModel uniqueName ){ ... }
Sign up to request clarification or add additional context in comments.

6 Comments

Thanks! I had a property named "Model" in my view model which broke the binding.
Seems like ASP.NET Core's model binding code could throw us a bone by maybe throwing an exception in this case!
I mean... Wow.. This is something I couldn't find on my own.
You are my angel!
Well, that's an hour of pointless debugging I'm never getting back.
|
4

I'm not sure it is same case, but I had same problem and nothing really looks to work for me.
The problem in my case was that I had a property called Model in my view model class

public string Model { get; set; }

When I renamed the property to ModelName everything was working fine again, even without FromForm attribute.

Looks like some special property names could be a bit of a problem for asp.net mvc model binding.

So, my advice is to check your model properties and maybe try renaming them one by one in order to check if the problem is there.

Hope this helps.

Comments

3

ASP.Net Core 3.1

In my case, I was using a complex model (a model that contains other models, like a shared model) posted by Ajax, so the inputs in the view were automatically named like this "ChildModel.PropertyName" (see code)

   [HttpPost]
   [ValidateAntiForgeryToken] // ("AUVM.PropertyName")
   public async Task<JsonResult> AddUser([FromForm]AUVM aUVM) //Parameter name must match the first part of the input name in order to bind
   {

   }
   [HttpPost]
   [ValidateAntiForgeryToken]
   public async Task<JsonResult> AddUser([FromForm]AUVM someUniqueName) //This is wrong and won't bind
   {

   }

Comments

1

I'm having the same problem this docs helps me to understand Model Binding https://docs.asp.net/en/latest/mvc/models/model-binding.html

I solved my problem by making sure that the property name is exact match in form field name and I also add [FromForm] attribute to specify exactly the binding source.

Comments

1

I ran into this today, and though in hindsight it seems obvious, just thought I'd add that you need to make sure your access modifiers for the Properties on the model you're binding are correct. I had public MyProperty { get; internal set; } on some and they would not bind. Removed internal and they worked just fine.

1 Comment

OMG that's the problem I had. I would have never figured this out without your awesome help. Thank you!!
1

I have run in to this issue where the model does not bind when I have more than one constructor on the underlying model like:

public class EmailModel
{
    public EmailModel()
    {}

    public EmailModel(string _name, string _company)
    {
        Name = _name;
        Company = _company;
    }
    public string Name { get; set; }
    public string Email { get; set; }
    public string Company { get; set; }
    public string Phone { get; set; }
    public string Additional { get; set; }
}

Fixed by removing all but one constructor like this:

public class EmailModel
{
    public EmailModel()
    {}

    public string Name { get; set; }
    public string Email { get; set; }
    public string Company { get; set; }
    public string Phone { get; set; }
    public string Additional { get; set; }
}

Comments

1

I had the same problem and I want to share what happened in my case and how I got the solution. Perhaps, someone may find it useful to know.

My context was ASP.NET Core 3.1 Razor pages. I had a handler as

public async Task<JsonResult> OnPostLogin([FromForm] LoginInput loginData)
{
  
}

and also I had a property in my ViewModel as

  public LoginInput LoginInput { get; set; }

And in my Razor page, I have used the form like this:

 <form asp-page-handler="Login" method="post">

 <input asp-for="LoginData.UserNameOrEmail">

 .....
 
        

So, notice that, in my form, I used the property LoginInput.UserNameOrEmail, but in my handler's parameter, I used the parameter name loginData. How will the ASP.NET Core know that, this LoginInput.UserNameOrEmail is actually loginData.UserNameOrEmail. It can't, right? Therefore, it did not bind my form data.

Then, when I renamed my ViewModel property "LoginInput" to the same name as the handler parameter, like this:

public LoginInput LoginData { get; set; }

The ASP.NET Core then found that the form data was matching the parameter name and then it started to bind properly. My problem was solved.

Comments

0

Change void to ActionResult.

[HttpPost]
public ActionResult Index(EmailModel email)

And don't forget verifying AntiForgeryToken from your view and action.

// to your form in view 
@Html.AntiForgeryToken()
// ------------

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(EmailModel email)

3 Comments

Doesn't help. Also I can't use AntiForgeryToken because this page is not mine and generated by 3rd party tools (Adobe Muse)
I think you can't get it as model with a tool which is not in action view. You can try to get value with form get method, and not as a model. By paramater names. Index(string Name, String Email, String Company, String Phone). And convert this values to your object model in procedure.
I also think mvc can't find model or something, and yes I can just use a bunch of action parameters, or fill it with Request.Form in action, or try to do that with IModelBinder, I just want to understand why I can't just use default model binding. Maybe I missed some conventions?
0

This issue can also happen if one or more of your properties in the request model fail to bind into an acceptable on the request model.

In my case, I was supposed to pass a List<string> type to a property, but accidentally passed a string. This resulted in the entire request model becoming null

Comments

0

In my case, I was using the MVC 4.0 convention of naming the object you are posting. E.g.,

js: $http.post("SaveAnswer", { answer: answerValues })

C#: public ActionResult SaveAnswer([FromBody] AnswerVM answer) {...}

When I changed the js to $http.post("SaveAnswer", answerValues), everything works.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.