Why is data not transmitted to the controller? - asp.net-mvc

I have next form:
<form asp-controller="Chat" asp-action="AddFile" method="post" asp-route-chatId="#Model.ChatId" enctype="multipart/form-data">
<textarea id="messageInput" class="textInput" style="width: 80vh" name="messageInput"></textarea>
<div>
<input type="submit" id="sendButton" value="Send Message" />
<input type="file" class="inputfile " id="File" name="File" value="File"/>
<label for="File">Choose a file</label>
</div>
</form>
ViewModel
public class ChatFileViewModel
{
public long ChatId { get; set; }
public string messageInput { get; set; }
public IFormFile File { get; set; }
}
and post method:
[HttpPost]
public void AddFile([FromBody] ChatFileViewModel chatFile)
{ ... }
The issue is - every time i press submit it transfers ChatId correctly, while messageInput and File are null. I have no idea what it is, because i have exactly the same construction working correctly in the other part of my app.

Using [FromBody] To force Web API to read a simple type from the request body, but your object is complex contain string and int can not treat as simple type.
Remove FormBody, I reproduce and it worked
More about FormBody at https://learn.microsoft.com/en-us/aspnet/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api

You should remove the [FromBody] attribute, since your request data is in the form. [FromBody] is usually used to deal with data in the request body like JSON and XML
[HttpPost]
public void AddFile(ChatFileViewModel chatFile)
{ ... }
For more details, you can refer to Model binding.

if you need of want to specify binding then you can use [FromForm] because you correctly setup for into multipart/form-data but it depends on your other actions
public IActionResult AddFile([FromForm]ChatFileViewModel model)
if you use asp- tag helpers you can use them for controls as well
<form asp-controller="Home" asp-action="AddFile" method="post" asp-route-chatId="#Model.ChatId" enctype="multipart/form-data">
<textarea asp-for="messageInput" class="textInput" style="width: 80vh" name="messageInput"></textarea>
<div>
<input type="submit" id="sendButton" value="Send Message" />
<input type="file" class="inputfile " asp-for="File" />
<label asp-for="File">Choose a file</label>
</div>
</form>

Related

How to pass modified model back to Controller in ASP.NET Core

I have the following model:
public class Card
{
[DataType(DataType.Date)]
[BindProperty]
public DateTime Day { get; set; }
[BindProperty]
public string Field { get; set; }
}
The following Controller:
// GET: Card
public async Task<IActionResult> Index(DateTime? day)
{
return View(model);
}
public async Task<IActionResult> Refresh(DateTime? Day, string Field)
{
return RedirectToAction("Index", Day);
}
The following View:
#model Card
<h1>Cards</h1>
<div class="text-center">
<label asp-for="Day" class="control-label"></label>
<input asp-for="Day" class="form-control" />
</div>
<div class="text-center">
<label asp-for="Field" class="control-label"></label>
<select asp-for="Field" class="form-control" asp-items="ViewBag.Fields"></select>
</div>
<form asp-action="Refresh">
#Html.HiddenFor(x => x.Day)
#Html.HiddenFor(y => y.Field)
<input type="submit" value="Refresh" class="btn btn-default" />
</form>
No matter what I change, I always get the initial Day value back and null as the Field, like the Model has never been changed…
So how can I post back the modified model to my controller?
your form is submitting the values from the hidden fields which are rendered on the page when the view first loads and then they are never modified (which is why you are seeing the default initialization for Day and for Field). Your editable fields are outside of the form and are what you're editing but they never get submitted to the server. I think the main takeaway here for you is that forms only know about inputs that exist inside of them (unless you write some javascript magic to handle this but there is no reason to do so in this case)
You need to remove the hidden fields and put your editable fields inside the form as follows:
#model Card
<h1>Cards</h1>
<form method="post" asp-action="Refresh">
<div class="text-center">
<label asp-for="Day" class="control-label"></label>
<input asp-for="Day" class="form-control" />
</div>
<div class="text-center">
<label asp-for="Field" class="control-label"></label>
<select asp-for="Field" class="form-control" asp-items="ViewBag.Fields"></select>
</div>
<input type="submit" value="Refresh" class="btn btn-default" />
</form>
you can also change your controller action to:
[HttpPost]
public async Task<IActionResult> Refresh(Card card)
{
return RedirectToAction("Index", card.Day);
}

POSTing data in ASP.NET MVC 4

I'm currently working on an ASP.NET MVC 4 app. I'm pretty new to ASP.NET MVC. Right now, I have a form coded up like this:
<form role="form" method="post" action="/contact/new">
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<label for="name">Name</label>
<div id="name">
<input class="form-control" type="text" autocomplete="off" />
</div>
</div>
<div class="form-group">
<label for="gender">Gender</label>
<select id="gender" class="form-control">
<option value="m">Male</option>
<option value="f">Female</option>
</select>
</div>
<div class="form-group">
<label for="email">Email Address</label>
<input class="form-control" type="email" autocomplete="off" />
</div>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
My controller and action look like the following:
public class ContactController : Controller
{
public ActionResult New()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult New()
{
return View();
}
}
My challenge is, I do not know what to put for the parameters of the HttpPost action in the controller. What should I put here?
Thanks!
MVC is based on Model View Controller. you should have a model for the View and your view should be strongly typed to its model.
If you don't want strongly typed view with some Model class, you have to read the form data from Request:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult New(FormCollection form)
{
string Name = form["UserName"].ToString();
return View();
}
and add name attribute to your input elements:
<input class="form-control" type="text" name="UserName" autocomplete="off" />
you should see these few links for making understanding of strongly type view and form post:
Dyanmic VS Strong Typed Views
What is strongly typed View in asp.net mvc
Why we need Strongly typed View
First, you need to ensure that the /name/ attributes on your form controls are filled out.
Then, you should define a ViewModel class called NewContactViewModel and your ActionResult as such:
public class NewContactViewModel
{
public string name { get; set; }
public string gender { get; set; }
public string email { get; set; }
}
[HttpPost]
public ActionResult New(NewContactViewModel model)
{
}

