[Original address] ASP. net mvc Framework (part 3): Passing viewdata from controllers to Views
[Original article publication date] Thursday, December 06,200 7 AM
According to Scott Guthrie's original article, the first CTP of the ASP. net mvc Framework will be released on April 9, December 7.
Over the past few weeks, I have been writing a series of posts about the newly developed ASP. NET MVC framework. ASP. net mvc Framework is a Web application that you can use to structure your ASP. NET web application, so that it has a clear separation of focus and facilitates unit testing.CodeAnd optional methods that support TDD processes.
The first article in this series creates a simple list of E-commerce Products/browsing websites. It discusses the high-level concepts behind MVC and demonstrates how to create a new ASP. net mvc project from scratch to implement and test the e-commerce product list function. The second part of the series is about ASP. the URL path selection (Routing) architecture of the net MVC framework is discussed in depth, its working principle and how you can use it to process more advanced URL path selection scenarios.
In today's post, I will discuss how controllers interact with views. Specifically, I will discuss how you can upload data from the Controller to the view to display replies returned to the client.
Brief description of the First Part
In the first part of this series, we created an e-commerce website to support the basic product list/browsing. We use the ASP. net mvc framework to implement this website. This method will naturally structure the code into a unique controller, model, and view component.
When the browser sends an HTTP request to our website, Asp. net MVC Framework will use its URL path selection engine to map incoming requests to the Action Method on a controller to process it. Controllers in MVC-based applications are responsible for processing incoming requests and user input and interaction, execute the application logic based on these inputs and interactions (obtain or update model data stored in the database, and so on ).
When an HTML response is generated and returned to the client, the Controller generally works with the "View" component. These view components are implemented in a separate class or template independent of the controller, the purpose is to fully focus on the encapsulation of display logic.
ViewNoContains any application logic or database access code. All application/Data logic should be processed by the Controller class. The motivation for such division is to help enforce a clear separation between your application/Data logic and the code generated on the interface. At the same time, this makes it easy for you to unit test your application/Data logic independently of your interface display logic.
ViewOnlyUse view-specific data transmitted from the Controller to generate the output. In the ASP. net mvc Framework, we call this view-specific data as "viewdata ". The other part of this blog will discuss some different methods you can use to pass viewdata from the Controller to the view to generate the display.
A simple product list scenario
To help illustrate some of the techniques we can use to pass viewdata from the Controller to the view, let's build a simple product list webpage:
We will use a categoryid integer to filter the products we want to display on the page. Note how we embed categoryid in the URL (for example, products/category/2 or/products/category/4 ).
Then, two different dynamic content elements are displayed on the product list page. The first element is the text name of the classification we want to display (for example, condiments-condiments ), the second element is an HTML <ul> <li/> </ul> product name list. I circled the two elements in red on the screen above.
Next, let's take a look at two different methods we can use to implement the productscontroller class. This class processes incoming requests and obtains the data required for processing requests, the data is then transmitted to a list view for display. The first method we want to study is to transmit this data using the dictionary object bound later, and the second method is to transmit this data using a strongly typed class.
Method 1: Use the controller. viewdata dictionary to transmit viewdata
The controller base class has a viewdata dictionary attribute that can be used to fill in the data you want to pass to the view. You can add an object to the viewdata dictionary in key/value mode.
The following is a productscontroller class. The category action method implements the product list scenario above. Note: How to Use the category ID parameter to query the text name of the category and obtain the product list in the category. It uses the "categoryname" and "Products" keys to store the two data in the Controller. viewdata set:
Then, we call the category action method above.Renderview ("list ")Which template is used for display. When you call renderview like this, it will pass the viewdata dictionary to the view to display the corresponding response.
Implement our view
We will use the list. aspx file in the \ views \ products directory of our project to implement our list view. This list. aspx inherits the site in the \ views \ shared folder. master page layout (when you create a new view page, you can right-click in vs 2008, choose "Add new project"> "MVC View" to add a master page ):
When we use the MVC View content webpage template to create a list. aspx web page, it is not from the common system. web. UI. the page class is inherited from the system. web. MVC. the viewpage base class is inherited (a subclass of the existing page class ):
The viewpage base class provides a viewdata dictionary attribute. You can access the data objects added by the Controller in the view webpage. Then we can retrieve the data objects and use them to display HTML output. You can use server controls or <% = %> to display code.
Use server controls to implement our views
The following is an example of how to use the existing <asp: literal> and <asp: repeater> server controls to implement our HTML interface:
We can use the following background code class to bind viewdata to these controls (note how we use the viewdata Dictionary of viewpage ):
Note: Because <form runat = "server"> is not displayed on the page, view-state is not output. The above control does not automatically generate any id value, which means you have full control over the output HTML.
Use the <% = %> code to implement our view
If you prefer to use in-line code to generate output, you can use the following list. aspx to achieve the same result as above:
Note: Because the viewdata type is a dictionary containing "objects", in order to use the foreach statement for it, we need to convert the viewdata ["Products"] type to list <product> or ienumerable <product>. I reference the system. Collections. Generic and mystore. Models namespaces on the page to avoid entering the complete names of the List <t> and product types.
Note: The "Var" keyword is used above. This is an example of the new C # and VB "type inference" Features in vs 2008 (read my previous post here ). Because we converted viewdata ["Products"] to list <product>, we obtained the complete intelliisense in the prduct variable in the list. aspx file:
Method 2: Use a strongly typed class to pass viewdata
In addition to the dictionary method bound later, the ASP. Net MVC framework also allows you to pass a strong viewdata object from the Controller to your view. There are several advantages to using this strongly typed method:
- Avoid using strings to query objects and get the compile-time check for your controller and view code.
- Avoid explicitly converting the value in the viewdata object dictionary in a strong language such as C #.
- Obtain the Automatic Code intelliisense of your viewdata object in the identification file of your view webpage and the background code file.
- Code refactoring tools can be used to automate changes to the entire application and unit test code base.
The following is a strongly typed productslistviewdata class that encapsulates the list. the aspx view displays the data required for our product list, which contains the categoryname and products attributes (implemented by using the new C # automatic attribute support ):
Then we can update our productscontroller implementation to use this object and pass a strong viewdata object to our view:
Note that the preceding section uses an additional parameter of the renderview () method to pass our strong productslistviewdata object to the view.
Use the viewdata Dictionary of a view with a strong viewdata object
The previously written list. aspx view implementation will continue to work with our updated productscontroller without modifying the code. This is because when a strong viewdata object is passed to a view class inherited from the viewpage, The viewdata dictionary automatically uses reflection to query the attributes of a strong object. So we have Code in the following view:
Reflection is automatically used to obtain the categoryname attribute from the strong type productslistviewdata object. This object is passed in when the renderview method is called.
Use the viewpage <t> base class to forcibly type viewdata
In addition to the dictionary-based viewpage base class, the ASP. Net MVC framework also released a generic-based viewpage <t> implementation. If your view is inherited from viewpage <t>, t indicates the viewdata type transmitted by the Controller to the view, then the viewdata attribute uses the strong type attribute of the t class.
For example, we can update our list. aspx. CS background code class, not inherited from viewpage, but from viewpage <productslistviewdata>:
After this is done, the viewdata attribute on the page will change from a dictionary to a productslistviewdata type. This means that we can no longer use a string-based dictionary to retrieve data, but can use a strong attribute:
Then, we can use the server control method or the <% = %> display method to generate HTML based on this viewdata.
Use server controls to implement viewpage <t> views
The following is an example. We can use the <asp: literal> and <asp: repeater> server controls to implement our HTML interface. This is the exactly the same identifier used when we use the list. ASPX page inherited from viewpage:
The following is the background code. Note: Because we inherit from viewpage <productslistviewdata>, we can directly access its attributes, instead of type conversion on anything (when we decide to rename one of the attributes, we will also get support from the refactoring tool ):
Use the <% =%> code to implement our viewpage <t> View
If you prefer to use in-line code to generate output, you can achieve the same result in list. aspx as follows:
Using the viewpage <t> method, we no longer need to use string query for viewdata. More importantly, note that we do not need to convert any attributes because they are strongly typed. This means that we can write foreach (VAR product in viewdata. Products) without converting the type of products. We also got the complete intelliisense in the product variable in the Loop:
Conclusion
It is expected that this post will provide some details about how the Controller transfers data to the view to display the replies returned to the client. You can use the dictionary bound later or use a strong type to achieve this goal.
When you try to build an MVC application for the first time, you may find it strange to separate the logic of the application controller from the code on the generated interface. You may spend a special period of time building more applications, so you will get used to it and turn your thoughts to processing a request and executing all the application logic, wrap the viewdata needed for the building interface reply and hand it over to a separate view page to display the concept.Important: If this model is uncomfortable for you, use it. The MVC method is purely optional and we do not think this is what everyone wants to use.
However, the benefit of this application division and its goal is that it allows you to run and test your application and data logic independently of the code displayed on your interface. This greatly facilitates the development of comprehensive unit tests for your applications and the use of TDD (test-driven development) processes when building applications. In future posts, I will discuss this in depth and discuss the best practices you can use to easily test code.