Application Research of ASP. NET Based on MVP Architecture Design

Source: Internet
Author: User
Tags add days

Microsoft's Microsoft patterns & Practices Team, Web client software factory adopts the mode view presenter + controller mode (mvpc mode ), it enables the Model-View-presenter mode to properly separate the business logic from the presentation layer, efficiently and simply perform unit tests, and more conveniently hide the complexity of the technology, convenient integration with various systems. In the future, I will explain the architecture and Application of Web client software factory separately.

The traditional ASP. NET development design uses postCodeIsolate business logic by page. Although it greatly facilitates development and design, ASP. NET still has the following shortcomings in enterprise-level application development:

The post-code page contains the code of the presentation layer, business logic layer, and data access layer. This is because the post code acts as the event trigger, process control, business rules and performance logic, business logic and data access coordinator among other roles. The post-code page has so many responsibilities that cause a lot of hard-to-Process Code. In enterprise applications, a good design principle is to properly separate layers and keep the content of the Post-code page as clean as possible. Using the Model-View-presenter mode, the content of the post code is very simple and the content of the presentation layer is strictly managed.

Another disadvantage of the Post-code model is that it is difficult to reuse reusable code between post-code pages without the help class/tool class. Obviously, this also provides an appropriate solution, but it often leads to ASP-style classes, not like first-class objects. Through proper design, each class should have clear responsibilities.

Finally, it is very difficult to perform unit tests on the rear code pages because they are too close to the performance Layer. Of course, you can choose tools such as nunitasp, but they are time-consuming and difficult to maintain. Unit testing should be simple and fast.

Various technical means can be used to maintain the separation of the Post-code page. For example, the castle monorail project imitates ruby-on-rails but abandoned the ASP. NET event model. Maverick. Net is a framework that supports ASP. NET event models, but retains the post-code pageProgramController. The ideal solution is to use the ASP. NET event model and keep the post-code page as simple as possible. The Model-View-presenter mode is a third-party framework that does not need to be used to achieve this goal.

Model-View-presenter

The Model-View-Presenter (MVP) mode is an enhancement of the Model-View-controller (MVC) mode. (MVC indicates ASP. net MVC Framework) for the event model, such as ASP.. NET Framework. The primary change for MVP was the implementation of the MVC observer design by presenter. The basic design is the same as that for MVC: Model stores data, view represents model performance, and presenter coordinates communication between the two. In MVP, view receives events and passes them to the presenter. How to deal with these events will be done by the presenter. In-depth comparison between MVC and MVP:

MVC (Model-View-Controller) pattern is a kind of software design pattern which appeared in Smalltalk-80 in 1980s S. Later, it has been widely used, clear separation of attention between controllers. (Model-View-Express) mode is mainly used to isolate the UI, UI logic, business logic, and data.

The difference between the two processes:

In MVC, users' requests first reach the controller, where the Controller obtains data from the model, selects an appropriate view, and presents the processing result to the view. In MVP, the user's request will first arrive at the view, and the view will pass the request to the specific presenter. After the presenter obtains data from the model, it will pass the processing result to the view through the interface.

Simplest example

In this example, the customer wants to display the current time on the page (which is easy to understand from a simple start ). The ASPX page showing the time is "View ". Presenter is responsible for deciding the current time (model) and notifying the view of the model. We started with a unit test.

[Testfixture]

Public class currenttimepresentertests {

[Test]

Public void testinitview (){

Mockcurrenttimeview view = new mockcurrenttimeview ();

Currenttimepresenter presenter = new currenttimepresenter (View );

Presenter. initview ();

Assert. istrue (view. currenttime> datetime. minvalue );

}

Private class mockcurrenttimeview: icurrenttimeview {

Public datetime currenttime {

Set {currenttime = value ;}

// This getter won't be required by icurrenttimeview,

// But it allows us to unit test its value.

Get {return currenttime ;}

}

Private datetime currenttime = datetime. minvalue;

}

}

