I wanted to write some distributed designs. In the current GIX4 project, many operations on the client must be recorded. The design of this function shows more or less how to design a multi-layer distributed system. Now I will describe this feature.
Function Description
The GIX4 project has a log review function, which requires the following features:
All operations of the customer must be recorded to support audit. For example, when a user logs on, opens a module, views data, and clicks the button ...... During operations, all the relevant data is recorded in the database of the server. The data includes the operation type, operation time, Operation content, operator, and client machine name.
Some specific events are recorded on the server, such as computing errors.
Design Objectives
This module must support the following goals:
* Provides simple and unified interfaces for client and server code.
* Asynchronous record is required.
* The same interface is also required if it is extended to a multi-level physical layer.
Design
First paste the completed design diagram and then describe it one by one:
Figure 1 all types
General
First, at the beginning of the API design, determine the interfaces to use based on the requirements. They contain two types: AuditLogItem, an anemia data type, and AuditLogService, a static class for AuditLogItem operations. AuditLogService temporarily publishes two static methods: one is to record the Log method Log (), and the other is to asynchronously record LogAsync (). As follows:
Because each physical layer uses the AuditLogService method, the implementation is different. Here we use the Provider mode and extract the IAuditLogProvider interface. asynchronous methods are no longer needed here:
/// <Summary> /// audit function provider /// </summary> public interface IAuditLogProvider {/// <summary> /// record the specified log /// </summary> // <param name = "log"> </param> void Log (AuditLogItem log );}
Except for the server that finally communicates with the database, other nodes use ClientAuditLogProvider as the provider by default. This provider uses ICommunication, which is responsible for communicating to the next node and submitting the logging function.
GIX4 implementation
This section mainly involves two classes: ServerAuditLogProvider and CSLACommandCommunication.
ServerAuditLogProvider uses the CSLA class library to convert AuditLogItem into a corresponding database model and store it in the database:
public class ServerAuditLogProvider : IAuditLogProvider{ public void Log(AuditLogItem log) { var dbItem = AuditItem.New(); dbItem.Title = log.Title; dbItem.Content = log.Content; dbItem.User = log.User; dbItem.MachineName = log.MachineName; dbItem.Type = log.Type; dbItem.LogTime = log.LogTime; dbItem.Save(); }}
CSLACommandCommunication uses the WCF and CSLA command modes as the basic framework, so that the current node sends the request to the next node. After the next node receives the request, use the Provider of the current node to process requests. The important code in the internal class AuditServerCommand is as follows:
[Serializable]public class AuditServerCommand : Csla.CommandBase{ private AuditLogItem _logItem; public AuditServerCommand(AuditLogItem logItem) { if (logItem == null) throw new ArgumentNullException("logItem"); this._logItem = logItem; } protected override void DataPortal_Execute() { //server log AuditLogService.Log(this._logItem); }}
Entire Process
The whole process is actually very simple:
Postscript
In fact, this design processIdeasVery simple: analyze the APIs to be provided (scenario-driven), analyze the differences in distributed implementation, write the basic part, and encode and refactor.
Actually, people familiar with CSLA should know that the communication mechanism in CSLA is implemented in a similar way. Therefore, this is a distributed design model.