One of the adventures of Internet cainiao, The Adventures of Internet birds

Source: Internet
Author: User

One of the adventures of Internet cainiao, The Adventures of Internet birds

An Offline service management system is built in the company. The function is very simple, mainly to record service application forms, approval and monitoring. The architecture of this system is set up by colleagues (cainiao like me won't let me set up). The architecture is very regular, with a three-tier architecture, however, my colleague said that the domain layer was added (he did not give me a clear explanation, but I saw some log and metric record behaviors on this layer ).

For the purpose of low coupling and high cohesion, we use the IOC framework (via IOC is equivalent to initialization, saving New and can be called directly, but IOC has an IOC container in the configuration file XML, you need to map interfaces to their implementation classes one by one (MapTo), in addition to link correspondence, file paths, namespaces, constructor parameters, etc.), Core layer (that is, the business logic layer, or service interface layer), define the service method in the interface, and then inherit the implementation. The object to be operated on is an interface class, And the instantiation of these object interface classes is in the Data layer, however, IOC realizes that the Core has no dependency on the Data layer. In the Controller (that is, the Web layer), the service is called through IOC. The IOC Resolver method is used to create the service object (IOC Initialization is placed in Global. in the Application_Start () method of the asax file, Global. the asax file is called first, including filters, error log processing, routing rules, and IOC initialization .), When creating a service object, inject the Data Warehouse into the service object, so that you can directly use the service object to call the database processing method in the warehouse. Because the warehouse interface class is defined in the Core layer, the injection is the warehouse class interface object, and the specific implementation of the warehouse interface is in the Data layer, operations on different data entity classes (Specific implemented objects) and methods for completing the data layer (nothing more than adding, deleting, modifying, and querying). Of course, there are some functions, for example, to add or modify object objects, you can directly call the encapsulated methods in the base class.) only the specific methods are required to write SQL statements by yourself.

The above are the design ideas of the entire system, and some of the details are the key.

1. How do I write permissions? Because there are three roles in the system: Administrator, reviewer, and user, we use the enum type to define

Public enum RoleType
{
Admin = 1,
User = 2,
Auditor = 3
}

In the Controller of the web layer, each Controller inherits from a BaseController (this class is defined by itself). In this class, we write the permission identification method. Pass