The unit test code above and the class diagram on the right describe the relationship between various elements of MVP. The first object instance created in the unit test is mockcurrenttimeview. From this unit test, we can see that no ASPX page (View) exists for all the unit tests showing logic ), you need an object that implements the view interface. Therefore, you can create a view Simulation object (mockview) to replace the real view object.

The next line of code creates a presenter object instance and transmits an object that implements the icurrenttimeview interface through its constructor. In this way, the presenter can now operate on the view, as shown in the class diagram, presenter only communicates with the view interface. This allows multiple views that implement the same view interface to be used by the presenter.

Finally, presenter calls the initview () method. This method gets the current time and passes the public attribute icurrenttimeview to the view ), unit Test asserted that the value of currenttime should be greater than its initial value (more assertions can be made if needed ).

Now you have to run the unit test and pass it!

Icurrenttimeview. CS-View Interface

The first step to pass unit test compilation is to create icurrenttimeview. CS: this interface provides a bridge between the presenter and the view. In this example, the View Interface needs to expose a model data so that the persenter can pass the model (current time) to the view.

Public interface icurrenttimeview {

Datetime currenttime {set ;}

}

Because only the model data needs to be displayed, only a set of cuttenttime is required in the View Interface, but a get is set to obtain the currenttime of the view in unit test, it can also be added to mockcurrenttimeview instead of defined in the interface, getter/setter does not need to be defined for the interface properties exposed in the View Interface (this technology is used in the unit test above ).

Currenttimepresenter. CS-the presenter
The presenter processes the logic between models and passes the model to the view. To compile a unit test, the presenter implementation code is as follows:

Public class currenttimepresenter {

Public currenttimepresenter (icurrenttimeview view ){

If (view = NULL) throw new argumentnullexception ("view may not be null ");

This. view = view;

}

Public void initview (){

View. currenttime = datetime. now;

}

Private icurrenttimeview view;

}

After the above Code is completed, the unit test, mock view, presenter, and view. unit test can now be compiled and passed successfully. The next step is to create An ASPX page to act as a real view.

Note the check of argumentnullexception exceptions. This technique is called design by contract. Doing the necessary check in the code can greatly reduce the number of bugs. About Design by contract

Showmethetime. aspx-the view

The following content is required for this page:

1. The ASPX page needs to provide a method to display the current time, and use a label control to display the time

2. The post code must implement the interface icurrenttimeview.

3. The post-code must create a presenter object and pass it to its constructor.

4. After creating a persenter object, you need to call initview ()

ASPX page:

<Asp: Label id = "lblcurrenttime" runat = "server"/>

...

<

Aspx post code page:

Public partial class showmethetime: Page, icurrenttimeview

{

Protected void page_load (Object sender, eventargs e ){

Currenttimepresenter presenter = new currenttimepresenter (this );

Presenter. initview ();

}

Public datetime currenttime {

Set {lblcurrenttime. Text = value. tostring ();}

}

}

All in all, yes, but there is a lot of content. The previous example shows that such a small function requires so much work. From creating An ASPX page to a presenter class, a view interface, and a unit test class ......, The benefit we get is the unit test of the presenter, that is, it is easy to perform unit tests on the Post-code page. This is the simplest example, just like writing "Hello World. When building enterprise-level applications, it will reflect the benefits of the MVP model. The following topic describes how to use the MVP mode in enterprise-level ASP. NET applications.

Use MVP in enterprise ASP. NET Applications

1. Use user controls to encapsulate views: this topic discusses user controls as views in MVP

2. MVP event handling: this topic discusses how to pass events to presenter, ispostback, and send messages to view together with page verification.

3. Page redirection for MVPs and pagemethods: this topic discusses how to use user controls as views to process page redirection using pagemethods.

4. MVP presentation Security Control: this topic discusses how to display/hide segments in a view based on basic security restrictions.

5. MVP application architecture (advanced): This is the focus. This topic displays an MVP application using nhib.pdf as the data access layer.

Encapsulate views using user controls

