Example of an ASP.NET MVC post model? - asp.net-mvc

I was watching the HaHaa presentation on ASP.NET MVC from MIX and they mentioned using a Post Model where I guess they were saying you could use a model that was ONLY for posting. I have tried looking for examples for this. Am I not understanding what they are saying? Does anyone have an example of how this might work in a strongly typed view where the view model and post model are not of the same type?

Below is ScottGu's example expanded a bit. As #SLaks explained, when the POST is received, MVC will try to create a new MyPostName object and match its properties with the from fields. It will also update the ModelState property with the results of the matching and validation.
When the action returns the view, it has to provide a model for it as well. However, the view doesn't have to use that same model. In fact, the view can be strongly typed with a different model, that contains the expanded data, for example it can have navigation properties bound to external keys in the DB table; and if that's the case, the logic to map from the POST model to the view model will be contained in the POST action.
public class MyGetModel
{
string FullName;
List<MyGetModel> SuggestedFriends;
}
public class MyPostModel
{
string FirstName;
string LastName;
}
//GET: /Customer/Create
public ActionResult Create()
{
MyGetModel myName = new MyGetModel();
myName.FullName = "John Doe"; // Or fetch it from the DB
myName.SuggestedFriends = new List<MyGetModel>; // For example - from people select name where name != myName.FullName
Model = myName;
return View();
}
//POST: /Customer/Create
[HttpPost]
public ActionResult Create(MyPostModel newName)
{
MyGetModel name = new MyGetModel();
name.FullName = newName.FirstName + "" + newName.LastName; // Or validate and update the DB
return View("Create", name);
}

The POST model would only be used to pass the data into your action method.
The model that the POST action sends to its view doesn't need to be related to the model that it received (and usually will not be).
Similarly, the model that the initial GET action (that shows the form in the first place) passes to its view (which submits to the POST action) doesn't need to be related to the model that the POST action takes (although it usually will be the same model)
As long as it has properties that match your input parameters, you can use any model you want for the parameter to the POST action.

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

Using view models to get data back

Assume we have update form.
This form requires two actions. One of them for GET request to show data and second for POST request to save changes.
[HttpGet]
public ActionResult Update(int id)
{
var viewModel = GetViewModel(id);
viewModel.Dictionaries = GetUpdateDictionaries(id);
return View(viewModel);
}
[HttpPost]
public ActionResult Update(UpdateViewModel viewModel)
{
if(Model.IsValid)
{
Save(viewModel);
return RedirectToHome();
}
viewModel.Dictionaries = GetUpdateDictionaries(id);
return View(viewModel);
}
It is a classical approach. We pass to POST update the same view model. But with this view model we pass many unnecessary data. For example dictionaries. Someone tells that it is a bad practice and suggest two alternative ways:
1) Use view model only for form data and pass dictionaries and other stuuf through ViewBug
2) Create special class only for necessary form data and use it in post update action.
Are there standart approach?
If your dictionaries are not part of the Model then the alternatives which MVC provide for passing information to the View is:
ViewData["MyDictionaries"]= GetUpdateDictionaries(id);
or
TempData["MyDictionaries"]= GetUpdateDictionaries(id);
or for .Net 4:
ViewBag.MyDictionaries= GetUpdateDictionaries(id);
Is your concern that viewModel.Dictionaries will all get sent to the client browser and then get posted back to the server? It won't. Only things that you render in markup e.g. with Html.TextBoxFor() get sent to the browser. So your current code is okay from that point of view.
The real objection to your dictionaries is, if the dictionaries are not a part of the thing your Model is a model of. The point of OO is that your models are models of something; so should only have properties corresponding to the something that it models.
If your models are not models of something, but only ViewModels, then putting the dictionaries on them in fine. But in that case, Save(model) would not be fine.

MVC sending data from View to Controller

