How to update Model when binding to a ViewModel? - asp.net-mvc

I have an [HttpPost] action method signature like this:
[HttpPost]
public ActionResult Edit(ExistingPostViewModel model)
{
// Save the edited Post.
}
Now, in the past (when i didn't use ViewModels, e.g R&D), i had an implementation of an Edit method like this:
[HttpPost]
public ActionResult Edit(Post model)
{
var existingPost = repo.Find(model.Id);
TryUpdateModel(existingPost);
repo.Save(existingPost);
return RedirectToAction("Success", existingPost.Id);
}
Which worked great.
But i'm confused how to adapt the above to the ViewModel approach.
If i do this:
TryUpdateModel(existingPost)
With my ViewModel approach, not much happens. No errors, but nothing is being updated because MVC won't know how to update a Post from a ExistingPostViewModel (before it was Post -> Post).
Now, i'm using AutoMapper. So i thought i could map from the ViewModel to the Post, then save the post.
But then im basically overriding everything. Which i don't want to do and defeats the point of the cut down ViewModel.
Can anyone un-confuse me?
This seems like a really common scenario, and i am totally stumped as to how people solve this. I can only see 3 possible solutions:
Don't use a ViewModel in the HTTP POST. As i said i did this in the past for R&D and it works, but now i see how my View's have evolved (validation, simplicity), and i can't compromise that just for the sake of this problem.
Don't use TryUpdateModel. Possibly, but then how would i merge in the changes?
Use left-to-right. Ugh. But at the moment this seems to be the way im leaning.
Someone please give me solution #4! :)
BTW, i'm using ASP.NET MVC 3, Razor and Entity Framework.

I actually ran into this exact same issue in a project I'm currently working on. As much as I wasn't a fan of it, I ended up doing the left to right approach and manually mapping my viewmodel data back to my entity.
The only nice thing about this approach is it does give you more control. Since I started using more compound viewmodels, where you actually have fields from more than one entity in your viewmodel, it started making more sense to do things this way.
I'm also using AutoMapper, and you're absolutely right, it does get awkward when you're trying to do a simple update operation. Wish I had some super clever workaround for you, but the "old fashioned way" seems to get the job done best for the work I've been doing.

Not sure if this will help, but it is working for me. I have my underlying domain table as a Visitor Object. My viewmodel contains the Visitor Object plus a couple of IEnumerables for dropdowns.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(int id)
{
Visitor Visitor = new Visitor();
Visitor = db.Visitors.FirstOrDefault(v => v.VisitorID == id);
UpdateModel(Visitor, "Visitor");
db.SaveChanges();
return RedirectToAction("Index");
}
The UpdateModel works off my viewmodel because of the "Visitor" string telling it what values to compare.

For simple things where you don't have to run any controls prior to implementing the update what you are doing is okay (db.get(), and then update).
When things get complicated, you have to load the entity, and then select and apply user's changes from the view model, property by property. In those cases, you end up writing Update methods, which gets the new data as input, and then you load the existing entity, then compare states, and take the required actions based on the view model data. Actually in this case, probably you wont have an Update method but will have behaviors, like CancelPost, AddComment, EditPost (which also logs the edit reason), AddTagsToPost etc.

Related

MVC4 Action method AutoMap actionfilter fails to convert the view model to domain model

so, I've seen this working on a previous project in MVC3, so wondering if a) i've screwed it up, or b) MVC4 is doing something different (can't see it would be).
I have a model bound Razor view which submits to a controller action method (as is the way with MVC)
post action method:
[HttpPost]
[AutoMap(typeof(MyViewModel), typeof(MyDomainObj))]
public void PostAction(MyDomainObj obj)
{... etc.. etc..
The action filter eventually does something like this:
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var model = filterContext.Controller.ViewData.Model;
NOTE: In Jimmy Bogard's example he used OnActionExecuted which I also tried..
The key issue I'm having is that at the pint where we get the "model" variable from the context, it's null. If I look at the filterContext.ActionParameters whilst debugging I can see a MyDomainObj instance!! which appears to (because it happens to have a prop name in common with the MyViewModel type) have been mapped from my form data!
So.. yes if I had MyViewModel type as the parameter to this method, then the param would be properly populated from the submitted form. But. I don't want to do that, I want to (and have done before based on JB's succinct how-to) converted the view model to domain model as part of the action executed/ing and then been able to just hit save on my domain model.
Summary - why is my ViewData.Model null on the post action filter?
Jimmmy also has/had a couple of ideas on how to implement post actions, along with another guy Matt Honeycutt who shares his view on how to do posts. I also believe Jimmy has gone in the direction of using explicit mapping in his get requests instead of attributes, as it can be hard to inject any extra code you need after mapping.
http://lostechies.com/jimmybogard/2011/06/22/cleaning-up-posts-in-asp-net-mvc/
http://trycatchfail.com/blog/post/Cleaning-up-POSTs-in-ASPNET-MVC-the-Fail-Tracker-Way.aspx
For a post you really want a couple of things imo, the original Entity and the Form Data. You could load the entity like you do for the GET request and do normal model binding to get the form data (remember you can accept a different model for post backs than you spit out in your view) then make the changes in the action.
Of course this would require using AutoMapper in your action, which you seem to be trying to avoid. But unless you write a custom model binder then you're not going to magically get the formdata in a model as the built in one looks at the action paramters to figure out what to bind. For this reason i'd recommend not using a domain model as a parameter for an action, as it may fill out fields that you don't wish it to.
I've also seen Jimmy using a ModelBinder to do something similar to your AutoMapGet, which may be another alternative method, but I'm guessing you've seen that post.
My standard post takes Matt's approach, moving the validation out into a global attribute so it can't be forgotten (there are some downsides to this) then accepting a new view model explicity for the form data, then I explicity load the entity, use automapper to update it and call save. Most the actions only end up being about 5 lines long.
I do avoid using the static methods on AutoMapper and pass a IMapper in via constructor injection. This allows me to make it a bit more testable if I really need to, however the methods are normally so simple the tests don't add all that much value.

Where should I place sub-structures within a MVC controller

I am trying to build a controller that will enable the user to add/remove subcontent to an item.
Think of it like a document where you can add different types of sections, like headlines, paragraphs, images etc. (they each have their own attributes so they are in seperate tables in the SQL)
My question is where should I put the code to handle the different types of subsections within this "document controller"?
They are all attached to this "document"/entity through database relations, but should I make a "crudl" controller for each type or should I do a base kinda crudl and then let them all inherit this?
I've looked into "Models" and "service layers" - is that the right way to do it?
I am still rather new with MVC, using C# and ASP.net I was hoping for someone to give me a hint in the right direction.
Nb. please let me know if I should rephrase the question. Didn't know what to ask to get the right answer here.
Specs: I use EF 4.x and MVC3 will upgrade to latest when available, if needed.
In hope of some clever answers or guidance. Thanks in advance people. And yes, I have tried to Google too. Don't know what to search for, so I come here.
where should I put the code to handle the different types of subsections within this "documentcontroller"?
The code for this would ultimately go into a controller action which you then handle and update the database accordingly. There are multiple ways of doing this, you could be generic e.g.
[HttpPost]
public ActionResult AddSection(string type)
{
switch (type)
{
case "HEADING":
// add new heading to database
case "PARAGRAPH":
// add new paragraph to database
}
return View(type);
}
Or you could be specific e.g.
[HttpPost]
public ActionResult AddHeadingSection()
{
// add to db
return View("Heading");
}
[HttpPost]
public ActionResult AddParagraphSection()
{
// add to db
return View("Parapgraph");
}
The above is just really pseudo code to give you a rough idea of how you could do it with minimal effort. IN a real life situation you will probably be posting extra information along with it e.g. AddHeadingSection(HeadingModel model). It's really up to you how you go about implementing this.
Also, you might want to consider using AJAX over full postbacks it would make your app a bit slicker.

MVC ViewBag Best Practice [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 1 year ago.
The community reviewed whether to reopen this question 1 year ago and left it closed:
Original close reason(s) were not resolved
Improve this question
For the ViewBag, I heard it was a no-no to use.
I would assume have the content from the ViewBag should be incorporated into a view model?
Question:
Is my assumption above the best practice. (Not to use a ViewBag and second to have it in the view model)
Are there situations where a ViewBag is absolutely necessary?
ViewBag is a dynamic dictionary. So when using ViewBag to transfer data between action methods and views, your compiler won't be able to catch if you make a typo in your code when trying to access the ViewBag item in your view. Your view will crash at run time :(
Generally it is a good idea to use a view model to transfer data between your action methods and views. view model is a simple POCO class which has properties specific to the view. So if you want to pass some additional data to view, Add a new property to your view model and use that.Strongly typed Views make the code cleaner and more easy to maintain. With this approach, you don't need to do explicit casting of your viewbag dictionary item to some types back and forth which you have to do with view bag.
public class ProductsForCategoryVm
{
public string CategoryName { set;get; }
public List<ProductVm> Products { set;get;}
}
public class ProductVm
{
public int Id {set;get;}
public string Name { set;get;}
}
And in your action method, create an object of this view model, load the properties and send that to the view.
public ActionResult Category(int id)
{
var vm= new ProductsForCategoryVm();
vm.CategoryName = "Books";
vm.Products= new List<ProductVm> {
new ProductVm { Id=1, Name="The Pragmatic Programmer" },
new ProductVm { Id=2, Name="Clean Code" }
}
return View(vm);
}
And your view, which is strongly typed to the view model,
#model ProductsForCategoryVm
<h2>#Model.CategoryName</h2>
#foreach(var item in Model.Products)
{
<p>#item.Name</p>
}
Dropdown data ?
A lot of tutorials/books has code samples which uses ViewBag for dropdown data. I personally still feel that ViewBag's should not be used for this. It should be a property of type List<SelectListItem> in your view model to pass the dropdown data. Here is a post with example code on how to do that.
Are there situations where a ViewBag is absolutely necessary?
There are some valid use cases where you can(not necessary) use ViewBag to send data. For example, you want to display something on your Layout page, you can use ViewBag for that. Another example is ViewBag.Title (for the page title) present in the default MVC template.
public ActionResult Create()
{
ViewBag.AnnouncementForEditors="Be careful";
return View();
}
And in the layout, you can read the ViewBag.AnnouncementForEditors
<body>
<h1>#ViewBag.AnnouncementForEditors</h1>
<div class="container body-content">
#RenderBody()
</div>
</body>
1) Is my assumption above the best practice. (Not to use a ViewBag and
second to have it in the view model)
You should use viewmodels instead of passing data via ViewBag as much as possible.
2) Are there situations where a ViewBag is absolutely necessary?
There is no situation where a ViewBag is absolutely necessary. However, there are some data I personally prefer using ViewBag instead of View Model. For example, when I need to populate a dropdown box for predefined values (i.e Cities), I use ViewBag for carrying SelectListItem array to view. I prefer not to pollute my ViewModels with this data.
1) Is my assumption above the best practice. (Not to use a ViewBag and
second to have it in the view model)
Yes.
2) Are there situations where a ViewBag is absolutely necessary?
No. Everything that you have stored in a ViewBag could go into the view model passed to the view.
The issue with ViewBags and the recommended best practice boils down to compile time checking. ViewBags are just dictionaries and with that you get 'magic' strings, so if you end up changing the object type of one of the viewbag items or the key name you won't know until runtime, even if you precompile the views using <MvcBuildViews>true</MvcBuildViews>.
Sticking to view models is best, even if you have to alter them to fit a specific view now and again.
I have found some use for ViewBag where there is common functionality across all pages, and the functionality does not depend on the page being shown. For example, say you are building StackOverflow. The job board appears on each page, but the jobs shown have nothing to do with the page (my usage was similar in concept). Adding a property to each ViewModel would be difficult and time consuming, and a lot of fluff to your tests. I don't think it is worth it in this situation.
I have used a base ViewModel class with the cross cutting data, but if you more than one (e.g., jobs & list of stack exchange sites), you either have to start stuffing extra data in, or some other abuse of a ViewModel, plus you need a ViewModel builder to populate the base data.
As for the magic strings problem, there are a lot of solutions. Constants, extension methods, etc.
With all that said, if you have something that is displayed on your page that depends on the context of the page, a ViewModel is your friend.
Erick
No. Use ViewModels.
No. If you design a perfect ViewModel, you never need a ViewBag.
If you cannot re-design EXISTING ViewModel use ViewBag.
If there were no use cases for it, it wouldn't be implemented in the first place. Yes you can do everything with ViewModels, but what if you don't really need one? One such scenario is editing entities. You can pass DTO directly as a model.
#model CategoryDto
<div class="md-form form-sm">
<input asp-for="Name" class="form-control">
<label asp-for="Name">("Category Name")</label>
</div>
But what if you want to select Category parent? Entity DTO ideally holds only it's own values, so to populate select list you use ViewBag
<select asp-for="ParentId" asp-items="ViewBag.ParentList">
<option value="">None</option>
</select>
Why do this? Well if you have 50 types of entities each with some sort of select from different values, you just avoided creating 50 extra ViewModels.
I thought I'd give my opinion on this, as I've used the ViewBag extensively.
The only real benefits you'll get from using it are for a small project, or in cases where you have a new project and just want to get the ball rolling and not have to worry about creating loads of model classes.
When your project is more mature, you may find issues with unexpected behaviour caused by using weak typing all over your application. The logic can be confusing, difficult to test and difficult to troubleshoot when things go wrong.
I actually went down the route of completely removing the ViewBag from my applications, and preventing other developers from using it within the same codebase by throwing compilation errors when they try to, even within Razor views.
Here's a sample ASP.NET 5 project on GitHub where I've removed it: https://github.com/davidomid/Mvc5NoViewBag
And here's a blog post where I explain the motivations for removing it and an explanation on how the solution works:
https://www.davidomid.com/hate-the-aspnet-mvc-viewbag-as-much-as-i-do-heres-how-to-remove-it
2.Are there situations where a ViewBag is absolutely necessary?
In some case you'll need to share your data from the Controller across the layouts, views and partial views. In this case, ViewBag is very helpful and I doubt there's any better way.
At the risk of opening up an old can of worms here, let me offer a tiny bit of insight. Regardless of what might be the "best practice," let me offer the real-world experience that the extensive use of ViewBag can be a nightmare source of niggling, hard to find bugs and issues that are an utter nuisance to track down and resolve. Even if an agreeable notion or rule for the use of ViewBag can be established, they too easily become a crutch for junior developers to rely on to distraction AND discourage the development of proper, strongly typed ViewModels.
Unfortunately, too many "tutorial" YouTube videos show the use of ViewBags for a demonstration purposes and offer little to no insight on when such a practice isn't appropriate for production code. Yes, there may be times when use of the ViewBag may be a suitable solution to a given problem, but can lead to a long and winding road of frustration and poor maintainability. At the risk of overcorrecting in the cautious direction, I would encourage younger developers not to rely on the ViewBag until they get more experience with MVC, develop a natural sense of when and how ViewModels are useful, and then after that time develop a more seasoned sense of when the use of the ViewBag is appropriate.

