Implement Model-View-Controller in ASP.NET

xiaoxiao2021-03-06  57

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></p> <p><script language = "c #" runat = "server"></p> <p>Void Page_Load (Object Sender, System.EventArgs E)</p> <p>{</p> <p>String selectcmd = "select * from recording";</p> <p>SqlConnection myconnection =</p> <p>NEW SQLCONNECTION</p> <p>"Server = (local); database = recordings; trusted_connection = yes");</p> <p>Sqldataadapter mycommand = new sqldataadapter (selectcmd,</p> <p>MyConnection);</p> <p>DataSet DS = New DataSet ();</p> <p>MyCommand.Fill (DS, "Recording");</p> <p>Recordingselect.datasource = ds;</p> <p>Recordingselect.DataTextField = "Title";</p> <p>Recordingselect.datavaluefield = "id";</p> <p>Recordingselect.database ();</p> <p>}</p> <p>Void Submitbtn_Click (Object Sender, Eventargs E)</p> <p>{</p> <p>String selectcmd =</p> <p>String.Format</p> <p>"SELECT * from track where recordingId = {0} Order by id",</p> <p>(String) RecordingSelect.SelectedItem.Value;</p> <p>SqlConnection myconnection =</p> <p>NEW SQLCONNECTION</p> <p>"Server = (local); database = recordings; trusted_connection = yes");</p> <p>Sqldataadapter mycommand = new sqldataadapter (selectcmd,</p> <p>MyConnection);</p> <p>DataSet DS = New DataSet ();</p> <p>MyCommand.Fill (DS, "Track"); MyDataGrid.DataSource = DS;</p> <p>MyDataGrid.databind ();</p> <p>}</p> <p></ script></p> <p></ hEAD></p> <p><body></p> <p><form id = "start" method = "post" runat = "server"></p> <p><h3> recording </ h3></p> <p>Select recording: <br /></p> <p><ask: DropDownList ID = "RecordingSelect" runat = "server" /></p> <p><ask: button runat = "server" text = "Submit" onclick = "submitbtn_click" /></p> <p><p /></p> <p><ask: DataGrid ID = "MyDataGrid" runat = "server" width = "700"</p> <p>Backcolor = "# ccccff" bordercolor = "black" showfooter = "false"</p> <p>Cellpadding = "3" Cellspacing = "0" font-name = "verdana"</p> <p>Font-size = "8pt" Headerstyle-BackColor = "# aaaaadd"</p> <p>EnableViewState = "false" /></p> <p></ form></p> <p></ body></p> <p></ html></p> <p>This file implements all three roles in this mode, but does 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 called.</p> <p>This page is very simple and is independent. This implementation is very useful, which is a very good starting point when the application is small and not changed frequently. However, if one or more of the following occurs during the development process, you should consider changing 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. In order to solve some such problems, the implementation of ASP.NET introduces code hidden features. The code hidden reconstruction uses the code hidden feature of the Microsoft Visual Studio® .NET development system, it can easily divide the representation (view) code from the 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. The following is the same example, but this time you use the code hidden function to implement ASP.NET. View now, indicating that the code is in a separate file named Solution.aspx: <% @ page language = "c #" codebehind = "solction.aspx.cs"</p> <p>Autoeventwireup = "false" inherits = "solution"%></p> <p><html></p> <p><HEAD></p> <p><Title> Solution </ Title></p> <p></ hEAD></p> <p><body></p> <p><form id = "solution" method = "post" runat = "server"></p> <p><h3> recording </ h3></p> <p>Select recording: <br/></p> <p><ask: DropDownList ID = "RecordingSelect" runat = "server" /></p> <p><ask: button id = "submit" runat = "server" text = "submit"</p> <p>EnableViewState = "false" /></p> <p><p /></p> <p><ask: DataGrid ID = "MyDataGrid" runat = "server" width = "700"</p> <p>Backcolor = "# ccccff" bordercolor = "black" showfooter = "false"</p> <p>Cellpadding = "3" cellspacing = "0" font-name = "verdana" font-size = "8pt"</p> <p>Headerstyle-backcolor = "# aaaAadd" enableViewState = "false" /> </ form></p> <p></ body></p> <p></ html></p> <p>Most of this code is similar to the code used in the first implementation. The main difference is in the first line:</p> <p><% @ Page language = "c #" codebehind = "soliion.aspx.cs"</p> <p>Autoeventwireup = "false" inherits = "solution"%></p> <p>The row tells the ASP.NET environment: The code hidden class implements 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. The second part of Model-Controller This is the following code hidden webpage:</p> <p>Using system;</p> <p>Using system.data;</p> <p>Using system.data.sqlclient;</p> <p>Public Class Solution: System.Web.ui.page</p> <p>{</p> <p>Protected system.Web.ui.WebControls.button submit;</p> <p>Protected system.Web.ui.WebControls.DataGrid mydatagrid;</p> <p>Protected system.Web.ui.webcontrols.dropdownlist recordingselect;</p> <p>Private Void Page_Load (Object Sender, System.EventArgs E)</p> <p>{</p> <p>IF (! ispostback)</p> <p>{</p> <p>String selectcmd = "select * from recording";</p> <p>SqlConnection myconnection =</p> <p>NEW SQLCONNECTION</p> <p>"Server = (local); database = recordings; trusted_connection = yes");</p> <p>Sqldataadapter mycommand = new sqldataadapter (selectcmd, myconnection);</p> <p>DataSet DS = New DataSet ();</p> <p>MyCommand.Fill (DS, "Recording");</p> <p>Recordingselect.datasource = ds;</p> <p>Recordingselect.DataTextField = "Title";</p> <p>Recordingselect.datavaluefield = "id";</p> <p>Recordingselect.database ();</p> <p>}</p> <p>}</p> <p>Void Submitbtn_Click (Object Sender, Eventargs E)</p> <p>{</p> <p>String selectcmd =</p> <p>String.Format</p> <p>"SELECT * from track where recordingId = {0} Order by id",</p> <p>(String) RecordingSelect.SelectedItem.Value;</p> <p>SqlConnection myconnection =</p> <p>NEW SQLCONNECTION</p> <p>"Server = (local); database = Recordings; trusted_connection = yes"); sqldataadapter mycommand = new sqldataadapter (selectcmd, myconnection);</p> <p>DataSet DS = New DataSet ();</p> <p>MyCommand.fill (DS, "Track");</p> <p>MyDataGrid.dataSource = DS;</p> <p>MyDataGrid.databind ();</p> <p>}</p> <p>#Region Web Form Designer Generated Code</p> <p>Override protected void oninit (Eventargs E)</p> <p>{</p> <p>//</p> <p>// Codegen: This call is necessary for the ASP.NET Web Form Designer.</p> <p>//</p> <p>InitializationComponent ();</p> <p>Base.onit (E);</p> <p>}</p> <p>///</p> <p>/// Designer Support for the method necessary - Do not use the code editor to modify</p> <p>/// This method is content.</p> <p>///</p> <p>Private vidinitiRizeComponent ()</p> <p>{</p> <p>This.Submit.Click = new system.eventhandler (this.submitbtn_click);</p> <p>This.Load = New System.EventHandler (this.page_load);</p> <p>}</p> <p>#ndregion</p> <p>}</p> <p>This code has been moved from a single ASP.NET page 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. 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. Model-View-Controller Refactoring To resolve 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. The code example below 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;</p> <p>Using system.collections;</p> <p>Using system.data;</p> <p>Using system.data.sqlclient;</p> <p>Public Class DatabaseGateway</p> <p>{</p> <p>Public Static DataSet GetRecordings ()</p> <p>{</p> <p>String selectcmd = "select * from recording";</p> <p>SqlConnection myconnection =</p> <p>NEW SQLCONNECTION</p> <p>"Server = (local); database = recordings; trusted_connection = yes");</p> <p>SqlDataAdapter mycommand = new sqldataadapter (selectcmd, myconnection); DataSet DS = New Dataset ();</p> <p>MyCommand.Fill (DS, "Recording");</p> <p>Return DS;</p> <p>}</p> <p>Public Static DataSet GetTracks (String RecordingID)</p> <p>{</p> <p>String selectcmd =</p> <p>String.Format</p> <p>"SELECT * from track where recordingId = {0} Order by id",</p> <p>RecordingID);</p> <p>SqlConnection myconnection =</p> <p>NEW SQLCONNECTION</p> <p>"Server = (local); database = recordings; trusted_connection = yes");</p> <p>Sqldataadapter mycommand = new sqldataadapter (selectcmd, myconnection);</p> <p>DataSet DS = New DataSet ();</p> <p>MyCommand.fill (DS, "Track");</p> <p>Return DS;</p> <p>}</p> <p>This is the only file that relies 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] Controller This reconstruction uses code hidden features to rewrite the model code to adapt to the data controls present on the page, and map the event forwarded the controller to the specific method of operation. 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;</p> <p>Using system.data;</p> <p>Using system.collections;</p> <p>Using system.Web.ui.webcontrols;</p> <p>Public Class Solution: System.Web.ui.page</p> <p>{</p> <p>Protected system.Web.ui.WebControls.button submit;</p> <p>Protected system.Web.ui.WebControls.DataGrid mydatagrid;</p> <p>Protected system.Web.ui.webcontrols.dropdownlist recordingselect;</p> <p>Private Void Page_Load (Object Sender, System.EventArgs E)</p> <p>{</p> <p>IF (! ispostback)</p> <p>{</p> <p>DataSet DS = DatabaseGateway.getRecordings ();</p> <p>Recordingselect.datasource = ds;</p> <p>Recordingselect.DataTextField = "Title";</p> <p>Recordingselect.datavaluefield = "id";</p> <p>Recordingselect.database ();</p> <p>}</p> <p>}</p> <p>Void Submitbtn_Click (Object Sender, Eventargs E)</p> <p>{</p> <p>DataSet DS =</p> <p>Databasegateway.gettracks</p> <p>(String) RecordingSelect.SelectedItem.Value;</p> <p>MyDataGrid.dataSource = DS; mydatagrid.databind ();</p> <p>}</p> <p>#Region Web Form Designer Generated Code</p> <p>Override protected void oninit (Eventargs E)</p> <p>{</p> <p>//</p> <p>// Codegen: This call is necessary for the ASP.NET Web Form Designer.</p> <p>//</p> <p>InitializationComponent ();</p> <p>Base.onit (E);</p> <p>}</p> <p>///</p> <p>/// Designer Support for the method necessary - Do not use the code editor to modify</p> <p>/// This method is content.</p> <p>///</p> <p>Private vidinitiRizeComponent ()</p> <p>{</p> <p>This.Submit.Click = new system.eventhandler (this.submitbtn_click);</p> <p>This.Load = New System.EventHandler (this.page_load);</p> <p>}</p> <p>#ndregion</p> <p>}</p> <p>The test can make the model code test easier by separating the model with the ASP.NET environment. 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, and can be avoided and test code separately. 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;</p> <p>Using system.collections;</p> <p>Using system.data;</p> <p>Using system.data.sqlclient;</p> <p>[TestFixTure]</p> <p>Public Class GatewayFixTure</p> <p>{</p> <p>[TEST]</p> <p>Public void tracks1234Query ()</p> <p>{</p> <p>DataSet DS = DatabaseGateway.getTracks ("1234");</p> <p>Assertion.assertequals (10, DS.Tables ["track"]. Rows.count);</p> <p>}</p> <p>[TEST]</p> <p>Public void TRACKS2345QUERY ()</p> <p>{</p> <p>DataSet DS = DatabaseGateway.getTracks ("2345");</p> <p>Assertion.assertequals (3, DS.Tables ["track"]. Rows.count);</p> <p>}</p> <p>[TEST]</p> <p>Public void recordings ()</p> <p>{</p> <p>DataSet DS = DatabaseGateway.getRecordings ();</p> <p>Assertion.assertequals (4, DS.Tables ["Recording"]. Rows.count);</p> <p>DataTable Recording = DS.TABLES ["Recording"];</p> <p>Ask.ASSERTEQUALS (4, Recording.Rows.count);</p> <p>DataRow Firstrow = Recording.Rows [0];</p> <p>String Title = (String) FIRSTROW ["Title"];</p> <p>Ask.ASSERTEQUALS ("UP", Title.trim ());</p> <p>}</p> <p>}</p></div><div class="text-center mt-3 text-grey"> 转载请注明原文地址:https://www.9cbs.com/read-119545.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="119545" 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.042</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 = 'J_2Bk_2Bfx56Kpe7UU66jSMS6qrHYfoc2wWJsSvRjh18X6fc4gLjEuKYHJSbTvyt76S6qJ_2BKWHtYxJxUDvM6YZmK6Q_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>