mvc form cannot create an abstract class

I have a form with 2 select box. But when I click the submit button, there's an error saying "Cannot create an abstract class". I have no idea what is going wrong here
#using (Html.BeginForm("Add", "Admin")) {
<input type="submit" value="Add" class="btn btn-warning small-text custom-btn" />
<div class="select-box">
<select name="users[]" multiple size="35">#{ Html.RenderAction("UserList", "GroupsAndUsers"); }</select>
</div>
<div class="select-box">
<p class="blue-text bold-text">Groups</p>
<select name="group" size="35">#{ Html.RenderAction("GroupList", "GroupsAndUsers"); }</select>
</div>
<input type="hidden" name="RedirectToUrl" value="~/GroupsAndUsers/AddUsers" />
}
Admin/Add
[HttpPost]
public ActionResult Add(Array userIDs, int groupID, string RedirectToUrl)
{
return Redirect(RedirectToUrl);
}
Array is an abstract class, so MVC has no idea which specific Array implementation to create when binding the parameters. Try something like:
public ActionResult Add(int[] userIDs, int groupID, string RedirectToUrl)

Model binding two or more collections

Has anyone had any luck model binding two or more collections using the code posted by Phil Haack here: Model Binding To A List?
As an example, I have the below code.
public class Book {
public string Name { get; set; }
}
public class Author {
public string Name { get; set; }
}
public ActionResult Index(List<Book> books, List<Author> authors) {
// Will never model bind two collections.
}
The HTML that I have is:
<input type="hidden" name="books.index" value="1" />
<input type="text" name="books[1].Name" />
<input type="hidden" name="books.index" value="2" />
<input type="text" name="books[2].Name" />
<input type="hidden" name="authors.index" value="1" />
<input type="text" name="authors[1].Name" />
<input type="hidden" name="authors.index" value="1" />
<input type="text" name="authors[1].Name" />
The exception that I get is:
The parameters dictionary contains an invalid entry for parameter 'authors' for method 'System.Web.Mvc.ActionResult Index(System.Collections.Generic.List1[Book], System.Collections.Generic.List1[Author])' in 'HomeController'. The dictionary contains a value of type 'System.Collections.Generic.List1[Book]', but the parameter requires a value of type 'System.Collections.Generic.List1[Author]'. Parameter name: parameters
Am I doing something wrong or is this not supported by ASP.NET MVC?
Your problem is somewhere else, I was unable to reproduce. The following works fine for me:
Model:
public class Book
{
public string Name { get; set; }
}
public class Author
{
public string Name { get; set; }
}
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(List<Book> books, List<Author> authors)
{
return View();
}
}
View:
<% using (Html.BeginForm()) { %>
<input type="text" name="books[0].Name" value="book 1" />
<input type="text" name="books[1].Name" value="book 2" />
<input type="text" name="authors[0].Name" value="author 1" />
<input type="text" name="authors[1].Name" value="author 2" />
<input type="submit" value="OK" />
<% } %>
It successfully binds values back in the POST action.
UPDATE:
I confirm that this is a bug in ASP.NET MVC 3 RC2 which will be fixed in the RTM. As a workaround you could put the following in your Application_Start:
ModelMetadataProviders.Current = new DataAnnotationsModelMetadataProvider();

Basic Problem with Asp.net MVC UpdateModel(myClass)

In my Controller in a Asp.net MVC 1 app I want to use UpdateModel to populate a variable with POST data in my controller. I've looked at dozens of examples but even the most basic ones seem to fail silently for me.
Here's a very basic example that's just not working.
What am I doing wrong?
public class TestInfo
{
public string username;
public string email;
}
public class AdminController : Controller
{
public ActionResult TestSubmit()
{
var test = new TestInfo();
UpdateModel(test);//all the properties are still null after this executes
//TryUpdateModel(test); //this returns true but fields / properties all null
return Json(test);
}
}
//Form Code that generates the POST data
<form action="/Admin/TestSubmit" method="post">
<div>
<fieldset>
<legend>Account Information</legend>
<p>
<label for="username">Username:</label>
<input id="username" name="username" type="text" value="" />
</p>
<p>
<label for="email">Email:</label>
<input id="email" name="email" type="text" value="" />
</p>
<p>
<input type="submit" value="Login" />
</p>
</fieldset>
</div>
</form>
It looks like you're trying to get the controller to update the model based on the form elements. Try this instead:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult TestSubmit(TestInfo test)
{
UpdateModel(test);
return Json(test);
}
In your code, you're creating a new TestModel instead of letting the MVC runtime serialize it from the HttpPost. I've let myself get wrapped around the axel on this also, you're not the only one!
make properties of your public field:
public class TestInfo
{
public string username {get;set;}
public string email{get;set;}
}
I'm not too familiar with ASP.NET MVC, but shouldn't your TestSubmit method look more like this:
public ActionResult TestSubmit(TestInfo test)
{
UpdateModel(test);
return Json(test);
}
In the controller you should have two methods, one to respond to the GET, the other, if required is for responding to the POST.
So, firstly have a GET method:
public ActionResult Test ()
{
return View (/* add a TestInfo instance here if you're getting it from somewhere - db etc */);
}
Secondly, you'll need a POST method:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Test (TestInfo test)
{
return Json (test);
}
Notice that there's no UpdateMethod there, the ModelBinder would have done that for you.

Resources