Thinking of application Architecture of ASP.--unity application and Layer three code

Source: Internet
Author: User
Tags syslog try catch

I'm going to do a project recently and talk to a foreign architect. The other person mentioned that he was going to replace the old technology with ASP. NET MVC, jquery, Unity and other technologies: such as ASP. NET Web Form. He asked me to help him think of something about architecture. All along, there are some ideas about the architecture of ASP. Just take this opportunity to write it out. Senior people may already know, it is to review it. Welcome to express your views. pointed out insufficient.

Application of Unity

Unity has been out for years. In the early years of the 1.2 version will be able to achieve the functions described here. The latest stable version is now 2.1. The 3.0 being developed may bring us more powerful features. Here is how to use unity to implement AOP, reducing the degree of coupling of code. High-level code relies on an abstract interface, and the implementation of the code is done by the concrete implementation class in the Unity container. So the Unity container is responsible for creating an instance of a concrete implementation class that maps it to an abstract interface. This is done to reduce the coupling of the code. In addition, there are many common parts in our application, such as logging, exception processing, database transaction processing, etc. can be implemented by AOP. Imagine every business method has to write calls logging, exception processing code, we developers will be tired. By implementing AOP through unity, these common code is extracted from every business method, making our code look fresher.

Using unity to reduce the coupling of code

In order to reduce the coupling of the code, the high-level code needs to rely on an abstract interface. The concrete implementation class then implements this abstract interface, registering the abstract interface to the implementation class mapping in the Unity container. That is, an abstract interface is specified to map to a specific implementation class.

The specific implementation code is as follows:

      <register type= "Businesslogic.iblluserform, Businesslogic" mapto= "Businesslogic.blluserform, BusinessLogic" >      </register>      <register type= "Businesslogic.ibllusermenu, businesslogic" mapto= " Businesslogic.bllusermenu, businesslogic ">      </register>

Here "Businesslogic" is the namespace. Iblluserform and Ibllusermenu are abstract interfaces. Its namespace is businesslogic. You can find that the implementation of the class Blluserform and Bllusermenu is also in the Businesslogic namespace, this is not important, abstract interfaces and concrete implementation classes can be in the same namespace can also be different namespaces. The key is that the mapping of the abstract class to the concrete implementation class is managed through the Unity container. Register this way to the Unity container to indicate this abstract interface and the specific implementation class mapping. Such mappings can be changed when needed, such as in the future due to business requirements of new situations, need a new concrete implementation class called Blluserform_blabla. So you can use Blluserform_blabla instead of the original Blluserform, You just need to change the configuration file. The original code does not even have to be recompiled. Think of unity, then the high-level code must rely on the implementation class, because, even if there is an abstract interface, the abstract interface itself is unable to create the instance directly. High-level code must use the new operator to create an instance of a concrete implementation class, which produces a direct dependency on the specific implementation class. The coupling of the code becomes higher. Unity is a container, a factory of manufacturing objects, how many objects you need, and how many objects it makes. It can also manage the mapping between these abstract interfaces and the concrete implementation classes. This is what people often say about the benefits of being dependent on abstraction.

In reality, there may be abstract interface Iblluserform, and so also have to change the situation, the appearance of this situation is due to ooa/ood do not in place, not correctly found abstract. Have to revisit the analysis and design that was done.

Implement AOP with unity and keep your code fresh

Business methods to access the database, do business processing will inevitably encounter unforeseen problems, when there is a problem, do not want to throw this problem information directly to the user, but want to write the detailed technical information of the problem to log. This is a common practice. Every business method writes a try catch and then calls the class that does logging to write the log. This will cause a lot of duplicate code. Fortunately, unity can help us save these repetitive codes. See how to do it:

This is code 1, implementing the Microsoft.Practices.Unity.InterceptionExtension.ICallHandler interface. Implement the Invoke method. "var retvalue = GetNext () (input, getNext);" is to invoke the intercepted method. if (RetValue. Exception! = null) to Judge RetValue. Exception is to determine if the intercepted method has exception. If any, write the Exception log.