Is it okay to hit the database from a custom model binder?

Say I have an object that gets some data from HttpPost and some from the database. I think I want to allow the ModelBinder to go to the database/repository for the that data missing from the post. In practice, is this a good or bad idea?
I've decided to edit my original answer given my thinking on these types of things has evolved since early 2010.
In my original answer, I basically expressed that, while my instincts told me you shouldn't do this, I was uncomfortable saying we shouldn't without being able to articulate why.
Now, I'd recommend against this on the grounds that the responsibility of a Model Binder is to translate a user request into a Request Model and that retrieving data outside of what can be derived from the request goes beyond this scope of responsibility.
I would say a bad idea. The idea of the model binder is that it takes the parameters from the request and creates your model from those. If your model binder, behind the scenes, fills in some of the details from the database this breaks the paradigm. I'd much rather expose the database call in my controller by explicitly fetching the required extra data from the database directly. Note that this could be refactored into a method if used frequently.
I think this is perfectly fine and use this technique all the time.
The only arguments against are very pedantic and amount to arguing over philosophy. IMHO you can put "fill in missing posted data" code into you MVC app as a method in your base controller vs. method in you ActionFilter vs method in you ModelBinder. It all depends on who get what responsibility. To me the model binder can do a lot more than simply wire up some properties from posted values.
The reason I love doing database calls in my modelbinder is because it helps clean up your action methods.
//logic not in modelbinder
public ActionResult Edit( KittyCat cat )
{
DoSomeOrthagonalDatabaseCall( cat );
return View( new MODEL() );
}
vs.
//logic in model binder
public ActionResult Add( KittyCat cat )
{
return View( new MODEL() );
}
It violates the way MVC is supposed to work. ModelBinder is for binging Models from the data that comes from the view. Populating missing info from the database is something that is supposed to be handled by the controller. Ideally, it would have same data layer/repository class that it uses to do this.
The reason it should be in the controller is because this code is business logic. The business rules dictate that some data may be missing and thus it must be handled by the brains of the operation, the controller.
Take it a step further, say you want to log in the DB what info the user isn't posting, or catch an exception when getting the missing data and email admins about it. You have to put these in your model binder this way and it gets more and more ugly with the ModelBinder becoming more and more warped from its original purpose.
Basically you want everything but the controller to be as dumb and as specialized as possible, only knowing out how to carry out its specific area of expertise which is purely to assist the controller.
I would say, no.
Here's why: It would create a dependency on your database for testing your controller actions that would not be easy to abstract out.
I would say it is ok. The argument that creates dependency to database is a false argument for 2 reasons:
1- Database access should be abstracted via repository interfaces. Repository interfaces are part of the domain model and their implementation is part of the infrastructure/data access layer. So there is no dependency to the database.
2- Model Binders and Controllers are both part of presentation layer implemented using ASP.NET MVC Framework. If Controllers are allowed to access database using repository interfaces, how come Model Binders are not allowed?
Also, there are situations that you'd "better" fill the missing data in your model from Model Binders. Consider the scenario where you have a drop-down list on your view. The first time the view is loaded, the drop-down list is populated. The user submits the form but the validation fails. So you'll need to return the form again. At this stage, you'll have to re-populate the list in the Model for the drop-down list. Doing this in Controller looks ugly:
public ActionResult Save(DocumentViewModel viewModel)
{
if (!ModelState.IsValid)
{
viewModel.Categories = _repository.GetAll();
return View(viewModel);
}
}
I believe the initialization of Categories here is ugly and like a code smell. What if you had a few properties that needed to be filled out from database? What if you had more than 1 action that had DocumentViewModel as an argument? You'd have to repeat this ugly step over and over. A better approach is to fill all the properties of the model using the Model Binder and pass it to the Controller. So the object that is passed to the controller is in a "consistent" state.

