ASP.NET MVC - POST parameters - asp.net-mvc

I have a view which contains multiple partial views, each of which is collecting information to populate different entity objects. My question is, upon the POST, how do I get a collection of objects that are populated with the right properties as a parameter to the Controller POST handler method?
so I would like something like this:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(List<object> objectCollection)
{
}

You got various options. Common one is to use default model binder. You just need to follow some naming (of html input elements) rules.
Advanced options are to use ActionFilters and custom model binders.
I recommend you to read this and this article.

Use FormCollection e.g...
public ActionResult Create(FormCollection frm)
{
Book book = new Book();
book.Name = frm["Name"];
// other work
return View();
}

Related

Create and assign value back from View bag to Text box in MVC

I have to create a textbox from a viewbag property in MVC. I could do the mapping like #Html.TextBox("Comments", (string)ViewBag.Comments) but how do I read it back when the page is posted to the server. It is not filling the viewbag property back. I am very new to MVC so maybe don't understand the concept totally .
Thanks
Your ViewBag wont get updated from your view and that is not the way to get data from your form. Rather, you should either use strongly typed model binding to read your data from your Action Method or you can simply check for the key in your Forms data. I am showing you example for both:
Example 1: Strongly typed model binding.
[HttpPost]
public ActionResult MyAction(string comments)
{
// the Comment from the text box.
return View();
}
Example 2: Reading from Posted Data:
[HttpPost]
public ActionResult MyAction()
{
// the Comment from the text box.
string comments = Request.Form["comments"];
return View();
}
I hope, you will like to use the Example 1.
Anyway, the best practice would be to bind your View with a Model class and use HtmlHelper for generating the text box like :
Html.EditorFor(model => model.Comments)
Where your Model class contains a property named Comments.
And your action method should accept the same Model type as argument. Here is an example:
[HttpPost]
public ActionResult MyAction(MyModel model)
{
string comments = model.Comments;
}
And you should bind your View with the model of type MyModel.
I can understand that, as you are new to MVC, this may not make clear sense now, so, I would suggest you to check out some basic MVC tutorial. You can start from here : http://www.asp.net/mvc/tutorials

Populating multiple table data in multiple dropdownlists on one page in ASP.Net MVC4