Using system;using system.data;using system.data.common;using system.collections.generic;using Microsoft.practices.unity.interceptionextension;using dataaccesscommon;using CommonUtil;namespace BusinessLogic{ Public    class Mydbhandler:icallhandler    {        private int iorder = 0;        Public Imethodreturn Invoke (imethodinvocation input, getnexthandlerdelegate getNext)        {            var retvalue = GetNext ( ) (input, getNext); Call the Intercepting method            if (RetValue. Exception! = null)            {                syslog.getinstance (). LogError (RetValue. Exception);            }            return retvalue;        }        public int Order        {            get            {                return iorder;            }            Set            {                iorder = value;            }        }}}    

This is code 2, which is a handler attribute, this attribute is used to mark whether unity is to be intercepted. All abstract interfaces that need to be intercepted are added with this attribute. The interception policy in the following code 4 configuration file will see if there is a attribute on the abstract interface, and some will intercept.

Using system;using system.collections.generic;using microsoft.practices.unity;using Microsoft.practices.unity.interceptionextension;namespace businesslogic{Public    class Mydbhandlerattribute: Handlerattribute    {public        override Icallhandler Createhandler (Iunitycontainer container)        {            return New Mydbhandler ();}}}    

Code 3, which is a very simple helper class, is used to help specify the type of custom attribute in the block configuration of code 4.

Using system;using system.collections.generic;using microsoft.practices.unity;using Microsoft.practices.unity.interceptionextension;namespace businesslogic{Public    class Gettypeconverter: System.ComponentModel.TypeConverter    {Public        override object ConvertFrom ( System.ComponentModel.ITypeDescriptorContext context,            System.Globalization.CultureInfo culture,            object Value)        {            return Type.GetType (value. ToString ());}}}    

Code 4, which is a blocking configuration with key points on Callhandler and Matchingrule. Callhandler Specifies that the Businesslogic.mydbhandler type be used for interception processing. Mydbhandler is already defined in code 1 (see above). Matchingrule, here is the Customattributematchingrule, the custom attribute as the interception condition. Customattributematchingrule requires two constructor arguments, one that is type, and one that uses the inherited type. When the type is specified, a string is used: "Businesslogic.mydbhandlerattribute, Businesslogic", so TypeConverter is required to convert it to type.

      <interception>        <policy name= "MyPolicy" >          <callhandler name= "MyHandler1" type= " Businesslogic.mydbhandler, businesslogic "></callHandler>          <matchingrule name=" Myrule "type=" Customattributematchingrule ">            <constructor>              <param name=" AttributeType "type=" System.Type, mscorlib ">                <value value=" Businesslogic.mydbhandlerattribute, businesslogic "typeconverter=" Businesslogic.gettypeconverter, businesslogic "/>              </param>              <param name=" inherited "type=" bool " >                <value value= "true"/>              </param>            </constructor>          </matchingRule>        </policy>      </interception>

Code 5, corresponding to the type registration also added interceptors and policyinjection settings. Interfaceinterceptor is used here. As follows:

      <register type= "Businesslogic.iblluserform, Businesslogic" mapto= "Businesslogic.blluserform, BusinessLogic" >        <interceptor name= "Myinterceptor" type= "Interfaceinterceptor" isdefaultfortype= "true"/>        < Policyinjection/>      </register>      <register type= "Businesslogic.ibllusermenu, Businesslogic" Mapto= "Businesslogic.bllusermenu, businesslogic" >        <interceptor name= "Myinterceptor" type= " Interfaceinterceptor "isdefaultfortype=" true "/>        <policyinjection/>      </register>

About database transactions, if your database task is relatively simple (such as crud only), the database transaction size is relatively small, Can be used System.Transactions.TransactionScope, then the following section of the code to implement the ultra-simple AOP method of transaction management:

Code 6, which is a fragment of replacement code 1:

                using (TransactionScope ts = new TransactionScope ())                {                    var retvalue = GetNext (). Invoke (input, getNext);                    if (RetValue. Exception! = null)                    {                        syslog.getinstance (). LogError (RetValue. Exception);                    }                    else                    {                        ts.complete ();                    }                    Return RetValue                }