In the above example, the ASPX page acts as a view, and there is only one simple purpose to view the ASPX page-display the current time. However, in a representative application, a page usually contains one or more functional sections, which may be webpart, user control, and so on. In enterprise applications, it is very important to keep functional separation and easily move from one place to another. MVPs are used to encapsulate views. aspx is used as "view initializers" and page redirection. To expand the example above, you only need to modify the implementation of the aspx page. This is another benefit of MVP. Many changes can be restricted to the view layer rather than the presenter and model.

Showmethetime. aspx Redux-the view initializer

In this new method, showmethetime. aspx is responsible for the following:

1. the user control that implements the icurrenttimeview interface must be declared in Aspx.

2. The post-code must create a presenter object and pass the user control to its constructor.

3. After creating a persenter object, you need to call initview ()

ASPX page :...

<% @ Register tagprefix = "mvpproject" tagname = "currenttimeview" src = "./views/currenttimeview. ascx" %>

<Mvpproject: currenttimeview id = "currenttimeview" runat = "server"/>

...

The aspx post code page:

Public partial class showmethetime: Page // no longer implements icurrenttimeview

{

Protected void page_load (Object sender, eventargs e ){

Initcurrenttimeview ();

}

Private void initcurrenttimeview (){

Currenttimepresenter presenter = new currenttimepresenter (currenttimeview );

Presenter. initview ();

}

}

Currenttimeview. ascx-user control as view

The user control now acts as a view, depending entirely on what we expect the view to be.

The ascx page :...

<Asp: Label id = "lblcurrenttime" runat = "server"/>

...

Ascx post code page:

Public partial class views_currenttimeview: usercontrol, icurrenttimeview

{

Public datetime currenttime {

Set {lblcurrenttime. Text = value. tostring ();}

}

}

Advantages and disadvantages of using a user control as a view

The main disadvantage of using a user control as an MVP view is the method of adding another element. Currently, MVP elements are composed of the following elements: unit test, presenter, View Interface, view implementation (the user control) and the view initializer (the ASPX page ). the advantages of using a user control as a view are as follows:

1. It is very easy for a view to move from one page to another. This is often happening in large applications.

2. view can be reused between different pages without the need to copy code

3. view can be initialized on different aspx pages. For example, a user control used to display the project list. Users may view and filter data in the report area of the site. In another area of the site, users can only view part of the data and cannot use filters. In terms of implementation, the same view can be passed to the same presenter, but different aspx pages can call different methods of presenter to initialize the view.

L4. Adding other views to the ASPX page does not require additional code. You only need to add the user control to the page, then, you can connect the post code with Its presenter. The user control is not used to manage different functional sections on the same page, and the maintenance becomes difficult soon.

MVP event handling

The preceding example essentially describes one-way communication between a presenter and its view. The presenter communicates with the model and passes it to the view. In most cases, a presenter is required to handle the event. In addition, some events depend on whether the verification on the page passes or ispostback. For example, data binding cannot be triggered during ispostback.

Declaration: page. ispostback and page. isvalid are unique to the Web. The presenter layer discussed below is valid only in the Web environment. However, as long as you make small changes, it can also work well in webform, winform and mobile applications. In any case, their theoretical basis is the same.

Simple event processing sequence diagram

In the above example, the user may add a few days to the current time, and then display the Update Time in the view. Assume that the user inputs a valid number, the time displayed in the view should be equal to the current time plus the number of days added. When ispostback is not used, the view displays the current time of the event. When ispostback is used, the presenter should respond to the event. The following sequence diagram shows what happened after the user's initial request (in the above section) and the user clicks the "add days" button ..

A) create a user control

This step only represents the user control declared on the ASPX page. The user control is created during page initialization. The figure shows the user control that implements the icurrenttimeview interface. In the page_load event of the post code on the ASPX page, presenter creates an instance and passes the user control as a parameter to the presenter through the constructor, the content of all the descriptions is the same as that of "using user controls to encapsulate views.

B) add presenter to view