I am quite new to MVC 3.
I know how to send a strongly typed object from a Controller to a View. What I have now, is a View which contains a table/form which consists of that data.
The user can change that data whilst they're are in that View (html page).
When they click on "Save", how do I send the data from the View back to the Controller so that I can update my database.
Do I overload the Controller method so that it accepts a parameter of the model type? Can you please provide some source code.
(Please do not show code of persisting data to a database, I know how to do that part).
Thank you very much for helping me.
I would also prefer using #Html.BeginForm()
I like creating an action method made for my post data. So let's say you have a UserViewModel:
public class UserViewModel
{
public int Id { get; set; }
public string Name { get; set; }
}
Then a UserController:
public class UserController
{
[HttpGet]
public ActionResult Edit(int id)
{
// Create your UserViewModel with the passed in Id. Get stuff from the db, etc...
var userViewModel = new UserViewModel();
// ...
return View(userViewModel);
}
[HttpPost]
public ActionResult Edit(UserViewModel userViewModel)
{
// This is the post method. MVC will bind the data from your
// view's form and put that data in the UserViewModel that is sent
// to this method.
// Validate the data and save to the database.
// Redirect to where the user needs to be.
}
}
I'm assuming you have a form in your view already. You'll want to make sure that the form posts the data to the correct action method. In my example, you'd create the form like so:
#model UserViewModel
#using (Html.BeginForm("Edit", "User", FormMethod.Post))
{
#Html.TextBoxFor(m => m.Name)
#Html.HiddenFor(m => m.Id)
}
The key to all this is the model binding that MVC does. Make use of the HTML helpers, like the Html.TextBoxFor I used. Also, you'll notice the top line of the view code I added. The #model tells the view you'll be sending it a UserViewModel. Let the engine do work for you.
Edit: Good call, did that all in Notepad, forgot a HiddenFor for the Id!
In MVC, the act of scraping out data from POST or GET HttpRequests is referred to as Model Binding - there are plenty of SO questions relating to this.
Out of the box, MVC will bind your Get and Post variables based on convention, e.g. a form field with the name 'FormName' will be bound back to a parameter on your controller with the same name.
Model binding also works for objects - MVC will instantiate an object for your controller, and set the properties with the same name as your form.

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.

How does the ASP.NET MVC UpdateModel() method work?

I'm working on my first .NET MVC application and using the NerdDinner tutorial as a reference point. One point that is intriguing me at the moment is the UpdateModel() method. (I don't like using things I don't really understand.)
Taken from the NerdDinner tutorial -
//
// POST: /Dinners/Edit/2
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection formValues) {
Dinner dinner = dinnerRepository.GetDinner(id);
UpdateModel(dinner);
dinnerRepository.Save();
return RedirectToAction("Details", new { id = dinner.DinnerID });
}
My main question is how does the UpdateModel() get access to the formValues passed in the Edit method? Why is the collection not passed in explicitly as a parameter to the method?
UpdateModel() is a Controller helper method that attempts to bind a bunch of different input data sources (HTTP POST data coming from a View, QueryString values, Session variables/Cookies, etc.) to the explicit model object you indicate as a parameter. Essentially, it is only for model binding.
If you express the input parameters for your Action as a strongly-typed model (like a View Model), you've already taken all of the steps that are done behind the scenes when UpdateModel() is called. If you retrieve an object from the DataContext and edit its properties, SaveChanges() is all you need to push the updates back to the database (in this case, Save()).
Example:
//
// POST: /Dinners/Edit/2
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(DinnerViewModel incoming) {
var dinner = dinnerRepository.GetDinner(incoming.DinnerID);
dinner.Description = incoming.Description;
dinnerRepository.Save();
return RedirectToAction("Details", new { id = incoming.DinnerID });
}
However, there is a use-case for using UpdateModel() with a strongly-typed model: when you are passing in a strongly-typed model and want its values to directly replace those of an entity from the database (provided they are all named and typed the same). In this case, you would retrieve the object, use UpdateModel() on it, and its model binding operation will pull in any similarly-named and typed properties from the strongly-typed object to the retrieved object. In other words, it will perform reflection for you.
So, like your example, if you want all properties to update without specifying which to update, and your strongly-typed model and database model have similarly-named properties, you would still want to use UpdateModel() to take advantage of the reflection.
Example:
//
// POST: /Dinners/Edit/2
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(DinnerViewModel incoming) {
var dinner = dinnerRepository.GetDinner(incoming.DinnerID);
UpdateModel(dinner);
dinnerRepository.Save();
return RedirectToAction("Details", new { id = incoming.DinnerID });
}
The only advantage here (over using a FormCollection object) is that you'd have access to all other properties of the strongly-typed object (as shown by incoming.DinnerID).
Conclusion: if you're translating a strongly-typed object to a derived object, it's probably easiest to use UpdateModel(). However, it's largely unnecessary if you are simply updating a few properties of the derived object. Also, be aware that use of the Entity Framework (instead of something like Linq to SQL) makes all of this moot, as it can relate strongly-typed objects and derived objects with its own methods.
It does inspect all the HttpRequest inputs such as Form, QueryString, Cookies and Server variables. I think in this order.
Instead of passing Model object as a parameter to "Post()" action method, we are creating an instance of an Model object within the "Post()" function, and updating it using "UpdateModel()" function. "UpdateModel()" function inspects all the HttpRequest inputs such as posted Form data, QueryString, Cookies and Server variables and populate the employee object.
e.g.
[HttpPost]
[ActionName("Create")]
public ActionResult Create_Post()
{
EmployeeBusinessLayer employeeBusinessLayer =
new EmployeeBusinessLayer();
Employee employee = new Employee();
UpdateModel(employee);
employeeBusinessLayer.AddEmmployee(employee);
return RedirectToAction("Index");
}

Resources