Could you explain the interaction Models and ViewModels in the ASP.NET MVC?
If I need to display data on the page, but not edit, whether to create a ViewModel to display or use the Model?
I have two methods in the repository. One returns the Model and the other Model gets.In View I need to send the model. Should I convert the resulting Model to a ViewModel that would pass it to the View, and upon receipt of the submission to convert it back into the model to keep it?
For example I have a class model and class ViewModel.
public class Item
{
public int Id { get; set; }
public string Name { get; set; }
public int Price { get; set; }
}
public class EditItemItemViewModel
{
public string Name { get; set; }
public int Price { get; set; }
}
On the edit page, I clicked the edit item, and must get to the controller:
[HttpGet]
public ActionResult EditItem(int id)
{
//some code
return View();
}
Where can I get the ID if I passed in the view ViewModel in which there was no ID?
If I somehow got the ID, I need to do the following, which would save the model?
[HttpPost]
public ActionResult EditItem(EditItemItemViewModel ViewModel)
{
var Item = _dataManager.Items.GetItemById("1");
Item.Name = ViewModel.Name;
Item.Price = ViewModel.Price;
_dataManager.Items.AddItem(Item);
return View("Sucsess");
}
Could you tell me how to work with Models and ViewModels?
You can get the id a few different ways:
#Html.HiddenFor(m => m.Id)
This will include the property in the actual HTTP request.
Another option is to simply include the id as part of your route (this is what I usually do):
#Html.BeginForm("EditItem", "SomeController", new { Id = Model.Id }, FormMethod.Post) {
...
}
In both instances, make sure to validate that the user should be able to update the record that corresponds to that id! There's nothing stopping a user from tampering with the id and sending you a different value.
As for whether or not to display the database model or the view model, that's really up to you. I would always advocate building a view model and keep your database models out of the picture except for in your controller. The convention I use at work is for every database object that I need to send to users I will create a corresponding view model. So if I have a database object called Product I will build another class for the view called ProductModel.
An advantage of following that pattern is something I actually explained to another user earlier in regards to model binding.
If I need to display data on the page, but not edit, whether to create a ViewModel to display or use the Model?
If it's very simple (like your example) and the properties map 1-1 like they do now. I would just use the Model as a view model, it's easier. Though if you want you could create a view model with the exact same properties and populate that and display it..it's a bit more work, but makes it so your domain models aren't necessarily tied to your views.
If you do that you may want to look into something like AutoMapper which would allow you to do something like
//simply copies the properties from one type to another
var viewModel = Mapper.Map<Item, EditItemItemViewModel>();
I have two methods in the repository. One returns the Model and the other Model gets.In View I need to send the model. Should I convert the resulting Model to a ViewModel that would pass it to the View, and upon receipt of the submission to convert it back into the model to keep it?
If you go the view model route then yes, you will end up doing a lot of converting between model and viewmodel, that's where something like AutoMapper can help out, or you can just create a couple extension methods that convert between the two types.
It looks like Justin Helgerson's answer explaining a way to handle models/viewmodels is pretty good.
Your posting your viewmodel, so i'm going to assume that you've referenced your model within the page
#model MyNameSpace.EditItemItemViewModel
Is there a reason the id is not included in your view model? The easiest method would be to include that in the model and pass the instantiated model when creating the view.
[HttpGet]
public ActionResult EditItem(int id)
{
var myViewModel = new EditItemItemViewModel() { Id = id };
return View(myViewModel);
}
Like Justin said, it is easier to put it in a hidden field somewhere inside the #Html.BeginForm as the id should just be for reference.
[HttpPost]
public ActionResult EditItem(EditItemItemViewModel viewModel)
{
var Item = _dataManager.Items.GetItemById(viewModel.Id);
Item.Name = viewModel.Name;
Item.Price = viewModel.Price;
// Should this be an Add?
_dataManager.Items.AddItem(Item);
return View("Success");
}
Related
Given an ASP.NET Core MVC controller method with no parameters.
Given a view model is created and partially populated with third-party data within the controller method.
Given my C# models have properly defined data annotations for property validation.
Is it possible to leverage the ASP.NET Core MVC framework to validate my view model such that Html.ValidationSummary() shows errors from the pre-populated view model on initial viewing of the form (as opposed to only showing on the submission of the form)?
Controller:
public IActionResult ViewForm()
{
MyViewModel viewModel = new MyViewModel();
// Pre-populate view model with some data (which may be invalid).
viewModel.MyRequiredProperty = someThirdPartyDataSource.Value;
//I want to validate here so pre-populated data errors are shown
//in the views "Html.ValidationSummary()".
return View(viewModel);
}
Models:
public class MyViewModel
{
public MyObjectToValidate MyObject { get; set; }
}
public class MyObjectToValidate
{
[Key]
public int ID { get; set; }
[Required(ErrorMessage="Property is required.")]
public string MyRequiredProperty
}
Maybe I can... (couldn't find solid answers to these looking through documentation myself)
Manually bind and validate the viewModel somehow prior to calling return View(viewModel)?
Take advantage of ViewResult myViewResult = View(viewModel);?
ControllerBase (which all controllers implicitly inherit from) has a TryValidateModel method that should do exactly what you need. So:
public IActionResult ViewForm()
{
MyViewModel viewModel = new MyViewModel();
// Pre-populate view model with some data (which may be invalid).
viewModel.MyRequiredProperty = someThirdPartyDataSource.Value;
//I want to validate here so pre-populated data errors are shown
//in the views "Html.ValidationSummary()".
TryValidateModel(viewModel);
return View(viewModel);
}
My end goal is to pass a strongly typed model (to populate a drop-down menu) and a list of models (based on a search query) to a view simultaneously from a controller. The view I am passing it to is the "Clear()" view. Currently in my HomeController.cs I have:
public ActionResult Clear()
{
var states = GetAllStates();
var model = new ProjectClearanceApp.Models.Project();
model.States = GetSelectListItems(states);
return View(model);
}
private IEnumerable<string> GetAllStates()
{
return new List<string>
{
"AL",
// ... (you get the point)
"WY",
};
}
private IEnumerable<SelectListItem> GetSelectListItems(IEnumerable<string> elements)
{
var selectList = new List<SelectListItem>();
foreach (var element in elements)
{
selectList.Add(new SelectListItem
{
Value = element,
Text = element
});
}
return selectList;
}
I read somewhere that that's the best way to get the list of options for a drop-down menu. Now I'd also like a pass a LIST of models to the same view (Clear.cshtml) based on a search query. I'm reading from this Microsoft tutorial to search in the controller action for that view by adding
public ActionResult Index(string searchString)
{
var movies = from m in db.Movies
select m;
if (!String.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title.Contains(searchString));
}
return View(movies);
}
to the controller. How can I pass both the list of drop-down options AND the list of models that fit the search from the controller to the view (or, how can I achieve the same effect without passing both from the controller)?
To achieve your end goal ,that is passing the list of model, viewmodel will be the best solution as per my knowledge.
Some key note above view model:
The ViewModel class, which is the bridge between the view and the model. Each View class has a corresponding ViewModel class. The ViewModel retrieves data from the Model and manipulates it into the format required by the View. It notifies the View if the underlying data in the model is changed, and it updates the data in the Model in response to UI events from the View
The ViewModel class determines whether a user action requires modification of the data in the Model, and acts on the Model if required. For example, if a user presses a button to update the inventory quantity for a part, the View simply notifies the ViewModel that this event occurred. The ViewModel retrieves the new inventory amount from the View and updates the Model. This decouples the View from the Model, and consolidates the business logic into the ViewModel and the Model where it can be tested.
Official definition/ Source: https://msdn.microsoft.com/en-us/library/ff798384.aspx
Additional information with Ex:
http://www.dotnettricks.com/learn/mvc/understanding-viewmodel-in-aspnet-mvc
Kindly let me know your thoughts or feedbacks
Thanks
Karthik
Model is a term that really describes what data is meant to be bound to the view, and what data the model binder will handle when you make a request to/from the view. Because I'm not exactly sure how you are using Index and Clear, I'll just stub these out generally. Please let me know if I've missed the point of your question:
If you are having trouble passing, for example, List<Movies> movieModel along with your List<SelectListItem> selectedStates (or any additional values) to the view, here are 2 common ways to do this.
ViewModel approach -- Create a model class that contains your "main" model along with any other properties, lists, etc. that you'll need in the view.
eg:
public Class MyViewModelClass
{
List<Movie> MoviesList {get;set;}
List<SelectListItem> StatesList {get;set;}
//some other properties/methods can go here as well ...
}
//In Controller
{
MyViewModelClass model = new MyViewModelClass();
model.StatesList = <build your select list>;
model.MovieList = <build your movie list>;
return View(model);
}
In the controller you would then create a new instance of MyViewModelClass model (different name obviously), and populate your movie list, state list, and any other properties, assign them to the model properties, and pass the whole thing as your return View(model);
This is nice because all of the data getting passed to the view can be in one place.
ViewBag approach -- Stick with a single model or List, and pass view-related data (such as dropdown lists, or state bools) in the ViewData or ViewBag.
ex.
//From Controller
public ActionResult SomeMethod()
{
var states = GetAllStates();
var model = <enter movies query here>;
ViewBag.StatesList = GetSelectListItems(states);
//This will be accessible in the view now
return View(model);
}
//In View:
#{
List<SelectListItem> StatesList = (List<SelectListItem>)ViewBag.StatesList; // Can now use this variable to bind to DropDownList, etc.
}
I prefer, for the most part, using a ViewModel to add everything I need. For one, the ViewBag/ViewData requires some casting, and it relies on "magic strings", so you don't have Visual Studio letting you know if you'd typed something wrong with intellisense. That said, either is viable.
Lets say that i have an URL that looks something like this: localhost/userdetails/5 where 5 is the users ID. Is there any way to make use of the ID directly in the view (razor viewengine) and show the details? Or do i handle it in the default action in the controller?
To keep things simple now, focusing on getting the id to the view, you basically want to use the id to populate your model with data and then pass that to the view. So in your controller:
public ActionResult Index(int id)
{
UserModel model = db.Users.Where(u => u.Id == id).SingleOrDefault();
return View(model);
}
The view (very simplified) might look like this:
#model MyProject.Models.UserModel
#Html.DisplayFor(m => m.Id)
#Html.DisplayFor(m => m.Username)
This is very basic though. Eventually, you'll get to a point where you realise you should use viewmodels for your views instead of a domain model that's come directly from the data source. That in itself gives you another problem to solve in the form of mapping properties from the domain model onto your viewmodel. Typically, AutoMapper or ValueInjecter are used for that. For now though, it's probably best to just focus on passing data to a view and getting it back into a controller so that you can do something with it.
Update
This is a simple scenario which demonstrates how to get the data back into the controller. So basically, you'd have a form which you would submit:
#using (Html.BeginForm("Index", "Home"))
{
// Form elements and submit button
}
That would post the data to this action method for you to do whatever you wish with the data:
[HttpPost]
public ActionResult Index(UserModel inputModel)
{
// Check to see if the model's data was valid.
if (ModelState.IsValid)
{
// Do something in the database here.
// Then redirect to give the user some feedback.
return RedirectToAction("Thanks");
}
// The model validation failed so redisplay the view.
return View(inputModel);
}
you can use this in both the controller or in the View as an extension method.
Example: asuming your routes id holder has the default values in global.asax
public int IdFromAdress(HttpContext httpContext)
{
RouteData rd = httpContext.Request.RequestContext.RouteData;
string stringId = (string)rd.Values["id"];
return int.Parse(stringId);
{
You can get the id with this
#HttpContext.Current.Request.RequestContext.RouteData.Values["id"].ToString()
But I would reccomend to use a ViewMdoel to pass the value to the view and not the ViewBag or accessing directly from the view
You should use the model (i.e. the model passed back to your view). A ViewBag is another option but since the ID is part of the model itself, it wouldn't make any sense to do that.
View
#model User
#{
ViewBag.Title = "User Details";
}
#Model.Id;
Controller
public ActionResult UserDetails(int id)
{
return View("UserDetails", (object)id);
}
Yes you can. There is more than one way to do it, but since you've tagged your post MVC, assume you'll want to do it the 'MVC way', which means (imo) using a view model.
So you write a view model
public class MyViewModel()
{
public int ID {get; set;}
}
You populate the model in the controller and pass it to the view
public ActionResut MyView (int id)
{
var viewModel = new MyViewModel {ID = id};
return View (viewModel);
}
Then you have a strongly typed view (strongly typed to the MyViewModel, that is)
and you can reference the model's properties
#Model.ID
Then to make this useful, you can add whatever other properties you're wanting to work with to your view model. Then you can populate them in your controller before rendering the view (to show user info, for example), or let the user populate them for you in the view (using textboxes and such wrapped in a form). Then you can collect the user input in the post action in the controller like so
[HttpPost]
public ActionResult MyView(MyViewModel viewModel)
{
//do stuff with the data from the viewModel
}
We are using a friendly Name URL route scheme. Basically using a combination of the Principal Identity and a friendly name this can be mapped back to an identity internally (Person ID). So a route like this:
routes.MapRoute(string.Empty, "{friendlyname}/Products/{action}", new {controller = "Products", action = "List"});
Would map to a URL like this:
Adam/Products/List
This all works fine and abstracts away the internal Id of the named person which is required as well.
The problem is our Views are comprised of many partial views. When there are rendered by using the #Html.Action method they ultimately need the PersonID but from the URL we only have the 'friendly name'.
I have thought about this for a while and there are two solutions to my mind:
Pass the 'friendly name' into each of the controller action methods that return the partial views and internally the method will have to do a lookup on the currently logged in identity and the friendly name. This will give the PersonID to me and I can then efficiently query from then on. The only problem with this apporach is that due to the multiple partial views I will be querying on the currently logged in identity and friendly name for each partial view call which is innefficeint and I feel I should only have to write this code once.
Somehow query in the view and get the PersonID so it can be passed to each #Html.Action call so the partial view controller methods will not have to do that lookup themselves saving round trips to the database for the same shared informtion. The problem with this is that I am not sure of a way of doing this cleanley in the view using the DI that we use through the rest of the application.
Any thoughts on approach to would be greatly appreciated.
Thank you,
Adam
You could add the Id to the session variables and access it from within the views with:
#{var personId = int.Parse(Session["PersonId"])}
Then you can pass it directly to partial views from the Parent without it hitting the client or having to pass parameters to any controllers.
Update
You could also access the session variable from the Controller if you wanted to do the work there instead without roundtripping to the database.
EDIT
If you put the property in a model and pass it to a page that post's back then the model will not persist between posts.
If for example your controller does:
[HttpPost]
public ActionResult DoSomething(ViewModel model)
{
if(ModelState.IsValid)
{
// Logic Here
}
return View(model)
}
when the page is reloaded, the model will have forgotten about the ID.
There are a couple of ways around this. Either use #Html.HiddenFor(m => m.ID)
which will put the property in the rendered HTML, which if it is truely a sensitive piece of information, is bad.
Or you can rebuild the view model on each subsequent postback.
Hope this helps
As Marc states I could you the Session to deal with this but I have gone with using the Model as he has stated in his update. If the parent View Controller action takes in the friendly name it can do the lookup, put the PersonID into the model and then any Partial Renders can have the models value passed into them in the parent View Controllers Action's view. An example is shown below (this is demo code but it hopefully gets the point across, I would never use a static data context in real code)
Home controller
public class HomeController : Controller
{
public ActionResult Index(string friendlyName)
{
int pupilId = Data.People.Single(x => x.Name == friendlyName).PersonId;
HomeIndexViewModel homeIndexViewModel = new HomeIndexViewModel {PupilId = pupilId};
return View(homeIndexViewModel);
}
}
Home Index View
#model SharingInformationBetweenPartials.Web.Models.HomeIndexViewModel
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#Html.Action("DisplayPersonDetail", "Person", new {Model.PersonId})
The PersonController's DisplayPersonDetail method can then present the respective data it wishes using the passed in PersonId:
public class PupilController : Controller
{
[ChildActionOnly]
public ActionResult DisplayPupilDetail(int pupilId)
{
Person person = Data.People.Single(x => x.PersonId == pupilId);
return View(person);
}
}
I did try what I thought was this before but I must have got something wrong as the ViewModels properties were getting shown in the URL which is what I was trying to get away from. Anyway, I hope this helps anyone else who may be looking to do something similar. If you have any questions then let me know.
Thanks,
Adam
You can use [Bind] attribute to specify the exact properties a model binder should include in binding or use Exclude parameter on the attribute to exclude PersonId
[HttpPost]
public ActionResult EditPerson([Bind(Exclude = "PersonId")] Person person)
{
//do domething
}
You can also use [ReadOnly] attribute that model binder will understand and not assign to that property.
[ReadOnly(true)]
public int PersonId{ get; set; }
But the best approach is to use separate ViewModels: one only for viewing and one for editing.
public abstract class Person
{
public string Name { get; set; }
public string Surname { get; set; }
}
public class PersonCreateVM : Person
{
//no PersonId here
}
public class PersonEditVM : Person
{
public int PersonId{ get; set; }
}
This approach is maybe a "overkill" but when used properly and with AutoMapper http://automapper.codeplex.com/ it's an ease to work with.
I'm new to .Net development, and now are following NerdDinner tutorial. Just wondering if any of you would be able to tell me
What is the differences between ViewData
and ViewModel
(all I know is they are used to pass some form of data from controller to view) and perhaps tell me on what situation should I use ViewData instead of ViewModel and vice versa
Thanks in advance!
Sally
What is ViewData ?
dictionary object that you put data into, which then becomes
available to the view.
ViewData Sample
Controller Action method likes :
public class HomeController : Controller
{
public ActionResult Index()
{
var featuredProduct = new Product
{
Name = "Smart Phone",
QtyOnHand = 12
};
ViewData["FeaturedProduct"] = featuredProduct;
return View();
}
}
How to use ViewData on View ?
#{
var viewDataProduct = ViewData["FeaturedProduct"] as Product;
}
<div>
Today's Featured Product is!
<h3>#viewDataProduct.Name</h3>
</div>
What is a ViewModel ?
Allow you to shape multiple entities from one or more data models or
sources into a single object
Optimized for consumption and rendering by the view
Its like :
How to use ViewModel with MVC 3 ?
Domain Model
public class Product
{
public Product() { Id = Guid.NewGuid(); Created = DateTime.Now; }
public Guid Id { get; set; }
public string ProductName { get; set; }
}
ViewModel
public class ProductViewModel
{
public Guid VmId { get; set; }
[Required(ErrorMessage = "required")]
public string ProductName { get; set; }
}
Controller Action Method
[HttpGet]
public ActionResult AddProduct()
{
//for initialize viewmodel
var productViewModel = new ProductViewModel();
//assign values for viewmodel
productViewModel.ProductName = "Smart Phone";
//send viewmodel into UI (View)
return View("AddProduct", productViewModel);
}
View - AddProduct.cshtml
#model YourProject.ViewModels.ProductViewModel //set your viewmodel here
Conclusion
By using ViewModel can pass strongly-typed data into View
But ViewData is Loosely Typed.So Need to cast data on View
ViewModel can use for Complex scenarios such as merging more than one
domain model
But ViewData can be used only for simple scenarios like bring data
for the drop down list
ViewModel can use for attribute-based validation scenarios which
needed for Ui
But Cannot use ViewData for such kind of validations
As a best practices always try to use strongly typed data with
Views.ViewModel is the best candidate for that.
ViewData:
In short, use ViewData as support data, such as a datasource to a SelectList.
ViewModel:
ASP.NET MVC ViewModel Pattern
When a Controller class decides to render an HTML response back to a
client, it is responsible for
explicitly passing to the view
template all of the data needed to
render the response. View templates
should never perform any data
retrieval or application logic – and
should instead limit themselves to
only have rendering code that is
driven off of the model/data passed to
it by the controller.
[...]
When using [the "ViewModel"] pattern we create strongly-typed
classes that are optimized for our
specific view scenarios, and which
expose properties for the dynamic
values/content needed by our view
templates. Our controller classes can
then populate and pass these
view-optimized classes to our view
template to use. This enables
type-safety, compile-time checking,
and editor intellisense within view
templates.