This question is: not "transaction" and "transaction" background: recently is doing a project, you need to use two third-party components: Beijing Liantang voice components and cmailsever as a secondary development component of voice chat room, the latter Secondary development assembly for small mail systems for websites
Demand: After the user logs in, there is no need to log in again to the chat room and the mail system, that is, realize a landing, all stations pass
The corresponding scheme will be given below and its dependence on transaction processing, and give a solution
Solution: When the user is registered, register a user to the chat room and the mail system, and modify the chat room and the mail system when the user changes the password, so when the user enters the chat room and the mail system, the main system only needs to deliver users and The password can meet the demand
The problem and its solution: When the user registers or modifies password information, if there is a chat room and the mail system error, then the user will not be able to log in to one of the systems, which puts forward an atomic transaction, To register and modify the password plus atomic transaction, the c # pseudo code is as follows:
Using
System.EnterpriseServices; [Transaction (Transaction (TransactionOption.Required)]
public
Class
Users: system.enterprisesservices.servicedcomponent
{[AutoComplete] public static void ModifyPassword (string userName, string olePassword, string newPassword) {ModifyMainSystemPassword (userName, newPassword); // modify the main database password ModifyVoiceChatPassword (userName, newPassword); // modify the chat room password ModifyMailSystemPassword (userName, NewPassword); // Modify the mail system password}}
This way can you realize that it will automatically return to the original state when there is a system to change the password. OK, the problem is solved!
Further think: But things don't have an idea, there is a prerequisite for the above code: chat room and mail system components must support transaction, so they can share transactions between applications, to achieve transaction submission / rollback purposes
Thoughts temporarily interrupted .......
Help for the 9CBS forum: How to achieve transaction processing to non-transactional components Using so-called resource compensator (CRMS), the following briefly talks about the implementation of the implementation of the implementation of the first, 2, 4, can search for SDK System .EnterpriseServices.comPensionResourceManager Namespace get more detailed information, or see Compensating Resource Managers (CRMS)
The postage here is to achieve integrity, the third step is that I am expanded, SDK has no such description.
1. Implement a CRM class
USING NAMESPACE
#region using namespaceusing System; using System.IO; using System.Reflection; using System.EnterpriseServices; using System.EnterpriseServices.CompensatingResourceManager; [assembly: ApplicationActivation (ActivationOption.Server)] [assembly: ApplicationCrmEnabled] [assembly: AssemblyKeyFile ( "crm ")] # endregionnamespace
CRMServer
#Region implementation code implementation code {[Transaction] // Create a Worker class public class CRMWorker:.. ServicedComponent {public void CRMMethod (string fileName, bool bCommit) {// Create clerk object Clerk clerk = new Clerk (typeof (CRMCompensator) , "CRMCompensator", CompensatorOptions.AllPhases); clerk.WriteLogRecord (fileName); clerk.ForceLog (); if (bCommit) ContextUtil.SetComplete (); else ContextUtil.SetAbort ();}} // Create class derived from Compensator class . public class CRMCompensator: Compensator {bool bBeginPrepareCalled = false; bool bPrepareRecordCalled = false; bool bBeginCommitCalled = false; bool bCommitRecordCalled = false; bool bBeginAbortCalled = false; bool bAbortRecordCalled = false; String _fileName; public override void BeginPrepare () {bBeginPrepareCalled = true;} public override bool PrepareRecord (LogRecord rec) {Object o = rec.Record; _fileName = o.ToString (); bPrepareRecordCalled = true; return false;} public override bool EndPrepare () {if (! Bbeginpreparecalled) {return false;} if (! Bpreparerecordcalled) {return false;} if (_filename == null) {Return FALSE
.} // This is a Prepare Phase success return true;} public override void BeginCommit (bool fRecovery) {bBeginCommitCalled = true;} public override bool CommitRecord (LogRecord rec) {bCommitRecordCalled = true; return true;} public override void EndCommit ( ) {! if (bBeginCommitCalled) {return;!} if (bCommitRecordCalled) {return;} if (_fileName == null) {return;.} // This is a Commit Phase success} public override void BeginAbort (bool fRecovery) { Bbeginabortcalled = true;} public override bool abortrecord (logrecord rec) {babyTrecordcalled = true Object o = rec.Record; _fileName = o.ToString (); return true;} public override void EndAbort () {if (! BBeginAbortCalled) {return;} if (! BAbortRecordCalled) {return;} if (_fileName == null ) {Return;} // this is an abort transcess.}} #Endregion} 2, generate strong names, compile into managed DLL [C #] sn -k crm.keycsc / t: library /R :system.EnterpriseServices.dll CRM.CS
3, use the command line to register the managed DLL as COM service regsvcs /: appname: CRMSERVER CRMSERVER.DLL
4. Call the COM service in the application [sample code]
USING NAMESPACE
#Region Using Namespaceusing System; Using System.IO; Using System.EnterpriseServices; Using CRMServer; Using System.Runtime.InteropServices; #ENDREGIONCLASS
CRM
{Public static int Main () {string logfilename = "crm.log"; Console.WriteLine ( "Creating a managed CRM worker object"); CRMWorker crmworker = new CRMWorker (); Console.WriteLine ( "Demonstrating a worker commit") CRMWORKER.CRMMETHOD (logfilename, true); console.writeline ("Demonstrating a worker abort); CRMWORKER.CRMMETHOD (logfilename, false); console.writeline (" DONE! "); Return 0;}}
Wow! Finally, you can pay a satisfaction!
Preparing to implement the above scheme on the project, but after happiness still need reason to think, can you really realize our requirements? There is at least the following questions: 1, you need to register your COM service on the server, deployment is inconvenient; 2, the code structure is more complex 3. If our web application needs to deploy through Mono in the Linux system? ... halo! Don't pick up your hint ...
Not satisfying is the only motivation to advance, will there be a better solution? I have continued to ask me that I have finally worked hard, I finally thought of a "perfect program": 1. Decompose the module, independent of the chat room and the mail system and the main system. 2. When the user registers, all users chat room and email The system password is the same, this password information is stored in the configuration file or database, which is used when the user enters the chat room and the mail system passes the password in the past. 3. When the user changes the password, there is no need to modify the chat room and the mail system password. Because they are always the same, there is a problem. What if I register when I registered? Below to give two solutions: 1, re-register once before the user logs in [not very good] 2, when the user is registered, it is ignored the error, providing a manual to the administrator to send the administrator to the chat room and The function of the mail system, when the user has problems, the administrator is handled [better]
Looking for him thousands of Baidu, he looked back, but the man was in a dim light.
Self-satisfaction, bricks continue ...