ASP.net MVC - How to persist model over various views

Situation: In some project management software written in asp.net I have a create project page (working fine). I need to add to this the ability to add tasks from a list of templates to this project pre-creation BUT the list of available tasks is dependent on some values sitting in the create form.
My abstract solution is this:
I have a "Create" view and an "Add Tasks" View - both strongly typed to a composite viewModel defined in the controller
My Create method checks which button was used to call it - if the
button was "Add Tasks" it then renders the AddTasks view, passing the model in from the create view, again all in the same controller.
The AddTasks View posts to the Create view with one of two buttons, one loads the view and the other causes an actually DB save.
My Problem is this:
The different views use different properties of the same model, but in passing this model between them, the data is reset (in any case reload or save).
I am guessing this is happening from auto binding of data - though I thought fields not present on the form would not overwrite existing model data passed down.
There is hardly any code in the controller manipulating the model at present - It is only passed from view to view in these cases.
This is the controller code:
// POST: /Project/Create/<viewModel>
[Authorize, AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Exclude = "Id,id")] ProjectViewModel model)
{
if (model.SubmitValue == "Create")
{
try
{
model.Project.Id = Guid.NewGuid();
model.Save(this.User.Identity.Name);
return this.RedirectToAction("Details", new {id = model.Project.Id});
}
catch (Exception e)
{
this.ModelState.AddModelError(e.ToString(), e.ToString());
}
return View(model);
}
if(model.SubmitValue == "AddTasks")
{
return this.View("AddTasks",model);
}
return this.View(model);
}
//POST: /Project/AddTasks/ + model
[Authorize, AcceptVerbs(HttpVerbs.Post)]
public ActionResult AddTasks([Bind(Include = SelectedCarrierTasks")]ProjectViewModel model)
{
return View(model);
}
The Question is: How do I maintain the state of the model across these views until it finally save it?
I would prefer to avoid any hackish (TempData) or JS dependant solutions, but I am not closed to these if they are really the best solution.
Thanks,
Adam Tolley
One simple solution is to persist the ViewModel object in a Session variable and bind the View from this source.I ts certainly not the most elegant solution. Another option, and probably less elegant one is persist this model data in the database, with some temporary/unsaved flag.
The problem is that when you display the add tasks view you're not providing fields for your "Project" object therefore the ModelState loses the data related to the project, you will need to provide this fields to ensure you're not loosing that data.
You don't need to display this fields they can be of type hidden and they will preserve the value. Just make sure that if you will be binding to a view model you will need to name this fields correctly like this Model.Project.Property.
Perhaps I am trying to solve the wrong problem (ala Bruce Eckel). I am going to try to move to a structure that needs this sort of fuzzy boundary less. I don't want to adopt a REST paradigm only to shoe-horn it into a stateful application.
Possibly these controls belong on the same page, and I can use some JQuery goodness to put in a tab pane for easiness on the eyes.
Thanks to those who answered, I found each useful and will try to remember to up-vote them as soon as I have some more rep.
I can't comment on other peoples questions at the moment, but the only real option is the session if you want to persist an objects state during web requests, or serializing it and placing it in a hidden field.
Or a final option would be to change the way your pages work so you can save the object after each request...
If your using nHibernate then you might want look into the Conversations pattern, but this just essentially saves the nHibernate session into the asp.net session anyway...

Resources