Public static UserInfo CurrentUser
{
Get
{
Var obj = System. Web. HttpContext. Current. Session ["user"];
Try
{
If (obj = null)
{
// Get windows user
Var loggedUser = System. Web. HttpContext. Current. User. Identity;
If (loggedUser! = Null & loggedUser. IsAuthenticated)
{
String userName = loggedUser. Name;
UserName = userName. Substring (userName. IndexOf ('\') + 1 );

UserInfo user = new UserInfo ();
User. UserName = userName;
// To-do find role
IUserService svc = IoC. Resolve <IUserService> (); // This Is How ioc initializes user service objects through user service interfaces.
Var roleInfo = svc. GetUserInfo (userName); the user service calls the database query to determine whether the user already exists in the database.
If (roleInfo! = Null)
{
User. RoleId = roleInfo. RoleId;
}
Else
{

// If the database does not have this User, the User is the default User.
User. RoleId = (int) RoleType. User;
Var repo = IoC. Resolve <IUserRoleRepository> (); // use IOC to reverse the user repository class (equivalent to initialization, saving New). repo can directly call methods in IUserRoleRepository
Var entity = repo. GetEntityInstance ();
Entity. RoleId = user. RoleId;
Entity. Operator = user. UserName;
Repo. Add (entity );
}

System. Web. HttpContext. Current. Session. Add ("user", user );
Obj = user;
}
}
}
Catch (Exception ex)
{
LogFormat. Write (LogFormat. BusinessError, "Auth-Exception", "error occurred when obtaining user authentication information! ", Ex, LogErrorLevel. Error );
}
Return (obj = null )? Null: obj as UserInfo;
}
}

This method is to obtain the UserInfo Class Object CurrentUser and call it in the following method:

Protected override void OnActionExecuted (ActionExecutedContext filterContext)
{
ViewBag. UserName = CurrentUser. UserName;
ViewBag. RoldId = CurrentUser. RoleId;
Base. OnActionExecuted (filterContext );
}

Of course, the login logout method is also written in:

Public void LogOff ()
{
Session. Abandon ();
CasAuthentication. SingleSignOut ();
}

In this way, the [Authorize] [HttpGet] and [ActionAuth (RoleType. User)] labels are added to each action in the Controller. In this way, ActionAuth can control permissions.

 

2. in Global. some routing configurations are required in the asax file. Otherwise, the system cannot find your action, RouteConfig. registerRoutes (RouteTable. routes); so define a static method RegisterRoutes in the RouteConfig class and configure the actions in the Controller you use as follows:

Routes. IgnoreRoute ("{resource}. axd/{* pathInfo }");

Routes. MapRoute (
Name: "BaseServiceMaintainanceIndex ",
Url: "Maintain/BaseService/Index ",
Defaults: new {controller = "Maintain", action = "SearchIndex"} // default parameter
);

3. use System. you can easily write programs. For example, if you query a List <T>, and you need to sort by time in descending order, you can use list. orderByDescending (c => c. dataChange_LastTime ). toList ();

4. paging: The paging mechanism mainly refers to the url input parameter, page number, after the number of lines, the data is returned through the data end limt {0 page number} {1 line number}, right, you also need to return the total data so that the front-end can calculate the number of pages divided. In the Controller, ViewData ["PagerRecord"] = pager is used to process the number of page numbers. Return to the View layer Pager pager = ViewData ["PagerRecord"] as Pager ;, in the View layer, ViewDataDictionary viewData = new ViewDataDictionary (); viewData object encapsulates the information to be transmitted on the page (this class of ViewDataDictionary is very important, it is used when data is transmitted between two pages (cshtml), and @ Html is used in page. partial ("PagerPartial", pager, viewData), routing parameters are sometimes used during page transmission, because the page needs to be refreshed during page transmission and the page must be refreshed without changing, therefore, the route parameters must be consistent. Therefore, RouteValueDictionary dict = new RouteValueDictionary () is also used this time. After the assignment is complete, assign the value to the viewData object.

5. because the query system has too many parameters, the parameter class is used at the Core layer, and the query return value also uses the result class. Data is the returned Data List, and some operations are also implemented using the return class.

 

// Query result class

Public class PagerResult <T>
{
Public int PageIndex {get; set ;}
Public int TotalCount {get; set ;}

Public IList <T> Data {get; set ;}
}

// Operation result class

[Serializable]
Public class ModifyResult
{

Private string _ status = "success ";
Private string _ message = "submitted successfully! ";

/// <Summary>
/// Modify the status
/// </Summary>
Public virtual string status
{
Get {return _ status ;}
Set {_ status = value ;}
}

/// <Summary>
/// Information
/// </Summary>
Public virtual string message
{
Get {return _ message ;}
Set {_ message = value ;}
}
}

Public class SuccessResult: ModifyResult
{
Public override string message
{
Get
{
Return "submitted successfully! ";
}
}

Public override string status
{
Get
{
Return "success ";
}
}
}

6. note that do not write select all on the database end and then use foreach () on the business logic layer for loop traversal. This will not only drag down the database but also put pressure on the business layer, the best way is to pass in the data end through the parameter for query. For example, there cannot be two records with the same Appid and sid. Therefore, when adding or updating a record, you need to judge and write a check function, getListByAppid (string appid) {} returns a List and then judges the resultList at the business layer, using Linq: resultList. where (t => t. sid = e. sid); e. sid is the sid of the data to be judged. You can also write getListByXid (string appid, int sid) {} to check whether the returned value exists.

7. For insert, delete, and update operations on multiple tables, you need to keep several tables updated/changed synchronously. Therefore, you need to use the transaction principle. In C #, I currently use using (TransactionScope tsCope = new TransactionScope () {} to introduce System. transactions: Add tsCope to ensure that the Code is complete to complete the transaction operation. complete ();

Using (TransactionScope tsCope = new TransactionScope ())
{
Data. DataChange_CreateTime = DateTime. Now;
Data. DataChange_LastTime = DateTime. Now;
Object iresult = _ dataRepo. Add (data );
Int iReturn = ConvertHelper. ToInt32 (iresult );
If (iReturn! = 0)
{
String operatorid = data. Operator;
// Write operation information to the Log Library
IOperatorLog ol = IoC. Resolve <IOperatorLog> ();
Ol. WriteLogInfo (iReturn, operatorid, LogMessage. Commit_Service_Application );
Res = new SuccessResult ();
TsCope. Complete ();
}
Else
{
Res = new FailedResult ();
}
}

8. Because the Core layer does not depend on the Data layer (this is essential for decoupling), sometimes it is impossible for you to initialize the Data entity on the Core layer. What should you do? To process Data, you cannot always pass the Data to the Data layer for further operations. This is a lot of trouble. In this case, you need to call the corresponding object repository interface in the Core layer to define a method for returning data instantiation. For example, I call AppFormEntity IN THE AppForm service, but there is no way to create an AppFormEntity, so I wrote a function IAppFormEntity CreateEntity () in IAPPFormRepository (this class is still in the Core layer); but its implementation class APPFormRepository is in the Data layer. Haha,

Public IAppFormEntity CreateEntity ()
{
Return new AppFormEntity ();
}

This is OK !! Of course, it is wise to write a generic interface method in the base class inherited by IAPPFormRepository and implement it in its implementation class. For example, the tenpository interface writes TEntity GetEntityInstance ();

Write in Repository

Public TInterface GetEntityInstance ()
{
Return new TEntity ();
}

Then, IAPPFormRepository inherits IRepository, and its implementation class APPFormRepository needs to inherit Repository and IAPPFormRepository

9. When querying multiple database parameters, You need to spell SQL statements. How can this problem be better? I used a common method here, which is implemented by List <string> concatenation. The specific implementation is as follows:

Public static StringBuilder GenerateSearchSql (SearchParams sp)
{
StringBuilder SQL = new StringBuilder (ConstSqlStr. SQL _APP_COUNT); // This is an SQL statement that queries a table and does not contain the where condition.
List <string> wheres = new List <string> ();
List <StatementParameter> listParameter = new List <StatementParameter> (); // query parameters

If (sp. Pid! = 0)
{
Wheres. Add ("a. Pid = @ Pid ");
ListParameter. Add (new StatementParameter {Name = "@ Pid", Direction = ParameterDirection. Input, DbType = DbType. Int32, Value = sp. Pid });
}

If (! String. IsNullOrEmpty (sp. AppId ))
{
Wheres. Add ("a. AppId = @ AppId ");
ListParameter. Add (new StatementParameter {Name = "@ AppId", Direction = ParameterDirection. Input, DbType = DbType. AnsiString, Value = sp. AppId });
}

If (! String. IsNullOrEmpty (sp. ApplicantId ))
{
Wheres. Add ("a. ApplicantId = @ ApplicantId ");
ListParameter. Add (new StatementParameter {Name = "@ ApplicantId", Direction = ParameterDirection. Input, DbType = DbType. AnsiString, Value = sp. ApplicantId });
}
If (! String. IsNullOrEmpty (sp. ServiceName ))
{
Wheres. Add ("s. ServiceName = @ ServiceName ");
ListParameter. Add (new StatementParameter {Name = "@ ServiceName", Direction = ParameterDirection. Input, DbType = DbType. AnsiString, Value = sp. ServiceName });
}
If (! String. IsNullOrEmpty (sp. UnitName ))
{
Wheres. Add ("r. UnitName = @ UnitName ");
ListParameter. Add (new StatementParameter {Name = "@ UnitName", Direction = ParameterDirection. Input, DbType = DbType. AnsiString, Value = sp. UnitName });
}
If (sp. Status! = 0)
{
Wheres. Add ("a. Status = @ Status ");
ListParameter. Add (new StatementParameter {Name = "@ Status", Direction = ParameterDirection. Input, DbType = DbType. Int32, Value = sp. Status });
}
// Determine whether the user has selected a condition
If (wheres. Count> 0) // the query is conditional.
{
String wh = string. Join ("and", wheres. ToArray (); concatenate conditions with and,
SQL. Append ("where" + wh); // after all the conditions are connected with and, add where to the front.
}
// Execute

Base. selectList <T> (SQL, listParameter ). cast <IT> (). toList (); // because the object interface class is returned, you need to convert the Object List to its parent class using the Cast <T> () method, the as method cannot be used.

Cast <> () method can refer to the http://www.cnblogs.com/ldp615/archive/2009/08/17/1548369.html

}

Note !! There are two types of Join functions in C #, but the value values are of the Array type. Therefore, you need to convert the List <string> type to the Array type.

[C #]
Public static string Join (
String separator,
String [] value
);

[C #]
Public static string Join (
String separator,
String [] value,
Int startIndex,
Int count
);

For the first time, write something in the background first.

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.