Implement Model-View-Controller in ASP.NET

xiaoxiao2021-03-06  54

Implementing Model-View-Controller Copyright Notice in ASP.NET: 9CBS is this BLOG managed service provider. If this paper involves copyright issues, 9CBS does not assume relevant responsibilities, please contact the copyright owner directly with the article Author.

Implementation strategy

To explain how to implement Model-View-Controller mode in ASP.NET, the benefits of separating models, views, and controller roles in software, the following example reconstructed a single page solution without separating all three roles To separate these three roles. The sample application is a web page with a drop-down list (shown in Figure 1), which shows a record stored in the database.

The user selects a specific record from the drop-down list, and then click the "Submit" button. Then, the application retrieves all track information in this record from the database and displays the result in a table. All three solutions described in this mode implement the identical functionality.

Single ASP.NET page

This page can be implemented in the ASP.NET in many ways. The simplest, most direct way is to place all content in a file called "Solution.ASPX", as shown in the following code example:

<% @ Import namespace = "system.data"%> <% @ import namespace = "system.data.sqlclient"%> start </ title> <script language = "c #" Runat = "Server"> void page_load (object sender, system.eventargs e) {string selectcmd = "select * from recording";</p> <p>SqlConnection myconnection = new SqlConnection ("Server = (local); Database = Recordings; trusted_connection = yes"); sqldataadapter mycommand = new sqldataadapter (selectcmd, myconnection);</p> <p>DataSet ds = new DataSet (); myCommand.Fill (ds, "Recording"); recordingSelect.DataSource = ds; recordingSelect.DataTextField = "title"; recordingSelect.DataValueField = "id"; recordingSelect.DataBind ();} void SubmitBtn_Click (Object sender, EventArgs e) {String selectCmd = String.Format ( "select * from Track where recordingId = {0} order by id", (string) recordingSelect.SelectedItem.Value); SqlConnection myConnection = new SqlConnection ( "server = (Local); Database = Recordings; Trusted_Connection = YES ");</p> <p>Sqldataadapter mycommand = new sqldataadapter (selectcmd, myconnection);</p> <p>DataSet DS = New Dataset (); MyCommand.Fill (DS, "TRACK");</p> <p>MyDataGrid.datasource = DS; mydatagrid.database ();} </ script> </ head> <body> <form id = "start" method = "post" runat = "server"> <h3> recording </ h3> Select Recording: <br /> <asp: DropdownList ID = "RecordingSelect" runat = "server" /> <ask: button runat = "server" text = "submit" onclick = "submitbtn_click" /> <p /> <asp : DataGrid ID = "MyDataGrid" runat = "server" width = "700" backcolor = "# ccccff" bordercolor = "black" showfooter = "false" cellpadding = "3" cellspacing = "0" font-name = "verdana" Font-size = "8pt" Headerstyle-backcolor = "# aaaAadd" enableViewState = "false" /> </ form> </ body> </ html> This file implements all three roles in this mode, but not Separate them into different files or classes. The view role is represented by a page generated code associated with the HTML specific related page. This page uses the implementation of the binding data control to display the DataSet object returned from the database. Model roles are implemented in page_load and subsmitbtn_click functions. The controller role is not directly represented, but is implied in the ASP.NET; see "Page Controller" Page Controller "updated when the user issued a request. Model-View-Controller describes it as a passive controller. The ASP.NET implements the controller role, but the programmer is responsible for connecting the action to the controller will respond to the event. In this example, the controller calls the page_load function before this page is loaded. When the user clicks the "Submit" button, control The SubmitBTN_Click function is called. This page is very simple and is independent. This implementation is very useful. When the application is small and does not change, it is a very good start. However, if the following occurs during the development process One or more of them should be considered to change this method.</p> <p>I hope to improve parallelism and reduce the possibility of errors. You may want to write view code and model code from different people to improve parallelism and limit the possibility of errors. For example, if all code is on a web page, the developer may accidentally change some source code for some access to the database when changing the DataGrid format. You will find this error until you check this page again, because it is compiled when you view this page again. You want to use the database access code on multiple web pages. In the current implementation, any code cannot be reused in other pages without repeating code. Duplicate code is difficult to maintain, because if the database code changes, you must modify all the webpages that access the database.</p> <p>In order to solve some such problems, the implementation of ASP.NET introduces code hidden features.</p> <p>Code hidden reconstruction</p> <p>With the Microsoft Visual Studio® .NET development system, you can easily divide the representation (view) code from Model-Controller code. Each ASP.NET page has a mechanism that allows the method to be called from the web page to be implemented in separate classes. This mechanism is provided through Visual Studio .NET, which has many advantages, such as Microsoft IntelliSense® technology. When you use the code hidden function to implement a web page, you can use IntelliSense to display the list of available methods of the objects used in the page backed by the page. IntelliSense does not apply to .aspx pages.</p> <p>The following is the same example, but this time you use the code hidden function to implement ASP.NET.</p> <p>view</p> <p>Now, the code is in separate files named Solution.ASPX:</p> <p><% @ Page language = "c #" codebehind = "solution.aspx.cs" autoeventwireup = "false" inherits = "solution"%> <html> <head> <title> solution </ title> </ head> < Body> <form id = "solution" method = "post" runat = "server"> <h3> recording </ h3> Select Recording: <ask: DropDownList ID = "RecordingSelect" runat = "server" / > <Ask: button id = "submit" runat = "server" text = "submit" enableViewState = "false" /> <p /> <asp: datagrid id = "mydataGrid" runat = "server" width = "700" backcolor = "# ccccff" bordercolor = "black" showfooter = "false" cellpadding = "3" cellspacing = "0" font-name = "Verdana" font-size = "8pt" headerstyle-backcolor = "# aaaadd" enableviewstate = "false" /> </ form> </ body> </ html> Most of this code is similar to the code used in the first implementation. Main differences in the first line: <% @ page language = "c #" codebehind = "sol ).aspx.cs" autoeventwireup = "false" inherits = "solution"%> This row tells the ASP.NET environment: code hidden class is implemented The method referenced in this page. Because this page does not have any access to the database, even if the database access code changes, it is not necessary to modify the page. Those familiar with the user interface design can modify this code without any errors in the database access code.</p> <p>Model-Controller</p> <p>The second part of the solution is the following code hidden webpage:</p> <p>Using system.data; using system.data.sqlclient;</p> <p>public class Solution: System.Web.UI.Page {protected System.Web.UI.WebControls.Button submit; protected System.Web.UI.WebControls.DataGrid MyDataGrid; protected System.Web.UI.WebControls.DropDownList recordingSelect; private void Page_Load (object sender, System.EventArgs e) {if (IsPostBack!) {String selectCmd = "select * from Recording"; SqlConnection myConnection = new SqlConnection ( "server = (local); database = recordings; Trusted_Connection = yes"); Sqldataadapter mycommand = new sqldataadapter (selectcmd, myconnection);</p> <p>DataSet DS = New Dataset (); MyCommand.Fill (DS, "Recording");</p> <p>Recordingselect.datasource = DS; RecordingSelect.DataTextField = "title"; RecordingSelect.DataValuefield = "ID"; recordingselect.database ();}}</p> <p>Void Submitbtn_Click (Object Sender, Eventargs E) {string selectcmd = string.format ("Select * from track where recordingid = {0} Order By ID", (String) RecordingSelect.SelectedItem.Value);</p> <p>SqlConnection myconnection = new SqlConnection ("Server = (local); Database = Recordings; trusted_connection = yes"); sqldataadapter mycommand = new sqldataadapter (selectcmd, myconnection);</p> <p>DataSet DS = New Dataset (); MyCommand.Fill (DS, "TRACK");</p> <p>MyDataGrid.datasource = ds; mydatagrid.database ();</p> <p>#Region Web Form Designer Generated Code Override Protected Void OnNit (Eventargs E) {// // Codegen: This call is required for the ASP.NET Web Form Designer. // InitializationComponent (); base.onit (e);} // /// Designer Support for the necessary methods - do not use the code editor to modify the // / this method. /// private void InitializeComponent () {this.submit.Click = new System.EventHandler (this.SubmitBtn_Click); this.Load = new System.EventHandler (this.Page_Load);} #endregion} This code from a single ASP.NET page is moved to a separate file. Several grammar changes are required to link two entities. The name of the member variable defined in the class is the same as the name referenced in the Solution.aspx file. Another aspect of an explicit definition is that how the controller links an event that responds to the operation that must be performed. In this example, the InitializationComponent method links two events. The first is the LOAD event, which is linked to the Page_Load function. The second is the Click event, which triggers the operation of the SubmitBTN_Click function after clicking the "Submit" button.</p> <p>The code hidden function is a good mechanism that separates the view role with the model role and the controller role. This feature may become less suitable when you need to let other pages reuse the code in the code hidden class. From a technical point of view, the code in the reuse code hidden web page is possible, but it is not recommended to do this because this will increase the interaction of all the web pages of the shared code hidden class.</p> <p>Model-View-Controller Reconstruction</p> <p>In order to solve the last problem, you need to further separate the model code to the controller. The view code is the same as the code in the previous implementation.</p> <p>model</p> <p>The following code example describes the model and is only related to the database; it does not contain any code-related code (depending on the ASP.NET code):</p> <p>Using system.collections; using system.data; using system.data.sqlclient;</p> <p>Public class databasegateway {public static dataset getRecordings () {string selectcmd = "select * from recording";</p> <p>SqlConnection myconnection = new SqlConnection ("Server = (local); Database = Recordings; trusted_connection = yes"); sqldataadapter mycommand = new sqldataadapter (selectcmd, myconnection);</p> <p>DataSet DS = New DataSet (); MyCommand.Fill (DS, "Recording"); Return DS;</p> <p>public static DataSet GetTracks (string recordingId) {String selectCmd = String.Format ( "select * from Track where recordingId = {0} order by id", recordingId); SqlConnection myConnection = new SqlConnection ( "server = (local); database = Recordings; trusted_connection = yes "); sqldataadapter mycommand = new sqldataadapter (selectcmd, myconnection);</p> <p>DataSet DS = New Dataset (); MyCommand.Fill (DS, "Track"); Return DS;} Now this is the only file that rely on the database. This class is a good example of the Table Data Gateway mode. Table Data Gateway contains all SQL code for accessing a single table or view: select, insert, update, and delete. Other code calls its method to interact with the database. [Fowler03]</p> <p>Controller</p> <p>This reconstruction uses the code hidden function to rewrite the model code to adapt to the data controls present on the web, and the event forwarded the controller to the specific operation method. Because the model here returns a DataSet object, its work is very simple. The code is the same as the view code, does not rely on the way data from the database.</p> <p>Using system.data; using system.collections; using system.web.ui.webControls;</p> <p>public class Solution: System.Web.UI.Page {protected System.Web.UI.WebControls.Button submit; protected System.Web.UI.WebControls.DataGrid MyDataGrid; protected System.Web.UI.WebControls.DropDownList recordingSelect; private void Page_Load (object sender, System.EventArgs e) {if (IsPostBack!) {DataSet ds = DatabaseGateway.GetRecordings (); recordingSelect.DataSource = ds; recordingSelect.DataTextField = "title"; recordingSelect.DataValueField = "id"; recordingSelect. DataBind ();}}</p> <p>Void Submitbtn_Click (Object Sender, Eventargs E) {DataSet DS = DatabaseGateway.gettracks (String) RecordingSelect.SelectedItem.Value);</p> <p>MyDataGrid.datasource = ds; mydatagrid.database ();} #Region Web Form Designer generated code override protected void OnInit (Eventargs E) {// // Codegen: This call is required for the ASP.NET Web Form Designer. // InitializationComponent (); base.onit (e);} // /// Designer Support for the necessary methods - do not use the code editor to modify the // / this method. /// private vidinitisComponent () {this.submit.click = new system.EventHandler (this.Submitbtn_Click; this.load = new system.eventhandler (this.page_load);</p> <p>} #ENDREGON} test</p> <p>By separating the model with the ASP.NET environment, the test of the model code can be easier. In order to test this code in the ASP.NET environment, the output must be tested. This means that HTML needs to be read and determine if it is correct, which is less lengthy and easy to generate errors. This lengthy process can be avoided by separating the model to run without ASP.NET. The following is an example unit test of the model code in NUnit (http://nunit.org):</p> <p>Using system;</p> <p>Using nunit.framework; using system.data; using system.data.sqlclient;</p> <p>[TestFixTure] Public Class GatewayFixTure {[TEST] public void tracks1234query () {</p> <p>DataSet DS = DatabaseGateway.gettracks ("1234"); assertion.assertequals (10, DS.Tables ["track"]. Rount);}</p> <p>[TEST] public void tracks2345query () {DataSet DS = DatabaseGateway.gettracks ("2345"); assertion.assertequals (3, ds.tables ["track"]. Rount.count);</p> <p>[Test] public void recordings () {dataset ds = DatabaseGateway.getRecordings (); assertion.assertequals (4, ds.tables ["replaording"]. Rount);</p> <p>DataTable Recording = DS.TABLES ["Recording"]; assertion.assertequals (4, Recording.Rows.count);</p> <p>DataRow Firstrow = Recording.Rows [0]; String Title = (String) FIRSTROW ["Title"]; assertion.assertequals ("UP", title.trim ());}} The following advantages and disadvantages:</p> <p>advantage</p> <p>Reduce dependence. Using the ASP.NET page, programmers can implement methods in a web page. As is shown in "Single ASP.NET Page", this is very useful for prototypes and small short-term applications. As the complexity of the page is increasing, or the need to share the code between the page is increasing, each part of the separation code becomes more useful.</p> <p>Reduce the code repeat. The getRecordings and getTracks methods in the DatabaseGateway class can now be used by other webpages. This does not need to be copied to multiple views.</p> <p>Isolate responsibilities and problems. Modify the techniques used by the ASP.NET page different from the techniques used by the written database access code. As mentioned earlier, by separating views and models, professionals in various fields work in parallel.</p> <p>The possibility of optimization. As mentioned earlier, divide the responsibilities into specific classes can improve the likelihood of optimization. In the example previously described, the data is loaded from the database each time a request is issued. Therefore, in some cases, the data can be cached so that the overall performance of the application can be improved. However, if the code is not separated, the cache data will be difficult to implement, or it is impossible.</p> <p>Testability. You can test models outside the ASP.NET environment by separating the model from the view.</p> <p>Disadvantage</p> <p>Added code and complexity. The examples shown above add more files and code, so when all three roles must be changed, the maintenance cost of the code will increase. In some cases, it is easier to make changes in one file compared to multiple files. Therefore, you must trade with the reason and additional cost of the separation code. If it is a small application, it may not be worth a price.</p> <p>Related mode</p> <p>For more information, see the following related modes:</p> <p>Table Data Gateway. This mode is an object of a gateway that acts as a database table. In this mode, all roles in the table will be processed by an example. [Fowler03]</p> <p>Bound Data Control. This mode is a user interface component that is bound to the data source, which can be displayed on the screen or web page.</p> <p>Thank you</p> <p>Fowler, Martin. Patterns of Enterprise Application Architecture. Addison-Wesley, 2003.</p></div><div class="text-center mt-3 text-grey"> 转载请注明原文地址:https://www.9cbs.com/read-117156.html</div><div class="plugin d-flex justify-content-center mt-3"></div><hr><div class="row"><div class="col-lg-12 text-muted mt-2"><i class="icon-tags mr-2"></i><span class="badge border border-secondary mr-2"><h2 class="h6 mb-0 small"><a class="text-secondary" href="tag-2.html">9cbs</a></h2></span></div></div></div></div><div class="card card-postlist border-white shadow"><div class="card-body"><div class="card-title"><div class="d-flex justify-content-between"><div><b>New Post</b>(<span class="posts">0</span>) </div><div></div></div></div><ul class="postlist list-unstyled"> </ul></div></div><div class="d-none threadlist"><input type="checkbox" name="modtid" value="117156" checked /></div></div></div></div></div><footer class="text-muted small bg-dark py-4 mt-3" id="footer"><div class="container"><div class="row"><div class="col">CopyRight © 2020 All Rights Reserved </div><div class="col text-right">Processed: <b>0.045</b>, SQL: <b>9</b></div></div></div></footer><script src="./lang/en-us/lang.js?2.2.0"></script><script src="view/js/jquery.min.js?2.2.0"></script><script src="view/js/popper.min.js?2.2.0"></script><script src="view/js/bootstrap.min.js?2.2.0"></script><script src="view/js/xiuno.js?2.2.0"></script><script src="view/js/bootstrap-plugin.js?2.2.0"></script><script src="view/js/async.min.js?2.2.0"></script><script src="view/js/form.js?2.2.0"></script><script> var debug = DEBUG = 0; var url_rewrite_on = 1; var url_path = './'; var forumarr = {"1":"Tech"}; var fid = 1; var uid = 0; var gid = 0; xn.options.water_image_url = 'view/img/water-small.png'; </script><script src="view/js/wellcms.js?2.2.0"></script><a class="scroll-to-top rounded" href="javascript:void(0);"><i class="icon-angle-up"></i></a><a class="scroll-to-bottom rounded" href="javascript:void(0);" style="display: inline;"><i class="icon-angle-down"></i></a></body></html><script> var forum_url = 'list-1.html'; var safe_token = 'BYZEvXIZ3jmzMZd0ChLL_2BYFcB29K8SSn35v83Qf5DIFrEtWXnmGJYGO1zoiSKErWiBET_2FrFsTw44A092IvD_2BZQ_3D_3D'; var body = $('body'); body.on('submit', '#form', function() { var jthis = $(this); var jsubmit = jthis.find('#submit'); jthis.reset(); jsubmit.button('loading'); var postdata = jthis.serializeObject(); $.xpost(jthis.attr('action'), postdata, function(code, message) { if(code == 0) { location.reload(); } else { $.alert(message); jsubmit.button('reset'); } }); return false; }); function resize_image() { var jmessagelist = $('div.message'); var first_width = jmessagelist.width(); jmessagelist.each(function() { var jdiv = $(this); var maxwidth = jdiv.attr('isfirst') ? first_width : jdiv.width(); var jmessage_width = Math.min(jdiv.width(), maxwidth); jdiv.find('img, embed, iframe, video').each(function() { var jimg = $(this); var img_width = this.org_width; var img_height = this.org_height; if(!img_width) { var img_width = jimg.attr('width'); var img_height = jimg.attr('height'); this.org_width = img_width; this.org_height = img_height; } if(img_width > jmessage_width) { if(this.tagName == 'IMG') { jimg.width(jmessage_width); jimg.css('height', 'auto'); jimg.css('cursor', 'pointer'); jimg.on('click', function() { }); } else { jimg.width(jmessage_width); var height = (img_height / img_width) * jimg.width(); jimg.height(height); } } }); }); } function resize_table() { $('div.message').each(function() { var jdiv = $(this); jdiv.find('table').addClass('table').wrap('<div class="table-responsive"></div>'); }); } $(function() { resize_image(); resize_table(); $(window).on('resize', resize_image); }); var jmessage = $('#message'); jmessage.on('focus', function() {if(jmessage.t) { clearTimeout(jmessage.t); jmessage.t = null; } jmessage.css('height', '6rem'); }); jmessage.on('blur', function() {jmessage.t = setTimeout(function() { jmessage.css('height', '2.5rem');}, 1000); }); $('#nav li[data-active="fid-1"]').addClass('active'); </script>