Being a newbie, please excuse my trivial question. (ASP.Net MVC4)
After reading lots of posts/tutorials I am still not sure about how to approach. What I am trying to do is have three Dropdownlists on my Index page. For instance, Country, Company, Branch. I have same data model for them which are linked to my database using EF. I have managed to just list all the data on the Index Page. However I need them inside the dropdownlist.
Question is how do I create the controller for that? Currently the controller looks like:
public class HomeController : Controller
{
private CorpCostEntities db = new CorpCostEntities();
public ActionResult Index()
{
return View();
}
...
...
}
Do I need to create separate ActionResult methods for each table to populate data? Or do I use method overload for Index(), such as Index(Country country), Index(Company comp), Index(Branch branch)?
Next question is since there will be difefernt ActionResult methods, do I need to create separate Views for that? I am using simple MVC structure. I don't have ViewModel or something other than MVC.
What exactly the approach to first create the controller for a multiple dropdownlists and then show them in an existing View page?
Thanks for help in advance.
No, you shouldn't need a separate action for each type, I would just toss those values in the ViewBag and read in the view (Here is how to load it into dropdown element):
public class HomeController : Controller
{
private CorpCostEntities db;
public HomeController(){
db = new CorpCostEntities();
ViewBag.CountryList = db.GetCountryList();
ViewBag.CompanyList = db.GetCompanyList();
ViewBag.BranchList = db.GetBranchList();
}
public ActionResult Index()
{
return View();
}
}
Regarding "Next question is since there will be difefernt ActionResult methods, do I need to create separate Views for that?", I am kind of unclear as to what you are asking, but I will give it a go on assumptions....Think of your (GET)ActionResults as pages (your action methods aren't just locked into returning 'pages', but bear with me). Say you have a Action "index" that displays a list of Customers, you would have your Index Action and Index view. Now, add an Edit screen, that will be another Action, Edit, and View, Edit.cshtml.
You might also want to consider to create a ViewModel (CorpCastViewModel) that contains all objects needed to render the view.
You would then have a propertie for the actual CorpCostModel, but also properties for your lookup collections and other stuff you need in your view.
Than you can create an editor as follows:
#Html.EditorFor(model => model.CorpCostModel.SomeField)
and a listbox as
#Html.DropDownListFor(model => model.CorpCostModel.CorpCountryId, new SelectList(Model.CountryList, "CountryId", "CountryName"), "")

Can you remove the HTML Field Prefix from strongly typed models in MVC 3?

I have a view model like this:
public class EditVM
{
public Media.Domain.Entities.Movie Movie { get; set; }
public IEnumerable<Genre> Genres { get; set; }
}
Movie is the real entity I wish to edit. Genres is simply present to populate a drop down. I would prefer that when I call:
#Html.TextBoxFor(m => m.Movie.Title)
inside my strongly typed view that the input control have a name = "Title" instead of "Movie.Title"
I do not wish to split my view into partial views or lose my strongly typed view by using ViewData or the like.
Is there a way to express to the View that I do not wish to have the Movie. prefix? I noticed that you can set:
ViewData.TemplateInfo.HtmlFieldPrefix = "x";
in the controller, but unfortunately it seems only to allow adding an additional prefix. Setting it to "" does nothing.
Is there any work around for this? Or am I stuck with the unfortunate prefix that isn't really necessary in this case if I wish to keep strongly typed views and lambdas?
Thanks for any help.
Update:
Here's the controller actions to maybe make things a bit clearer.
public ActionResult Edit(int? id)
{
var vm = new EditVM
{
Movie = id.HasValue ? _movieSvc.Find(id.Value) : new Movie(),
Genres = AppData.ListGenres()
};
return View(vm);
}
[HttpPost]
public void Edit([Bind(Prefix = "Movie")]Movie m)
{
_movieSvc.AddOrUpdateMovie(m); //Exceptions handled elsewhere
}
No, in order to do what you want you would have to rewrite the Html helpers, and then you would have to write your own model binder. Seems like a lot of work for minimal gain.
The only choice is a Partial view in which you pass the Movie object as the model. However, this would require you to write your own model binder to have it be recognized.
The reason you have to do m.Movie.Title is so that the ID has the correct name, so the model binder can recognize it as a member of your model.
Based on your update:
Your options are:
Use non-strongly typed helpers.
Use a partial view.
Rewrite the stronly typed helpers
Don't use the helpers at all, and write the values to the HTML
Personally, i'd just use 1 or 2, probably 2.
EDIT:
Based on your update above. Change your code to this (note, Genres does not get posted back to the server, so m.Genres will just be null on postback):
[HttpPost]
public void Edit(EditVM m)
{
_movieSvc.AddOrUpdateMovie(m.Movie); //Exceptions handled elsewhere
}
EDIT:
I did just think of an alternative to this. You could simply do this:
#{ var Movie = Model.Movie; }
#Html.TextBoxFor(m => Movie.Title)
However, if there was a validation error, you would have to recreate your EditVM.
I have a view model like this
I think that you might have some misunderstanding about what a view model is. A view model shouldn't contain any reference to your domain models which is what those Movie and Genre classes seem to be. I mean creating a new class that you suffix with VM and in which you stuff all your domain models as properties is not really a view model. A view model is a class that is specifically designed to meet the requirements of your view.
A much more correct view model would looks like this:
public class EditVM
{
public string MovieTitle { get; set; }
public IEnumerable<GenreViewModel> Genres { get; set; }
}
and in your view you would have:
#Html.EditorFor(x => x.MovieTitle)
#Html.EditorFor(x => x.Genres)
Another option is to either use the TextBox(string name, object value) overload instead of the TextBoxFor:
#Html.TextBox("Title", Model.Movie.Title)
You could also specify the input tag HTML instead of using a helper.
Another option is to take EditVM as your postback parameter. This is what I would do. My post action parameter is always the same type of the .cshtml model. Yes there will be properties like lists that are null, but you just ignore those. It also allows you to gracefully handle post errors as well because if there is an error you'll need to return an instance of that view model anyhow, and have the values they submitted included. I usually have private methods or DB layer that handles retrieving the various lists that go into the ViewModel, since those will be empty on postback and will need to be repopulated, while not touching the properties that were in the post.
With your post method as it is now, if you need to return the same view, you've gotta create a new EditVM and then copy any posted values into it, and still populate the lists. With my method, you eliminate one of those mapping steps. If you are posting more than one thing, are you going to have umpteen different parameters on your post action? Just let them all come naturally into a single parameter typed to the EditVM of the View. While maybe having those null properties in the VM during the postback feels icky, you get a nice predictable consistency between View and postback IMO. You don't have to spend alot of time thinking about what combination of parameters on your post method will get you all the pieces of data from the form.

What is the purpose of passing a data model instance from within [HttpGet] Create to its View?

I notice there are 2 common practices to implement the Create form.
First Approach
From within [HttpGet] Create action method, we pass an instance of data model to the Create.cshtml as follows:
public ActionResult Create()
{
DataModel dm = new DataModel();
return View(dm);
}
Second Approach
From within [HttpGet] Create action method, we don't pass an instance of data model to the Create.cshtml as follows:
public ActionResult Create()
{
return View();
}
The [HttpPost] Create(DataModel dm) for both approaches is as follows:
[HttpPost]
public ActionResult Create(DataModel dm)
{
if (ModelState.IsValid)
{
db.Movies.Add(dm);
db.SaveChanges();
return RedirectToAction("Index");
}
else
return View(dm);
}
The question is: What is the purpose of passing a data model instance from within [HttpGet] Create to its View ?
Passing a data model to the view associated with the 'Create' is useful if you want the application logic to supply the initial values to be displayed on the form (whether because you don't want them hard-coded in the form defined in the view, or because they might differ depending on the context).
Default values for the bound controls, values in the viewmodel to be consumed by the view to generate dropdowns, etc... as mentioned by rsalmeidafl.
At the risk of sounding like a curmudgeon, this is really best practice. You shouldn't be calling the database to generate select lists and things from your views.
Finally, sending a default instance of the model to your view can also let you reuse edit/create views very easily, since you can bind values without fear of NullRef exceptions for your model. (if you strongly type your views)

asp.net mvc - bootstrapping object via model binder

I have a domain object Thing which can contain several Categories. So I have implemented my HTML helper to create a checkbox group of all possible Categories. I have no problem receiving:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Thing Thing, List<string> Categories)
However I am wondering whether I could use a custom Model binder to use just this:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Thing Thing)
So basically I am looking for a way to use the model binder to bootstrap the object tree/graph.
Any pointers appreciated. Thanks.
Christian
I was mixing up domain objects and DTOs. Making Thing a DTO (or view object?) does the trick.
so having something like this works:
class Thing
(
List Categories;
)
The model binder figures out how to put the posted data into the Categories

Resources