I am learning ASP.NET MVC, and ran across a video on the asp.net/mvc website that showed how to retrieve a value from a textbox after a postback. In the video the author simply grabs the value from the Request object in the controller.
It seems like this breaks the separation of concerns concept? By doing this the controller is now dependent upon the presence of a Request object which won't exist if one runs unit tests against the controller.
So I assume this is an incorrect way of retrieving form data on a postback. What is the correct way? Once I am in my controller, how do I get access to the postback data?
It seems there should be some intermediate step that essentially pulls the data from the postback and packages it into a nice object or some other format that the controller would then used?
The data should be posted back to your Model or ViewModel. Your controller method that handles the POST will expect the model to be provided as a parameter.
Here is a blog entry that gives an example
Using model binding, MVC can populate data coming from the form data, the query sting, cookies, and a number of other sources directly into your object model or other paramters defined as parameters to your action methods in the controller.
There's too many details of how this works to summarize here, but it is the cornerstone of the power of ASP.NET MVC.
Check out Models and Validation in ASP.NET MVC as a good starting point. You'll find tons of other resources around MVC model binding out there.
I've really liked Steven Sanderson's Pro ASP.NET MVC 2 Framework if you prefer physical books.
Related
I am currently working with integrating a classic asp site with MVC3. I have some questions on some areas of the integration that I would like some feedback on.
Firstly, I have a asp page posting to an MVC controller action. I have very little scope to modify the asp page. I want to take the form fields posted from the asp page and map them in to a model object. The posted values have obscure names such as "my_name" which I want to map to Name property on the model object. Is the best way of doing this via a Model Binder or is there an alternative?
Next question I have is a follow on from the previous, I am concerned with any cross site scripting so want to check the values of the posted variables to be valid and contain no strange characters etc. Is there something built in to MVC3 that does this out of the box?
When the asp page posts to the controller action, I would like to show a waiting icon while the controller action is processing as the controller action could take 10 seconds plus as it must call external systems etc. Therefore I don't want the post to seem as its hanging. Is it possible to wire up the controller action to return a view with a waiting icon, while the main body of the action is processing in the background and once complete redirects to another page?
Is the best way of doing this via a Model Binder or is there an
alternative?
The best way of doing is a model binder. You can have a custom model binder to take care of the ASP scenario that maps the my_name to Name. Mostly you should have a separate action to handle the requests coming from classic asp and you can link the custom model binder to only this action.
Is there something built in to MVC3 that does this out of the box?
The request validation is enabled as default in MVC. So if an user tries to post a script block to the action MVC will throw exception. Of course you can switch off request validation by decorating the action with ValidateInput(false) if you need.
For long running actions you have to use asynccontrollers.
In the application I'm developing in ASP MVC 3 I have the following scenario. I have some properties of the model that I wanna use after the page makes a request, however when the post request is done they arrive as null since they are not bound to any control in the view form.
For what I've read this is the expected behaviour of ASP MVC and people recommend to use a #Html.HiddenFor() to be able to receive them, but I don't want this information to be available to user in case he selects "View source" from the browser.
In JSF I remember that you could use the #ViewScope annotation for this scenario, but is there something similar in ASP MVC? For what I've read saving them in the ViewData property will not work either and I do not want to use the Session because this properties will only be relevant in this particular view.
If I understand your question correctly, you may be looking for something like TempData.
You can read about it here:
http://blogs.teamb.com/craigstuntz/2009/01/23/37947/
A more recent post can be found here:
http://codeoverload.wordpress.com/2011/05/29/controller-tempdata-in-asp-net-mvc-3/
Is there a way to keep information between post backs in MVC2 without utilizing Session variables or the query string?
You mean like the view state from .NET Web Forms? Technically there is, although it isn't recommended - you're much better off utilizing models and posting the model data to the server and pushing the model back into the view.
This will work well but if you're needing something as stateful as the WebForms ViewState, I would recommend doing your project in WebForms or use the session to save your models.
Edit: Build your form that posts (or gets) data back to the same page. Then in your controller, have a method like this.
[HttpPost]
public ActionResult LoginUser(LoginViewModel model)
{
//work on the model here
return View(model);
}
This will push the form data that the user just submitted back into your view. Then have an Html helper like this in your view.
<%: Html.TextboxFor(m => Model.Username) %>
There are a slew of excellent resources on the web about using html helpers with models. Google around and you'll come across them.
You could use Hidden Form fields to POST the values back to the server with each form submission.
Other alternatives include a cookie or Http Cache - what is stopping you using session?
As a high level concept, you should rely as little as possible not only on Session to store your state, but on statefulness in general in a web application. The idea is that the web itself is stateless by design, and when designing software on that paradigm the software should be designed to embrace a stateless nature.
More specifically, using a ViewModel gives you a strongly typed representation of the data needed for your view to pass down to the client. Pieces of that data which hold information about the state of a given request which can be made from that view can be added to the view in probably a number of ways, but the two most immediate ones are:
As hidden form field elements
As parts of URLs for requests
Check out the NerdDinner tutorial for a standard approach to using either ViewData or a strongly-typed ViewModel. Some Google searches will, as always, yield more information and tutorials. But note specifically where the tutorial uses the ViewModel properties in the view. These can be used anywhere in the rendering of the HTML, either in the HTML helpers or in manually constructing the tags.
Additional interesting reading regarding the statelessness of the web (and this whole not-as-new-as-many-people-seem-to-think REST thing) is the article: How I Explained REST to My Wife.
If your main issue with the Session variables is of a practical nature (want something that works for a single request, not needing to worry about cleaning it up etc) rather than a requirement to not use Session then use the TempData dictionary. It deals with putting information in the Session for a single request only and the framework will automatically remove it for you afterwards.
I'm trying to work out if there's a built in way in ASP.NET MVC to assign the form values that are POST'd back to the properties of the ViewModel that was originally sent to the View?
So I'm thinking along the ideas of decorating some of the properties in the ViewModel with an attribute and then reflecting over the ViewModel and using that name to extract values (and coerce) from the Form[] object.
However, I'd imagine that something like this was already built in and so don't want to re-invent the wheel here.
The problem that I'm trying to solve is that a user clicks a button on a form and the server validates the data and if there are errors we return the user to the form by using the same ViewModel to carry the data and thereby fill the values back into the form that the user originally entered.
(Yes, I'm also doing client side validation using JavaScript to make this lightweight but for security I have to repeat validation on the server.)
Ideas?
You can use UpdateModel or TryUpdateModel in your controller.
I recommend using one of the overloads in which you specify the fields to be updated.
This is discussed in detail on page 78 of the Wrox Professional ASP.net ebook (or echapter!)
I don't think MVC has anything like this built in, or at least I haven't seen anything. It would be nice though as many other MVC frameworks do this (struts for example).
What are the basic differences between classic .cs-aspx.cs-aspx (code behind/beside) model and new MVC model?
The basic difference between MVC and classic ASP is that in classic ASP all of the code and mark-up for the application exists in the .asp file. In MVC the .aspx file contains only the code and mark-up for rendering the page. The rest of the application for handling requests, retrieving model data, and enforcing business logic exists in controller and model classes. These classes can be much more easily tested than class ASP code because it is separated from the code that is responsible for rendering the view.
This separation of concerns is the basis of the MVC pattern. According to the pattern, the code is divided into three major components -- Model, View, and Controller. Classes in the model represent the business objects for the application, the persistence framework, and business logic applied to the business objects. Classes in the controller accept incoming requests, use the inputs or query parameters to retrieve the appropriate model data, and generate the necessary data for the view to render. Views (aspx pages) take the data supplied by the controller and generate the mark up.
Webforms (codebehind) is somewhere between classic ASP and the MVC pattern. Webforms does not enforce the separation of concerns in the way that MVC does, but it does allow much more of the code to exist "behind" the actual page. For example, you can separate out the business objects, business logic, and persistence framework (the Model, if you will) from the code that is responsible for generating the view. The difficulty is that the controller actions (input handling and model retrieval) are still linked with the view rendering code. This integration makes it much more difficult to test this code and makes the view/controller code much more dependent on each other than is necessary -- the concerns are "mixed", not "separated." In general, this is evidence of bad design because it make it more difficult to make needed changes in the future.
Hope this helps.
Simply put it this way: MVC is how really web apps should be built. Code-behind (asp.net web forms) is not a good practice. If you are truly a developer you will appreciate that the MVC is the best practice since it really separates logic from data and presentation. Simply MVC is the elegant and right way.
A really simple way to perceive the difference between MVC and ASP (or ASP.NET forms for that matter) is that in MVC the Controller is the handler of the request.
Requests get routed to a controller not a 'page' or a 'form'. The controller will pass along info in the request to the model then make some simple choices as to which view that should be used to present the desired state of the model. Note this is the important point the controller has a choice of what view to use in the response.
MVC breaks the relationship between the requested URL and the UI code needed to render a particular representation of data.