Preface
There has been a period of time not updated blog, has been busy working very little time to continue to study something, said also ashamed, the main reason for blame is because of laziness. Fantasy is no use, and sometimes a lot of ideas have been stifled to the cradle, has not started to give up, which is the majority will have a bad habit, the world's most not missing is the dreamer, but practitioners, there is a saying saying good not afraid of thousands of strokes, I am afraid of a recruit, can do a good job is the winner of life. In addition, there are many interesting techniques in the study, but often there is no research to the end, just study how to use it, and then want to write an article is very dangerous things, if a technical research is not transparent, this time to express the words of opinion this will only harm, will not help people, to know that the smattering will be their own final harm.
First, the structure analysis
The above is written to oneself because found that they have recently lazy habits, so do a little review, OK. The basic techniques used in distributed development are discussed above, including Microsoft's WCF, Windows Service, message queue, and so on, where the message queue mainly discusses Microsoft's MQ, Since the author is now a. NET program ape, the use of MQ has been discussed in detail from the most basic of Microsoft MQ. You can see this article after the first few technical basics.
This article will use the technology discussed in the previous articles to build a small framework, mainly to achieve application (computer or mobile) and Web service communication between each other, intermediate message mediation Service using the above discussed in the MQ to implement, the specific architecture as shown:
With regard to implementations, the application in this example is just a small application using the computer-side WPF, which is developed using Microsoft's message queue, which is the Windows service developed by the Server service, The remote end of the Web service uses WCF to do the development. Specifically developed code will be discussed in detail later in this article.
Note: The structure of near-end entities, remote-side entities, webservice entities, and data contracts must be consistent in this architecture, so that you can avoid writing intermediate code for many conversions at development time.
Second, the architecture code
2.1 Near-end apps
The application-side is a simple WPF application that simulates a near-end application that sends message information to the message queue after execution completes, in this case the message queue stores the object information in XML format, so the message object needs to be sent first to specify how information is stored in the message queue, with the following simulation code:
Using system;using system.collections.generic;using system.linq;using system.net.security;using System.Text;using System.threading.tasks;using system.messaging;using system.xml.serialization;namespace MQSend{public class SendMQ { public void Send () {MessageQueue MQ = null; if (! Messagequeue.exists (". \\private$\\MSMQ")) {MQ = Messagequeue.create (". \\private$\\MSMQ"); } else {MQ = new MessageQueue (". \\private$\\MSMQ"); } MQ. Formatter = new XMLMessageFormatter (new type[] {typeof (Student), typeof (Teacher)}); for (int i = 0; i < 6; i++) {MQ. Send (New Student () {Id =i,age = "All", Name = "Zhang San" +i.tostring (), Teachers = new list< Teacher> () {new Teacher () {Id = 2, Name = "Miss Li" +i.tostring ()}}); } MQ. Close (); }} [Serializable] public class Student {public int Id {get; set;} public string Name {get; set;} public string Age {get; set;} Public list<teacher> Teachers {get; set;} } [Serializable] public class Teacher {public int Id {get; set;} public string Name {get; set;} Public list<student> Students {get; set;} }}
Note: The above code entity object Student and teacher have many-to-many relationships, which tend to have circular reference problems when serializing, because serialization is actually a property traversal that will be serialized down the object all the way down, so be sure to pay attention to the loop application when programming
Problem.
Note: Also, do not declare a collection of interface types when referencing a collection of properties, because a collection of interface types is not allowed to be declared when sending Message Queuing, otherwise "XX is an interface and cannot be serialized." "The problem.
After the application is run, messages are sent to the native message queue with the following message:
2.2 Remote-side server Service
The remote-side service This example develops Windows services because the service can be running at all times since it is powered on, that is, it can get messages from the message queue at all times, and then call the remote side's Web service to process the message. Because the content of the near-end message is the XML serialized object, the remote side server needs to deserialize the object into the service's entity object first when manipulating the Message object (the entity object here refers to the entity object of the Web service) and then does all the work on the entity object.
In addition, when developing the service, it is best to record the service running process, that is, the operation of the service is logged to the log file, because the service is very prone to problems during the operation, in the event of a problem, the content of the problem is recorded in the log file, This will quickly find and fix the problem.
Each service has a number of events, the most used of which is the service's turn-on event OnStart and end event OnStop, which adds logging functionality to both events, that is, the health of the service is written to the log when the service is turned on and off. In addition, a timer control is added to the service, with the interval time set to 1000ms, so that the message can be requested in real time, then the message is manipulated and the log information is saved.
As shown in the project structure, the webservice of the system is added to the project, and the specific proxy class mqserviceclient and the tool class Fileoperate are added for the webservice.
The specific code for the service is as follows:
Using system;using system.collections.generic;using system.componentmodel;using system.data;using System.diagnostics;using system.io;using system.linq;using system.messaging;using System.ServiceModel;using System.serviceprocess;using system.text;using system.threading;using system.threading.tasks;using Distributeservice.mqservice;namespace distributeservice{public partial class Service1:servicebase {public Service1 () {InitializeComponent (); } private ServiceHost host; Private Fileoperate Fileoperate {get {return fileoperate.getfileoperate (); }} protected override void OnStart (string[] args) {try { var str = "▌▌▌▌▌▌▌mqservice start at" + DateTime.Now.ToString () + "▌▌▌▌▌▌▌\r\n"; Fileoperate.writetext (str, fileoperate.files); } catch (Exception ex) {fileOperate.writetext (ex. Message, Fileoperate.files); Throw }} protected override void OnStop () {thread.sleep (30000); var str = "▌▌▌▌▌▌▌mqservice stop at" + DateTime.Now.ToString () + "▌▌▌▌▌▌▌\r\n";; Fileoperate.writetext (Str,fileoperate.files); if (this.host!=null) {this.host.Close (); }} private void Timer1_elapsed (object sender, System.Timers.ElapsedEventArgs e) {Message Queue MQ = null; if (Messagequeue.exists (". \\private$\\MSMQ")) {MQ = new MessageQueue (". \\private$\\MSMQ"); try {MQ. Formatter = new XMLMessageFormatter (new type[] {typeof (Student)}); var me = mq. Receive (); var stu = Me. Body; Fileoperate.writetext (Stu. ToString () + "\ r \ n", Fileoperate.filem); var client = new Mqhandlerclient ();//. Getmqhandlerservice (); Client. ADD ((Student) Stu); Client. Close (); } catch (Exception ex) {Fileoperate.writetext (ex. ToString () + "\ r \ n", Fileoperate.filem); Throw } finally {MQ. Close (); } } } }}
one of thewebserivceclientthe code is as follows:
Using system;using system.collections.generic;using system.linq;using system.management.instrumentation;using System.text;using system.threading.tasks;using distributeservice.mqservice;namespace DistributeService{Public Class Mqserviceclient {private static mqhandlerclient instance; private static Object _object = new Object (); Private Mqserviceclient () {} public static mqhandlerclient Getmqhandlerservice () { if (instance = = null) {lock (_object) {if (instance==null) {instance=new mqhandlerclient (); }}} return instance; } ~mqserviceclient () {if (instance!=null) {instance. Close (); Instance. Abort (); } } }}
Note: The code here is mainly to do the message processing, but often error, so to record the running log, the recommended use of open source log4net or nlog, but in this case, the stack information is written to a text file, you can easily see.
2.3 Remote-side web Service
The remote end Web service exposes the processing interface to the message, mainly the operation of adding and removing the db. The example of the Web service using the WCF to develop, the background using the EF code first as the system ORM Framework, and use FLUENTAPI to build the system's mapping part, the system published the database of the additions and deletions to the interface, the specific structure diagram is as follows:
The Web service across the remote side provides data for the other end, where WCF exposes a crud operation interface to the database after it is deployed to host, and the down DAL layer encapsulates the context of the database (DbContext) and the table entities of the database. The mapping rules for the DAL layer entity object to the database are encapsulated in the mapping layer, which is implemented using FLUENTAPI, and the final operation of the database is the EF framework. Next, you'll show the code for the next few major layers.
2.3.1 WCF layer additions and deletionsThe following code is a service developed using WCF, which creates a context object for the database at the same time when the client object is created, and finally synchronizes the data to the context, which is managed and synchronized to the DB by EF.
Using system;using system.collections.generic;using dal;using entitys;namespace distributewcf{//note:you can use the The "Rename" command on the ' Refactor ' menu to change the class name ' Mqhandler ' in code, SVC and config file together. Note:in order to launch WCF Test Client for testing the This service, please select Mqhandler.svc or MQHandler.svc.cs at t He solution Explorer and start debugging. public class Mqhandler:imqhandler {private TestContext context; Public Mqhandler () {this.context=new TestContext (); } public bool Add (Student stu) {this.context.Students.Add (new entitys.student () {Name = stu. Name,teachers = new List<entitys.teacher> ()}); This.context.SaveChanges (); return true; } public bool Delete (int stuid) {var stu = This.context.Students.Find (new {stuid}); This.context.Students.Remove (Stu); This.context.SaveChangeS (); return true; } public bool Update (Student stu) {return true;} Public list<student> FindAll () {var lists = This.context.Students.SqlQuery ("SELECT * from Student "); var liststu = new list<student> (); foreach (var student in lists) {var stu = new Student (); Stu. StudentID = student. Id; Stu. Name = student. Name; Stu. Sex = student. Age; Stu. Teachers = new list<teacher> (); foreach (var teacher in student. Teachers) {stu. Teachers.add (New Teacher () {Id = Teacher. Id, Name = teacher. Name,}); }} return liststu; } } }
Mapping Mapping code for 2.3.2 Fluent APIThis example uses the fluent API to do the mapping, because this mapping is very convenient to modify, and control the process of object Relational compilation at development time, so using this method mapping function, this kind of mapping is very simple, as long as the familiar mapping rules can be easily manipulated. The following code illustrates the mapping between a many-to-many relationship between a student and a teacher in this example.
The corresponding teacher entity and the mapping code are as follows:
Using system.data.entity.modelconfiguration;using entitys;namespace mapping{public class Teachermapping: entitytypeconfiguration<teacher> {public teachermapping () } {this . ToTable ("Teacher"); This. Haskey (x = x.id); This. Property (x = x.id). Hascolumnname ("Id"); This. Property (x = X.name); This. Hasmany (x=>x.students) . Withmany (x=>x.teachers) . Map (x = x.totable ("Stuteahcer"). Mapleftkey ("Teacherid") . Maprightkey ("StudentID") ); } } public class teacher{Public int Id {get; set;} public string Name {get; set;} Public ilist<student> Students {get; set;}}}
corresponding student entity and mapping Code as follows:
Using system.componentmodel.dataannotations.schema;using system.data.entity.modelconfiguration;using Entitys; namespace mapping{public class studentmapping:entitytypeconfiguration<student> { public Studentmapping () {this . ToTable ("Student"); This. Haskey (x = x.id); This. Property (x = x.id) . Hascolumnname ("Id") . Hasdatabasegeneratedoption (databasegeneratedoption.identity) . Hascolumntype ("int"); This. Property (x = X.name); This. Property (x = X.age); } } public class student{Public int Id {get; set;} public string Name {get; set;} public string Age {get; set;} Public ilist<teacher> Teachers {get; set;}}}
There are several ways to note:ef entity-to-object mappings, most commonly dataannotations data annotations and the fluent API two ways to write mappings. The students and teachers in this example are many-to-many relationships, and when you add a mapping using the Fluent API, you only need to add a many-to-many relationship between the objects, because this relationship generates an intermediate table so you use totable to specify the intermediate table's indication, and using Mapleftkey and Maprightkey to specify the primary key for the table.
The above code is the main code of the remote side, after running the code will add the corresponding table structure in the database, development is very simple, the resulting database table structure as shown:
Conclusion
Because this article just put forward a method of distributed development, this method needs to be tested in the project to evaluate the quality of the architecture, in addition, in the development also need to do strict management, and unified coding standards and acceptance criteria, there are a lot of attention to the place, the content of this article is not necessarily all correct, but after the author's test , what is the problem also please leave a discussion.
"Architecture Path (Distributed trilogy)"--ws+mq+wcf+ef (Code first)