I'm developing an ASP.NET web application.
In one view, I have a base model (BaseObject) and depending on a combo box selection there are more fields with specific informations to this object (with own model classes like SpecificObject1, SpecificObject2, ...).
To handle the controller action, my idea is to have the following code:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Update(BaseObject model, FormCollection fc)
{
...
}
My BaseObject has a property for identifying the specific object, for example: model.SubObjectTypeId
My idea is to have a switch in the controller action and to "cast" the FormCollection to the specific model.
Is there a way to do this automatically or do I need to create helper classes which creates an instance of the specific object class and sets the parameters?
The input fields are having the same names as the properties are namend of the specific object.
PS: I'm trying to avoid using AutoMapper. I prefer built-in solutions by ASP.NET MVC.
Thanks for your help.
Usually in these cases is better to build a ModelBinder a class that has the task to create the correct instance for the controller action. It parses the Form collection and creates the instance to pass to the controller.
This way the controllers are thinner and are more respectful of the SRP. :-)
Related
This sounds simple in theory (and it probably is)
I have a view from a Get ActionResult using #model IPagedList
As the model.
I also have a form on the view and when user clicks submit, the code jumps to the post action,
However it throws an error when I try to include IPagedList traclerlist as a parameter in the Post ActionResult.
“Cannot create an instance of an interface”
Tried ICollection and IList and get the same result ?
Any Ideas? Need code ?
Please note this is an MVC 3 application using razor views.
Think about what the model binder is doing. The model binder constructs instances of a class and then uses form values, etc. to populate your model. You are telling the model binder to construct an instance of an interface, which it cannot do. Is it supposed to choose a random class that implements IPagedList? How do you expect that to work?
IPagedList is an interface. You cannot create an instance of this class. It is designed to be a definition for a class for you to inherit from.
I am doing big project in Web Forms and entered a big mess of code(can be solved with little refactoring), so I decided to take a peek at mvc, seems like everyone favores it over web forms.
I have dll file with all LINQ to SQL classes and methods for existing sql db and I started teaching myself by reacreating this project in mvc.I first recreated my homepage from webforms to razor, so far so good and I recreated one of the user controls to partial view and looped it.
Partial view is strongly typed with one of L2S class, the thing is there is some raw data in it.Like for example My model for partial view is my L2S class PostDetails: it consist od some data ready from output like: Title, Permalink, ViewsNumber etc. but it also cointains some raw data like UserId(I need to call method from dll to get username),DateTimeCreated(on which I also need to call method to get time difference), In webforms I would do this in codebehind but I'm not sure where to do it in mvc, maybe in controller and pass it in ViewData.I am also asking this for future, not just this case.
You should perform those actions in the controller. The controller is exactly what it sounds like, it controls the data flow between the model and the view.
Here is an example using your PostDetails:
PostDetailsModel
String Title {get;set;}
String Permalink {get;set;}
Int ViewNumber {get;set}
Int UserId {get;set}
DateTime DateTimeCreated {get;set;}
GetDetailsView: this will be requested by your user, and will be a visual representation of the PostDetailsModel (however you want to format that). When this View is requested, a call is made to your controller....
PostDetailsController
//This method will (by default) come from calling [BASEURL]/PostDetails/GetDetails
public ActionResult GetDetails()
{
var details = new PostDetailsModel();
details.UserId = GetUserId();
details.ViewNumber = GetViewNumber();
....
//By default this looks for a view in the PostDetails folder
//by the name of your method (GetDetails)
return View(details);
}
Notice how the controller is the router between the model and the view, basically. A note, however, it would be better to fill your model from methods contained within some sort of business layer (however you implement that). Something like var details = BL.GetDetails();
Also, when the user makes requests to save data, then you can do that with another method that takes the data (whether it be the PostDetailsModel or an int or...) and does whatever it needs to do, then it can redirect back to the display action (or wherever you need it to go)
There is a wealth of information on MVC with a simple google search. Here is Microsoft's overview, but the wikipedia article is very succinct if you just want the basics
In MVC, All your requests will be handled by an action method in a controller. and then controller returns a view. So you can get the data in your controller (or a different layer which will be called from the controller) and pass that data to your view.
Strongly typed views are a clean way of doing things. Create a ViewModel for your scenario. Mostly ViewModels looks similar to the Entities. Ex : For Displaying the details about a customer, i will create a viewModel called "CustomerViewModel"
public class CustomerViewModel
{
public string CustomerId { set;get;}
public string FirstName { set;get;}
}
Then in my CustomerController, I will have a get method for the customer
public class CustomersController : Controller
{
public ActionResult Details(int id)
{
CustomerViewModel objCustomer=new CustomerViewModel;
objCustomer.FirstName="Samuel";
//Instead of hardcoding the values here , you can get it
// from the database using the id and assign to the properties
return View(objCustomer);
}
}
And you will have a view called "Details.chtml" in your Views\Customer
folder which is strongly typed to your CustomerViewModel
#model CustomerViewModel
<div>
<h2>#Model.FirstName</h2>
<p>#Model.CustomerId</h2>
</div>
This can be accessed like http://yourdomain.com/Customer/Details/25
Personally i prefer to keep my controller actions thin. so i write the GetFromDatabase code in a seperate service layer and i just call that method from my action method
I think that you'll find this article very useful:
MVC Overview
It explains in detail, as to what each component should be used for:
Models. Model objects are the parts of the application that implement
the logic for the application s data domain. Often, model objects
retrieve and store model state in a database. For example, a Product
object might retrieve information from a database, operate on it, and
then write updated information back to a Products table in SQL Server.
Views. Views are the components that display the application s user
interface (UI). Typically, this UI is created from the model data. An
example would be an edit view of a Products table that displays text
boxes, drop-down lists, and check boxes based on the current state of
a Products object.
Controllers. Controllers are the components that handle user
interaction, work with the model, and ultimately select a view to
render that displays UI. In an MVC application, the view only displays
information; the controller handles and responds to user input and
interaction. For example, the controller handles query-string values,
and passes these values to the model, which in turn queries the
database by using the values.
Is it a better idea to have a single ViewModel per view or one per controller action?
Example:
public ProjectController : Controller
{
public ActionResult Edit(int id)
{
var project = ...;
return View(new ProjectEditViewModel(project));
}
[HttpPost]
public ActionResult Edit(ProjectEditViewModel model)
{
}
**OR**
[HttpPost]
public ActionResult Edit(Project model)
{
}
[HttpPost]
public ActionResult Edit(ProjectEditPostViewModel model)
{
}
}
Here are the three options, which is best?
Use the same ViewModel for my POST/GET actions.
Use a ViewModel for my GET action and my domain model for my POST action.
Use a different ViewModel for GET and a different ViewModel for POST.
Using a different view model for the GET and POST actions is the best and most flexible design. But using the same view model for the GET and POST actions also works in 90% of the cases and it is fine a good design. So if using the same view model works in your scenario don't hesitate to reuse it like this.
In the case where different view models are used for the GET and POST actions there is still some relation between those classes: inheritance or composition.
The correct answer
Neither. There's no silver bullet and shouldn't be.
The correct answer is therefore: use as many view models as your user interface process demands. That's regardless of views or controller actions.
Sometimes an action demands a view, other a view. But don't follow some strict guidelines that would hinder your development. View models will come naturally as you develop your application. And should. Otherwise you may end up with unreasonable views that are based on some guideline you've set in stone.
This is actually a similar answer as #DarinDimitrov's, but with a direct conclusion.
Use different model to receive input parameters in Post action (I don't even call it ViewModel in that case) than to pass output parameters to the view.
That way you can customize exactly what input parameters do you accept.
I follow this approach for basic forms:
One view model for the GET
One view model for the POST
The GET model inherits the POST model.
I will often pass a domain object to the GET model's constructor, and do 2 things with it:
Populate the POST model properties with data from the domain object.
Encapsulate the domain object as a local variable in the GET model. I use this for displaying some (read-only) data from the domain object. Saves a bit of effort. Some people will tell you not to do this.
I have a service which has a method that's called when a certain controller method is triggered.
My service returns a custom result object PlacementResult in which I want to communicate errors that may have happened (validation) back to the controller method.
Should PlacementResult have a ModelState or a ModelStateDictionary to communicate errors back to the controller (and finally view)? How would I string this together?
Finally, how do I get the ModelState/ModelStateDictionary (whichever you tell me I should choose) back into the view (highlighting the appropriate text box, show the error message etc.)?
Thank you !
This is a good link that shows how a service can perform validation and communicate the result back to the controller:
http://www.asp.net/mvc/tutorials/validating-with-a-service-layer-cs (fixed link)
No, you do not want to add a ModelStateDictionary to your result type. There is already a ModelStateDictionary on the Controller (in the ModelState property). It is not appropriate for results to set the controller's model state. That should be done during binding or within the controller action itself. Use a custom model binder if you need to.
Your choose one can see the model state errors by examining the controller's ViewData.ModelState property.
Your PlacementResult should return a dictionary object or a List which you should merge with the model state at the beginning of each action.
If you step through you will notice the controllers model state dictionary contains all your input fields, their values and the errors associated with them. You want to merge the PlacementResult errors into the model state dictionary at the appropriate keys. This is how the view engine knows which fields to flag as invalid.
ModelState.Merge(PlacementResult);
if(ModelState.IsValid)
{
...
}
I don't know what your PlacementResult looks like, see if you can possibly utilize this in your view:
ModelState.AddModelError(ErroredProperty, ErrorMessage);
Make sure you return the object that failed back to the view
return View(myObjectInstance);
Based on SoC I think you have to return errors from your services and merge them in your ModelState if needed.
But our objective is maintain decoupling and also to use ModelState.Merge() method. it isn't?
There is an concrete implementation that could help
You can pass the Controller to your method, since the Controller class contains the ModelState property. Once in your method you can do the following:
private PlacementResult BuildResult(Controller controller)
{
controller.ModelState.AddModelError(propertyName, errorMessage);
}
In your action...
BuildResult(this);
if(ModelState.IsValid) {...
I'm wondering what the real measurable advantage to using Modelbinders is?
Rather than getting primitives sent into your action:
public ActionResult Search(string tagName, int numberOfResults)
you get a custom object:
public ActionResult Search(TagSearch tagSearch)
This makes your Search action "thinner" (a good thing), much more testable and reduces maintenance.
Model Binders
A model binder in MVC provides a
simple way to map posted form values
to a .NET Framework type and pass the
type to an action method as a
parameter. Binders also give you
control over the deserialization of
types that are passed to action
methods. Model binders are like type
converters, because they can convert
HTTP requests into objects that are
passed to an action method. However,
they also have information about the
current controller context.
From here.
Here's another benefit:
You can create modelbinders that retrieves an object from the database just given an ID.
This will allow you to get actions like this
// GET /Orders/Edit/2
public ActionResult Edit(Order order){
return View(order);
}
And the custom ModelBinder would do the datafetching for you, keeping your controller skinny.
Without that ModelBinder it could look like this:
// GET /Orders/Edit/2
public ActionResult Edit(int id){
var order = _orderRepository.Get(id);
// check that order is not null and throw the appropriate exception etc
return View(order);
}