var retvalue = GetNext (). Invoke (input, getNext); This is called the method of interception. That's our business approach. We can do some logging work before intercept, that is, before this statement, and we can do some logging work after this statement. Subject to specific requirements. With the exception processing, and the corresponding logging, there is the processing of database transactions. Then the class of business logic and the corresponding class of database access becomes relatively simple. The original need to explicitly create the transaction object, now no need, now the business method by default is open transaction management. All database operations in business methods are considered to be the same database transaction. Commit the database transaction automatically after the business method is finished.

Three-layer code

Code 7 abstracts The Code of the interface, which refers to the custom attribute "Mydbhandler", which brings the AOP way of exception, logging, and transaction processing.

Using System;namespace businesslogic{[Mydbhandler] public interface Ibllusermenu {int Addusermenu (Dataen Tity.        Usermenu Usermenu);        int Deleteusermenu (Dataentity.usermenu usermenu);        Dataentity.usermenu Findausermenu (Dataentity.usermenu usermenu);        System.collections.generic.list<dataentity.usermenu> Getallusermenu ();        int Selectcountusermenu ();        int Selectcountwhereclauseusermenu (Dataentity.usermenu usermenu);        System.collections.generic.list<dataentity.usermenu> Selectgroupbyprimarykeyusermenu (); System.collections.generic.list<dataentity.usermenu> Selectmenusbyapplicationid (DataEntity.UserMenu        Usermenu);        System.collections.generic.list<dataentity.usermenu> Selectorderbyprimarykeyusermenu ();        System.collections.generic.list<dataentity.usermenu> Selecttopusermenu ();        int Updateusermenu (Dataentity.usermenu usermenu);        Object CONNECTION {get; set;} Dataentity.usermeNu usermenu {get; set;}    System.collections.generic.list<dataentity.usermenu> usermenu_list {get; set;} }}

Code 8 Business Class and its methods, after AOP processing, each method has exception processing, logging, and transaction control.