To enable the event to be passed from the view (User Control) to the presenter. View must contain a reference to the currenttimepresenter object. For this purpose, view initializer and showmethetime. aspx pass the presnter to the view. This will not cause dependencies between the presenter and the view. The presenter depends on the View Interface and the view depends on the processing of events by the presenter. Let's see how they work in our code.

Icurrenttimeview. CS-The View Interface

Public interface icurrenttimeview {

Datetime currenttime {set ;}

String message {set ;}

Void attachpresenter (currenttimepresenter presenter );

}

<A name = eventhandlingpresenter> currenttimepresenter. CS-

Presenter </a>

Public currenttimepresenter (icurrenttimeview view ){

If (view = NULL) throw new argumentnullexception ("view may not be null ");

This. view = view;

}

Public void initview (bool ispostback ){

If (! Ispostback ){

View. currenttime = datetime. now;

}

}

Public void adddays (string daysunparsed, bool ispagevalid ){

If (ispagevalid ){

View. currenttime = datetime. Now. adddays (double. parse (daysunparsed ));

}

Else {

View. Message = "Bad inputs... no updated date for you! ";

}

}

Private icurrenttimeview view;

}

Currenttimeview. ascx-the view

The ascx page :..

<Asp: Label id = "lblmessage" runat = "server"/> <br/>

<Asp: Label id = "lblcurrenttime" runat = "server"/> <br/>

<Br/>

<Asp: textbox id = "txtnumberofdays" runat = "server"/>

<Asp: requiredfieldvalidator controltovalidate = "txtnumberofdays" runat = "server"

Errormessage = "Number of days is required" validationgroup = "adddays"/>

<Asp: comparevalidator controltovalidate = "txtnumberofdays" runat = "server"

Operator = "datatypecheck" type = "double" validationgroup = "adddays"

Errormessage = "Number of days must be numeric"/> <br/>

<Br/>

<Asp: button id = "btnadddays" text = "add days" runat = "server"

Onclick = "btnadddays_onclick" validationgroup = "adddays"/>

...

The ascx code-behind page:

Public partial class views_currenttimeview: usercontrol, icurrenttimeview {

Public void attachpresenter (currenttimepresenter presenter ){

If (presenter = NULL) throw new argumentnullexception ("presenter may not be null ");

This. Presenter = presenter;

}

Public String message {

Set {lblmessage. Text = value ;}

}

Public datetime currenttime {

Set {lblcurrenttime. Text = value. tostring ();}

}

Protected void btnadddays_onclick (Object sender, eventargs e ){

If (presenter = NULL) throw new fieldaccessexception ("presenter has not yet been initialized ");

Presenter. adddays (txtnumberofdays. Text, page. isvalid );

}

Private currenttimepresenter presenter;

}

Showmethetime. aspx-the view initializer

The ASPX page :...

<% @ Register tagprefix = "mvpproject" tagname = "currenttimeview" src = "./views/currenttimeview. ascx" %>

<Mvpproject: currenttimeview id = "currenttimeview" runat = "server"/>

...

The aspx code-behind page:

Public partial class showmethetime: Page // no longer implements icurrenttimeview

{
Protected void page_load (Object sender, eventargs e ){

Initcurrenttimeview ();

}

Private void initcurrenttimeview (){

Currenttimepresenter presenter = new currenttimepresenter (currenttimeview );

Currenttimeview. attachpresenter (presenter );

Presenter. initview (page. ispostback );

}

}

C) presenter initview

If ispostback is not required, presenter only displays the current time. Presenter needs to know what to do during ispostback, which is not determined by the post code of Aspx. In the above code, you can see that there is no ispostback processing in the post code of Aspx. It simply transmits the value to the presenter, And the presenter determines the action to perform.

This may cause a problem: "What will happen if post-back is triggered by another user control ". In this example, the current time is saved in the viewstate of the label control and displayed on the label control again. These are dependent on the customer's needs. In general, this is a good problem with presenter-the impact of post-back caused by another user control on this user control. Even if you are not using MVP, it is a good problem.

Download instance source code:

Mvp.sampleapp.rar (624.74 KB)

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.