I have been working on this MVC 3 Razor app and typically utilize view models for my views.
A fair number of my view models contain more information than just the particular entity that I am interacting with in my form. So my GET action handler will init the view model and provide each property with the intended value etc..
In my POST action handler I check to see if the model state is valid, if not I redisplay the form/view with errors.
In my POST action handler I find myself having to copy the code from my GET action handler in order to re-render the view again. How can I implement my controller actions so that I am not having to copy the code that is responsible for gathering the data for the view model?
I have tried allowing my action handler to handle both POST and GET but then I have the input params to deal with. My POST action handler will have the view model as an input parameter but for the GET action handler will not.
Your POST handler can return the ActionResult from the GET handler, as follows:
public ActionResult SomePageGet() {
var model = new SomePageViewModel();
// Populate ViewModel:
...
return View("SomePageGet", model);
}
[HttpPost]
public ActionResult SomePagePost(SomePageViewModel input) {
// Validate the model:
...
if (!ModelState.IsValid) {
// Return the GET page, with error messages:
return SomePageGet();
}
return View("Success");
}
Since the ModelState holds all error messages (and invalid input), the GET page will show them normally.
In situations like these we create builders for our view models.
Take a look at option 3 under this post.
You can simply refactor the common code into an extension method on the main entity you're working on.
Then call it as many times as you wish while staying DRY.
I don't precisely know what's the function of that common code, but mostly it will be related data for rich presentation.
In that case the solution which I prefer, is to let the view load the extra data from another action using RenderAction which can be later refactored to AJAX page update staying DRY and separating concerns of actions.
"...I find myself having to copy the code..."
I don't understand why; why can't you simply create a member in your controller and call it? Not everything in your controller has to be an Action. But you might want to look at builders instead as #ataddeini suggested.
Your POST action method should be able to just the the viewmodel type as the parameter, instead of all the individual pieces of data. If the viewmodel is more complex to build, you may want to write a modelbinder for your view model that can do that more complex work (your action method would still take the VM type as the parameter).
[HttpPost]
public ViewResult MyAction(MyViewModel model) {
// model should now be fully populated; check ModelState.IsValid though in case there are errors (such as the user entering "abc" for an int property)
}
Related
I'm interested in the concept, not the implementation. Consider a CarBookingRequest scenario where user through an interface requests for booking a car. Let's discuss it under the following constraint and taking only View in perspective by keeping Controller and Model simple:
There is one controller class/code which contains all the functions representing relevant actions
There is one model class/code that deals only with single database with few tables (no other data models)
There can be many interfaces through which a request can be made:
1. Desktop Application
A user clicks a Button that fires the Click event which in turn is pre-programmed to make a call to BookingController with request NewBooking. Something like:
Event OnClick() {
C = New BookingController
C.Request('NewBooking')
}
2. Mobile Application
A user taps a Button that fires the Touch event which in turn is pre-programmed to make a call to the same BookingController with request NewBooking. Something like:
EventListener OnTouch() {
C = New BookingController
C.Request('NewBooking')
}
3. Vending Machine
A user presses a PushButton on the machine that fires the event which is pre-programmed to make a call to the same BookingController with request NewBooking. Something like:
Event OnPress() {
C = New BookingController
C.Request('NewBooking')
}
Assume similar implementation for a Web Interface and Service Interface where the request is made by another system or a scheduled task. Obviously all these implementation are different versions of BookingViews written in very different languages and platform. Now if I knew these implementations beforehand and I am making a Booking MVC, what should be my View, Controller and Model Class like? or how many? and why?
Should I have a "Main" BookingView class that has a function such as:
Function CallController(Command) {
If Command = 'NewBooking' {
Return New BookingController
}
or some good implementation of controller/action registry to fetch appropriate controller
}
and every specific View should in-turn call this function which then will call the BookingController as:
Event OnClick {
C = MainView.CallConroller('NewBooking')
}
Or should each View call the controller separately in its own way?
May be too many questions but I am of the view that my View, Controller and Model should be reusable and every new Interface (Mobile, Machine or Web) should require only their specific handling of the View (events or displays) while the connecting and fetch data code remains untouched.
The core idea of MVC patterns is to separate the three aspects of the application - model, view and controller - from each other.
The way you describe your solution, doesn't seem to adhere to this principle. Let me suggest a method that helps you to achieve good MVC, following these rules. I am describing the generic rules, you can then modify according to the specifics of your application, frameworks etc:
Your controller should not know about the views. This rule helps to separate "view" from control. If you follow this rule, your controller, instead of worrying about types of client, can just return one type of resource (e.g. a JSON resource, in this case a Booking). Then, each client (Web, mobile, machine) has to handle presentation of this resource, whichever way they want. But the important point is that, it is not the concern of controller.
Your Model should not know about the controller. The concern of Model is to implement a car booking. It does not know what is being done with it (like whether a controller wants to access it to then pass it to someone else or so). For example, it may have an interface such as
CarBooking:
constructor();
book();
unbook();
...
It performs the business logic of constructing a request, booking a request or removing a booking. Period.
How do you achieve this, proper separation of Model, View and Controller? Well, one method is to start from within, and then move outward. That is, start from Model, then controller, then view. In reality, you may not do it in this order as you has to consider all of these aspects. But, what I am saying is more in the logical sense.
i am new in mvc and learning it by going through wrox book. i encounter few thing and i am looking for good clarification.apologized for asking many question in one shot.
1) #Html.DisplayFor & #Html.EditFor
when we use #Html.DisplayFor then what html control render at client side ?
when we use #Html.EditFor then what html control render at client side ?
2) what ModelState.IsValid does ?
i always see ModelState.IsValid return true ? when it actually return false ?
3) how to extract the form submitted value from ModelState ?
i try to do it this way like ModelState["Name"] or ModelState["Name"].ToString() both gives error.
4) what is Remote Validation in mvc ?
5) when we use html helper to render text boxes then how could i attach multiple attribute with it. i tried this way
i tried to display model text like this way but did not
#Html.LabelFor(m => m.Name, new { #id = "name", #class = "", title = "#m.Name" })
can't we specify or assign model text like this way title = "#m.Name" ? if not then how could i assign a model text to title attribute ?
when we need to use # sign when we work with html controls attribute
6) Is it possible to call different type of function/method directly from view
i like to know that
a) if i have few static function or static classes function then can we call it directly from view ?
b) can we can controller method directly from view ?
c) how to call any generic method directly from view?
d) is it possible to call any action method directly from view ?
e) can we can call any model method directly from view ?
which is possible and which is not please explain with reason and sample code
7) regarding data annotation
i want to work with data annotation but i want data annotation should render different js in page for fancy validation message. how to use different jquery validation plugin with data annotation....where we need to change in code.
please answer all my question point wise with example & sample code for better understanding. thanks
when we use #Html.DisplayFor then what html control render at client side ?
That's totally gonna depend on the specific type of the property you are calling the DisplayFor on. The DisplayFor helper will analyze the specific type of the property used in the expression and invoke the corresponding display template. You could also write custom display templates for your view model types. Brad Wilson wrote a nice blog post about templates that I invite you to go through to better familiarize with the basic concepts: http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-1-introduction.html
There are a series of posts, make sure you've read them all.
when we use #Html.EditFor then what html control render at client side ?
That's totally gonna depend on the specific type of the property you are calling the EditorFor on. The EditorFor helper will analyze the specific type of the property used in the expression and invoke the corresponding editor template. You could also write custom editor templates for your view model types. Brad Wilson wrote a nice blog post about templates that I invite you to go through to better familiarize with the basic concepts: http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-1-introduction.html
There are a series of posts, make sure you've read them all.
i always see ModelState.IsValid return true ? when it actually return false ?
When there are errors added to the ModelState. Could happen if you have used some data annotations on your view model to do validation and the values submitted to the server failed this validation. Normally it's the default model binder that is adding error messages to the ModelState (making ModelState.IsValid return false) when binding the request values to your view model.
i try to do it this way like ModelState["Name"] or ModelState["Name"].ToString() both gives error.
In ASP.NET MVC you use a view model. Your [HttpPost] controller action takes a view model as parameter which is a class specifically designed to meet the purpose of your view logic. Here's an example of how a typical POST action might look like in ASP.NET MVC:
[HttpPost]
public ActionResult SomeAction(MyViewModel model)
{
if (!ModelState.IsValid)
{
// validation on the view model failed => redisplay the view
// so that the user can fix the errors
return View(model);
}
// At this stage you know that the model has passed validation
// It is here that you would typically map the view model to some domain model(s)
// and pass them to your DAL for some processing.
// Finally when this processing completes redirect (Redirect-After-Get pattern)
return RedirectToAction("Success");
}
4) what is Remote Validation in mvc ?
It's a view model property decorated with the [Remote] attribute which in turn emitted some HTML5 data-* attributes on the corresponding input field. In turn the jquery.validate.unobtrusive.js script will use those properties to send an AJAX request to the corresponding controller action to perform validation before the form is actually submitted. Please feel free to read the corresponding documentation: http://msdn.microsoft.com/en-us/library/gg508808(v=vs.98).aspx
a) if i have few static function or static classes function then can
we call it directly from view ?
No of course not. This question doesn't have any sense. The view doesn't know about any server side specific things other than controller actions. So if you want to call something from a view this something in the ASP.NET MVC world is called a controller action. You could of course us AJAX or something to call it.
b) can we can controller method directly from view ?
Yes, of course, if this controller method returns an ActionResult in which case this controller method has a name: A controller action.
c) how to call any generic method directly from view
Absolutely impossible. That would have been a huge security vulnerability if it was possible. You can only invoke controller actions from a view.
e) can we can call any model method directly from view ?
No, for the Christ sake. I repeat: That would have been a huge seurity vulnerability if it was possible. You can only invoke controller actions from a view.
i want to work with data annotation but i want data annotation should
render different js in page for fancy validation message. how to use
different jquery validation plugin with data annotation....where we
need to change in code.
Sorry, I have strictly no idea what you are asking here. ASP.NET MVC client side validation is tightly coupled with the jquery.validate plugin (whose documentation I invite you to read to better understand its functionality: http://jqueryvalidation.org/documentation/). And if this plugin doesn't meet your requirements, after all, ASP.NET MVC view spits HTML, so feel more than free to use some of the gazillions available javascript validation plugins out there that might fit your specific needs.
Hopefully this answers some of your questions. Next time you post a question on StackOverflow make sure that it is very specific and not asking about the philosophy on the entire world (as you did here). Make your homework, read the documentation, and if you have specific issues, post your code, explain the difficulties you encountered with it, and we will be glad to help.
I have looked at previous questions but I could not find an answer to this particular scenario: I am using ASP.NET MVC 3 with a TDD approach. On my action methods, I use the return type of ViewResult opposed to ActionResult. This is fine to test my controllers. However, I need to test my view models as well as my controllers. I can do this quite happily by using the Model property on the ViewResultBase (which is implemented ViewResult but not ActionResult) for my model tests.
If there view model is null then I would like to redirect to another action. ActionResult supports a RedirectToAction method. However, ViewResult does not. I have tried the View method but the url does not change in the browser address bar. Also, I even tried the classic ASP.Net Response.Redirect(...), unsurprising, my unit test complains that the Response object has not been populated.
So, what approach do I use to achieve the equivalent of the ActionResult RedirectToAction for ViewResult?
if you need to return more than one result type from a controller, then set its return type to action result and then assert that the different conditions create the right result type.
For instance, in AJAX actions, you may want to return HttpStatusCodeResults to set the response property to errors should validation fail or there be an exception.
Then when the action has succeeded, you may want to return a partial view for display with the result.
Using this approach you can tailor your logic in your controller and still assert the different results are correct.
I found a way to do it. I used the following steps:
I set my action method return type to ActionResult
I changed its unit test to use ActionResult
I created two additional action methods with the return type of ResultView.
For each branch of the if statement of action method from [1], I redirected to the appropriate action method in [3], I used RedirectToAction to redirect.
I create two unit tests that use ResultView to test the action methods created in [3] and give me access to the underlying Model for each.
I am currently developping a full-web application under VS2010 and I am using the ASP .NET MVC 3 framework.
Here is a simplified overview of my application :
I have implemented a controller Ctrl1.
Ctrl1 contains a HttpGet action method ActMeth1.
The Ctrl1Views folder contains a view View1.
I have implemented a controller Ctrl2.
Ctrl2 contains a HttpPost action method ActMeth2.
ActMeth2 returns a view View2 included in the Ctrl2Views folder.
Ctrl1 and Ctrl2 are in the same namespace.
I want ActMeth1 to call ActMeth2 to perform some logic and then to return View2.
Here is the source code of ActMeth1 :
public ActionResult ActMeth1()
{
Ctrl2 myCtrl2 = new Ctrl2();
return myCtrl2.ActMeth2();
}
Unfortunately ActMeth1 returns View1.
Does someone can give me an explanation to this fact ?
Thanks in advance for your future help
Instantiating a controller's action method in another controller's action method is inviting trouble in the long run.
You can use tempdata, or pass the data via route dictionary of RedirectToAction.
I think you better reorganize your logic
As you are trying to do this logic in server side anyway,
a. Create a service that does the work for both the controllers
b. make the view shared between both the controller actions or create a partial view for the common html
c. Call the appropriate service method and render the shared view
You could do:
public ActionResult ActMeth1()
{
Ctrl2 myCtrl2 = new Ctrl2();
myCtrl2.ActMeth2();
return View("~/Views/Ctrl2Views/View2.cshtml");
}
I'm not sure you should be instantiating controller 2 from inside controller 1 though...
If a view needs to acces data from a model, do you think the controller should:
a) pass the model to the view
b) pass the data of the model to the view
c) neither; it shouldn't be the controllers concern. Let the view access the model directly to retrieve the data. Only let the controller give some parameters the view needs to filter the data from the model.
d) it depends on the situation.
e) none of the above, but [...]
Thanks
After some debate in the comments to an answer that was deleted by the user, maybe this needs clarification. My view of the MVC architecture is biased towards that of the Zend Framework (php) in which an action in a controller by default has a default view assigned to it. So it's not so much the model that dictates which view is approporiate, but rather the controller. Do you feel the model should dictate what view is appropriate? The only way I see fit to let the view be build based on a model, is by letting the controller pass the model to the view. Are there other techniques to let a view access a model without the controller being involved? Or is it perfectly fine to let a controller pass the model to a view, so that the view can be build based on the models attributes?
e) None of the above; pass in a view-optimised "ViewModel".
Example in ASP.NET MVC:-
public ActionResult Details(int id)
{
Product p = ProductService.GetProductById(id);
if(p == null) { return RedirectToAction("Index"); }
ProductViewModel model = new ProductViewModel(p);
return View(model);
}
both a) and b) "will do" subject to d). Never ever c).
Typically, the ViewModel just encapsulates the Model (if nothing complicated is going on, your view could access the model directly via ProductViewModel.Product). If the view needs to do anything complicated with the Model however, it's the ViewModel's responsibility to do that, rather than the responsibility of the Controller, or the View.
This keeps your concerns nice and segregated. Your Controller doesn't care exactly what specific data your View needs (beyond the fact that it's rendering some Details of a Product), or especially what format your View needs that data in. Your View doesn't depend on the implementation details of your Model. Your Model doesn't have to concern itself with how it's being Viewed. If you have two Views rendering Products (e.g. Create, Edit, Summary, MoreDetails etc), those Views can have different ViewModels to expose only the data that each specific View needs, so your Views aren't depending on eachother. Lovely :)
Some further reading from various viewpoints:-
http://www.thoughtclusters.com/2007/12/datamodel-and-viewmodel/
http://stephenwalther.com/blog/archive/2009/04/13/asp.net-mvc-tip-50-ndash-create-view-models.aspx
http://www.nikhilk.net/Silverlight-ViewModel-MVC.aspx
I think ViewModels are a particularly .NET thing, but I see no reason at all why the pattern can't be used in PHP.
Hope this helps.
Ideally, it should "pass the data of the model to the view" so the view doesn't need to know any explicit structure of the model and thus be more reusable and designer-friendly.
But practically, "pass the model to the view" works as just fine. Most of the time you will need a new view anyway because clients never share favorite colors (if you know what I mean :-) so views re-usability doesn't justify having a lot of tedious code required to copy data from the model to the view.
What you should concern more about is the modularity of the controller itself, since many websites do share common functionalities (controllers) such as web forums or a news listing but not looks (views)
This is late I know, but I'm having this issue on a project I am working on. I started with a) - for simplicity - and now running into road blocks.
I am coming around to this method:
e) None of the above; pass in a view-optimised "ViewModel".
because it avoid bloating both your model classes (instances of which are "transaction objects") and your views. For example, you may need to render a number with a specific number of decimal places (this is the problem I am having now).
With an intermediate "ViewModel" this is easy - you just write the relevant ViewModel "getXXX" method to return the number formatted how you wish.
If you just pass the model directly into the view, you will need to specify it in the view every time you use this figure (going against DRY - don't repeat yourself), or alternately, add a rendering method to your model classes (which goes against a class being for one purpose only).
Cheers
a) pass the model to the view
Otherwise the controller is manipulating the view via screening the model. This is what would happen in "b) pass the data of the model to the view". The b) option doesn't really even make sense in the pure MVC pattern. After all, the model IS the data. If the model is changed for consumption, a view has been applied, whether you choose to do it in the controller and pass it off as a controller function. What happens when you have a different view? Does the controller screen its data differently? You soon have two views for model, the controller sub-view and the view itself.
For me that's e).
As already mentioned here, ideally the view and the model are decoupled. The way I prefer to implement this is to have a viewHelper for a model. This has the API the view can use to get the data. Now views are not affected by changes in the model and the view doesn't need to 'get' the internals of the model. These are hidden away by the viewHelper.
example:
class Post {
public function export(ViewHelper $helper) {} // I try to avoid getters when I can
}
class PostViewHelper {
public function getTitle($parameters) {} // title of current post in the loop
}
class PostView {
private $helpers = array();
public function loadTemplate($path) {}
public function addHelper(ViewHelper $helper, $name) {}
public function __get($key) {} // if exists $this->helper[$key] etc
}
in a template
<h1><?php $this->post->getTitle(); ?></h1>
You may want to implement this differently. But my point is in how the view and the model are decoupled, introducing an intermediate viewHelper wich creates the view/template API.
I don't think it's that complicated. a or b.
The controller's job is to manage the relationship. It finds the model and view and provides the view all the model data it needs to do its job. That's it. MVC doesn't dictate the exact form the data takes.
(a) Start simple. It's pretty natural to pass the model objects directly to the view. If you have a page about a Foo, just pass the Foo.
(b) But at times-- and only at times-- you create a value object / DTO to get the data to the view (called a ViewModel above). Do this when there's a mismatch between the view and the native model, such as summary views. If the view is presenting a summary of 1,000,000 objects, you don't want to hand the view the model objects; you want to hand the view a summary of the 1,000,000 objects.
And the exact implementation really depends on the language and framework you are using. But I think these guidelines are a good start.
uhh b.
i dont really see the difference between a and b other then some technicallity of how you will be passing data.
usually you pass a map of data to the view with some data from the model