Using system;using system.collections.generic;using system.data;using dataentity;using DataAccess;using         Dataaccesscommon;using Commonutil;namespace businesslogic{Internal class BLLUserMenu:BusinessLogic.IBLLUserMenu {        Private readonly Dataaccess.dalusermenu dal = new Dataaccess.dalusermenu ();        Private object conn = null;        Private Usermenu Usermenu;        Private list<usermenu> Usermenus;            Public object CONNECTION {get {return conn;            } SET {conn = value;            }} public Usermenu Usermenu {get {return usermenu;            } set {Usermenu = value; }} public list<usermenu> Usermenu_list {get {RE            Turn Usermenus;             } set {   Usermenus = value;            }} #region business logic method public int Deleteusermenu (Usermenu usermenu) { Return DAL.        Deleteusermenu (Conn,usermenu); } public int Updateusermenu (Usermenu usermenu) {return DAL.        Updateusermenu (Conn,usermenu); } public int Addusermenu (Usermenu usermenu) {return DAL.        Addusermenu (Conn,usermenu); } public list<usermenu> Getallusermenu () {return DAL.        GETALLUSERMENU (conn); Public Usermenu Findausermenu (Usermenu usermenu) {return DAL.        Findausermenu (Conn,usermenu); } public System.Int32 Selectcountusermenu () {return DAL.        SELECTCOUNTUSERMENU (conn); Public System.Int32 Selectcountwhereclauseusermenu (Usermenu usermenu) {return DAL.        Selectcountwhereclauseusermenu (Conn,usermenu); } public List<usermeNu> Selecttopusermenu () {return DAL.        SELECTTOPUSERMENU (conn); } public list<usermenu> Selectorderbyprimarykeyusermenu () {return DAL.        SELECTORDERBYPRIMARYKEYUSERMENU (conn); } public list<usermenu> Selectgroupbyprimarykeyusermenu () {return DAL.        SELECTGROUPBYPRIMARYKEYUSERMENU (conn); Public list<usermenu> Selectmenusbyapplicationid (Usermenu usermenu) {return DAL.        Selectmenusbyapplicationid (conn, usermenu); } #endregion}}

Code 9 has several business methods for database operations, the above business class and its methods are relatively simple, so a business method only one database operation. In many cases there are multiple, even more complex. As in the following example:

        public bool Moveupitem (Usermenuitem usermenuitem) {usermenuitem = dal.            Findausermenuitem (conn, usermenuitem); Usermenuitem Previousmenuitem = dal.            Selectpreviousmenuitem (conn, usermenuitem); int itempordinal = Usermenuitem.            ORDINAL; Usermenuitem.            ORDINAL = previousmenuitem.ordinal;            Previousmenuitem.ordinal = itempordinal; Dal.            Updateusermenuitem (conn, usermenuitem); Dal.            Updateusermenuitem (conn, previousmenuitem);        return true; } public bool Movedownitem (Usermenuitem usermenuitem) {usermenuitem = dal.            Findausermenuitem (conn, usermenuitem); Usermenuitem Nextmenuitem = dal.            Selectnextmenuitem (conn, usermenuitem); int itempordinal = Usermenuitem.            ORDINAL; Usermenuitem.            ORDINAL = nextmenuitem.ordinal;            Nextmenuitem.ordinal = itempordinal; Dal.            Updateusermenuitem (conn, usermenuitem); Dal. UpdateusermenuitEM (conn, nextmenuitem);        return true; }

Code 10, the code for data access, is basically this pattern, constructs parameters, crud SQL statements, and then invokes the DB helper to execute. The method return types for these data accesses are the following: int, single business entity, List of business entities, BOOL. An int usually represents the number of records affected, or the value of an orthopedic field, and a single business entity represents a record in the database. The list of business entities represents multiple qualifying records in the database. These are converted into business entity classes.

Using system;using system.collections.generic;using system.data;using dataentity;using DataAccessCommon;namespace dataaccess{public class Daluserform {#region data access methods public int Deleteuserform (Object Co NN, UserForm UserForm) {list<mystaticdbhelper.mydbparameter> paras = new List<mystaticdbhelper . mydbparameter> {new Mystaticdbhelper.mydbparameter ("@FormID", Dbtype.int32, UserForm.            FORMID)};            String strSQL = "DELETE from [UserForm] WHERE [FormID] = @FormID";            int result = 0;            result = Mystaticdbhelper.executenonquery (conn, System.Data.CommandType.Text, strSQL, paras);        return result; } public int Updateuserform (Object conn, UserForm UserForm) {List<mystaticdbhelper.mydbparame Ter> paras = new list<mystaticdbhelper.mydbparameter> {new Mystaticdbhelper.mydbparameter ("@FormN Ame ", dbtype.string, useRform. FORMNAME), New Mystaticdbhelper.mydbparameter ("@TableID", Dbtype.int32, UserForm. TABLEID), New Mystaticdbhelper.mydbparameter ("@SingleOrList", Dbtype.boolean, UserForm. singleorlist), New Mystaticdbhelper.mydbparameter ("@WithCRUD", Dbtype.boolean, UserForm. Withcrud), New Mystaticdbhelper.mydbparameter ("@ApplicationID", Dbtype.int32, UserForm. ApplicationID), New Mystaticdbhelper.mydbparameter ("@FormID", Dbtype.int32, UserForm.            FORMID)};  String strSQL = "UPDATE [UserForm] SET [FormName] = @FormName, [TableID] = @TableID, [singleorlist] = @SingleOrList,            [Withcrud] = @WithCRUD, [ApplicationID] = @ApplicationID WHERE [FormID] = @FormID ";            int result = 0;            result = Mystaticdbhelper.executenonquery (conn, System.Data.CommandType.Text, strSQL, paras);        return result;           } public int Adduserform (Object conn, UserForm UserForm) { List<mystaticdbhelper.mydbparameter> paras = new List<mystaticdbhelper.mydbparameter> {new My Staticdbhelper.mydbparameter ("@FormName", Dbtype.string, UserForm. FORMNAME), New Mystaticdbhelper.mydbparameter ("@TableID", Dbtype.int32, UserForm. TABLEID), New Mystaticdbhelper.mydbparameter ("@SingleOrList", Dbtype.boolean, UserForm. singleorlist), New Mystaticdbhelper.mydbparameter ("@WithCRUD", Dbtype.boolean, UserForm. Withcrud), New Mystaticdbhelper.mydbparameter ("@ApplicationID", Dbtype.int32, UserForm. ApplicationID), New Mystaticdbhelper.mydbparameter ("@FormID", Dbtype.int32, UserForm.            FORMID)}; String strSQL = "INSERT into [UserForm] ([FormName], [TableID], [singleorlist], [Withcrud], [ApplicationID]) V  Alues (@FormName, @TableID, @SingleOrList, @WithCRUD, @ApplicationID);            Select Scope_identity () as [FormID] ";            int result = 0; DataSET ds = NULL;            ds = Mystaticdbhelper.executedataset (conn, System.Data.CommandType.Text, strSQL, paras); if (ds. Tables.count > 0 && ds. Tables[0]. Rows.Count > 0) {UserForm. FORMID = Convert.ToInt32 (ds. Tables[0].                Rows[0][0]);            result = 1;        } return result; Public list<userform> Getalluserform (Object conn) {String strSQL = ' select * FROM [userf            ORM] ";            DataSet ds = null;            ds = Mystaticdbhelper.executedataset (conn, System.Data.CommandType.Text, strSQL); Return Datamapper.mapdatatabletoobjectlist<userform> (ds.        Tables[0]); } public UserForm Findauserform (Object conn, UserForm UserForm) {LIST&LT;MYSTATICDBHELPER.MYDBPA Rameter> paras = new list<mystaticdbhelper.mydbparameter> {new Mystaticdbhelper.mydbparameter ("@F Ormid ", Dbtype.int32, UserForm.            FORMID)}; String strSQL = "select * from [UserForm] WHERE [FormID] = @FormID";            DataSet ds = null;            ds = Mystaticdbhelper.executedataset (conn, System.Data.CommandType.Text, strSQL, paras); Return Datamapper.mapdatatabletosinglerow<userform> (ds.        Tables[0]); }//omitted most of the #endregion}}

Code 11 code for the Business entity class

Using system;using system.collections.generic;namespace dataentity{public class Usermenu {#region private M        Embers private int _imenuid;        private string _strmenuname;        private int _iapplicationid;        private int _imenustyle;        private int _ischeme;                #endregion #region Properties public int MENUID {get {            return _imenuid;            } set {_imenuid = value;            }} public string MENUNAME {get {return _strmenuname;            } set {_strmenuname = value;            }} public int ApplicationID {get {return _iapplicationid;            } set {_iapplicationid = value;  }} public int MENUSTYLE {get          {return _imenustyle;            } set {_imenustyle = value;            }} public int SCHEME {get {return _ischeme;            } set {_ischeme = value; }} #endregion}}

If you don't TransactionScope

Strictly speaking, TransactionScope have some limitations. People have found a lot of TransactionScope limitations (Baidu, Google search has a lot of). Regardless of whether distributed transactions, as long as the scale is large, the complexity is higher, preferably do not use TransactionScope. Database transaction size is small, complexity is low, with TransactionScope or good. Once the scale becomes larger and the complexity becomes higher, the problems that TransactionScope brings are tricky. In the end, only TransactionScope is discarded. The problem also comes, do not transactionscope that use what. TransactionScope still brings some programming convenience, write a using clause, it can manage non-distributed database transactions, can also manage distributed database transactions. We can go to see a friend Artech article: http://www.cnblogs.com/artech/archive/2012/01/05/custom-transaction-scope.html, They proposed a class similar to TransactionScope usage. However, the classes they present do not support distributed transactions for the time being. If it is non-distributed, it can be borrowed. Another thing to say is that the code Artech in this article proves a case of TransactionScope. When the insertion record to 100,000, one-time commit transaction, TransactionScope incredibly hung up. This is only a single database, do not know the more complex, the larger will be. I hope you will brainstorm and find a solution that is perfect instead of TransactionScope.

Source: Thinking of ASP Application Architecture--unity application and three-layer code

Thinking of application Architecture of ASP.--unity application and Layer three code

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.