A Taste of AOP from Solving Problems With OOP and Design Patterns (Part II)

zhaozj2021-02-16  73

Continue the first part of the article, we will consider the problems proposed in the original text in this text, and explore the relevant technical mechanisms provided in the .NET / CLR, and finally achieve the same results in the form of AOP. . In order to let you enter the status as soon as possible, let's briefly review the contents already discussed in the previous article:

In the first part of the article, we started from a very simple fictional business operation (Calculator), combined with the non-functional needs (operational logs, permission control, performance monitoring, etc.) that often face in business development. The idea of ​​the object, combines the Decorator design mode, separating the core functions of the business operation object and other other service function code to achieve higher cohesion, loosely coupled software components.

However, after the problem of solving the confusion of the target code (that is, improved code cohesive), we have introduced a lot of code, including more objects and more complex structures introduced to solve problems (with JJX) The words are "excessive design" - although I emphasized this is a relatively reasonable design that can solve the problem we have to solve, but I am also hope that readers can experience this article in this feeling. The superiority of the method - It seems that JJX really occasionally this eye-catching, the trend is ignorant :)

The newly introduced problem becomes more prominent when the number of similar business operations continues to grow. In our current enterprise application project, the number of business components is already dozens. And we have several basic non-business needs for each component: based on method calling particle size rights control, method call log, business operation review, informative performance monitoring, configurable buffer strategy ... these requirements are once Another enterprise project was developed again and again. Do you say that there is an Application Building Block? Don't forget, that is just the tool you can use, even if the implementation of each function requires only one statement, think about it, 50 components take 20 methods ... How? Is it enough? Result Technology Director said a "Can I use my own buffer controller to replace the new buffer control application building block for MS?" ......

But so many object-oriented design methods also have design models still can't solve these problems? Why does the buffer control logic applied to each method of this component cannot be reused on another method of another component? Why can't the logic written almost exactly the same method logic logic on one component of a component? I think the answer may be an object-oriented package mechanism - method, this is already a detail of the object package in the interior, you have returned to the structure of structured programming at this level - you can call another method, Parameters you want to pass, but this call is no longer able to save or merge. Since OOP is not suitable for new production relationships, it is bound to produce demand for new production technology - this new product is called AOP. Abstract, AOP is a functional implant mechanism that is cross-cut on the internal hierarchical element (mainly constructor and method); simply, AOP allows you to intercept the method and implant the new code (but now technology The evolution has been developed towards more and more complex directions), and the most critical is that this cross-cutting is the type of object, and even unrelated to the object type. In this article, we will use the technical mechanisms provided in .Net / CLR to intercept and implant our non-business demand code for all 50 components.

Ok, talk less, we cut into the topic. Still from the easiest example (or that sentence: I hope you can imagine it is more complicated, more realistic - or for such a simple thing, any design technology is too designed to escape the design.)

Public Class Calculator {Public Int Add (INT X, INT Y) {RETURN X Y;}} This is a NUNIT-based unit test code:

[TestFixTure] public class unittest {public void testcalculator () {Calculator Calc = new calculator (); assert.isnotnull (CALC); askERT.Add (3, 5));}}

Still as part of the same needs, let's add way to this class to call the log. This time we use a new design pattern proxy to think. In fact, Proxy 's structure and Decorator are basically the same, the main difference between these two modes is that Decorator is mainly used to add responsibilities to objects; and Proxy is mainly used to control / master access to objects. Now, we want to have an proxy responsible for the calling code and real objects to master / control access to objects, while also need to know its existence. In order to apply this mode, we still can't escape the abstract base or interface, introduce the factory and other steps, then we first use the factory method to encapsulate the creation process of the object:

Public class calculator {} public static calculator createInstance () {return new calculator ();} public int address {Return x y;}}

Since the default non-parameter constructor has been modified as internal visibility private, the test code for using the new statement cannot be compiled, and we adjust the test code to the newly provided static factory method call:

Public class unittest {public void testcalculator () {Calculator Calc = Calculator.createInstance (); ...}}

Now let's see how to embed a proxy between calling code and real objects, apparently we should move your hands during the process of object creation, such as this:

Public class calculator {... public static calculator createinstance () {return (Calculator) New loggingProxy (new calculator ());}}

In the imaginary code above, we want to put a new instance of a real object (New Calculator ()) as a constructor that is incompatulative into the agent object, because the ultimate is really working or our true object, must definitely put this guy Pass it to the agent object. Then we want to create a good proxy object to return to the call code with the identity of the real object (ie, Calculator class). However, in terms of knowledge of object-oriented programming for C #, only when loggerproxy is the derived class of Calculator, the above type conversion code may be established at the runtime. The Calculator itself is already a specific class, so that LoggerProxy is probably not reason, all in order to have a proxy class that can be compatible with it, we can only extract public base categories or abstract interfaces (such as Icalculator), then separately Delivery, then I want to use the factory to combine it ... so, it is equal to the old way to solve the problem with Decorator mode, isn't it? :) However, if there is a way to make the LoggerProxy class with "imitation" other classes, or say that it seems to be in the case of calling the code and the proxy, the previous code can be settled! So we need a so-called transparent proxy, also referred to as TP)! Good news: There is also such a transparent agent class (__transparantProxy) in the CLR; unfortunately, we can't let your agent class derive from the transparent agent class to get this ability (just as most people hope), Cary can't make CLR think about a transparent "imitation" another class. To get a transparent agent in the CLR, we actually need a real agent (RP).

A real agent is a class that is derived from System.Runtime.Remoting.Proxies.RealProxy. The primary feature of this REALPROXY class is to help us dynamically generate a transparent agent class instance that can be transparently compatible with a specified class in runtime. How do you tell it what we want "imitate" class? You need to explicitly call a protected realproxy (Type ClasStoproxy) constructor in this class from the constructor derived from the RealProxy class, which is incorporated into the type of transparent agent to imitate, as shown below:

Using system.runtime.remoting.proxies;

Public Class MyRealProxy: RealProxy {Public MyRealProxy (Type ClasStoproxy): Base (ClasStoproxy) {...}}

This way, when constructing a new instance of the MyRealProxy class, RealProxy will help us construct a transparent agent that can be transparent in the interior! And when you get the instance of this new real agent, you can use its getTransParentProxy () method to get the inside of its internal constructive transparent agent. In order to verify that the transparent agent imitation can imitate any type of extraordinary ability, please add and run this test code in unit test:

public void TestTransparentProxy () {Type classToProxy = typeof (Calculator); RealProxy realProxy = new MyRealProxy (classToProxy); object transparentProxy = realProxy.GetTransparentProxy (); Assert.IsNotNull (transparentProxy); Assert.IsTrue (classToProxy.IsInstanceOfType (transparentProxy)) } We first choose a classtoproxy, and then construct our real agent (REALPROY), and then remove the internal dynamically generated transparent agent instance to imitate the type of agent type from the created real agent instance. TRANSPARENTPROXY). Next we verify two things: First, our transparent agent is not empty reference (indicating that it is indeed a transparent agent); then use the type.isinstanceOfType () method to verify the type of object is really wishing to imitate the type ( Of course, you can also write to detect the form of static types, namely Assert.IStrue (TransparentProxy is Calculator), but this method in code is possible to dynamically test type) ......

(Rely ... Meng! Compile not to go!) Hey, friends who want to learn too lazy to do it or active, actually verify the above code, so the impression is deep! :)

In fact, there is a problem, and the new problem is precisely the driving force of us to learn new things. @ # $ #% $ & * &% ... still let us first solve the problem of compilation. Look at the error message know: Our own defined real agent class (MyRealProxy) does not implement a method called invoke (). Turn over the document, discover this method to pick a type of parameters for system.runtime.remoting.Messaging.IMessage, and return a same type of object - what is this stuff? No matter, I have realized it (I will explain this later)! Who let REALPROY are an abstract base class, no matter what you have to remember to achieve this method when you derive it from this class:

Using system.Runtime.Remoting.MESSAGING; Public Class MyRealProxy: RealProxy {... public override iMessage Invoke (iMessage MSG) {Return null;}}

Friends using Visual C # .NET 2003 are blessed. If you can't stand it, you can also check yourself to check the definition of the method of Override, just get "Override" in the editor, then after you press the space - - "Till, don't tell me ..."

This compilation is definitely no problem, running NUnit Execute the TestTransparentProxy test node, you will immediately discover the second question (enough - a next two): An exception is generated when the RealProxy (Type Classtoproxy) constructor is executed Saying ClasStoproxy must be a type derived from the MarshalByrefObject type. What is this stuff? We still have to let go later. In fact, familiar or use .Net Remoting friends know that if you want an object to go out of AppDomain around the world, it or if MBV (Marshal By Reference), or be MBR method That is to let the type derive from this weird MarshalByrefObject (as for the method of MBV object, there are two kinds, please review it!) So we follow the CLR protest, specify the base class of our Calculator class as MarshalByrefObject (or Derived class):

Public Class Calculator: MarshalByrefObject {...}

This time, running the test, you will see green through the symbol, which verifies the basic understanding of TP / RP (Note: If you don't use NUNIT, create or modify the project into the Console type, then use console .Writeline () Output We need to verify the results after Assert - such as console.writeline (TransparentProxy! = Null) then look at it is True is also possible - but you really don't want to install a NUnit?: )

Now let's take a look at what IMESSAGE I have just said. Check the definition of this interface, find that there is a Properties property inside, the type is iDictionary, which means that iMessage is just a message that provides data with a dictionary. I want to know what news this is, we have to study what data is there in this dictionary. Then let's take a look - how to see? We noticed that this iMessage is incorporated when we are called by our real agent class, apparent that we should check the incoming message in this method. But Who will call this method? When is it called this method? Let us first recall how the call is to be done (the picture is gradually falling) ......

In the Feng's computer system, the calling method is performed through the stack. The stack is a data area that calls the code and the transfer parameter data and execution results between the modified code. Even in today's object-oriented world (or even in today's .NET world), ordinary method calls are still done via the stack. However, our advanced code is unless of this underlying mechanism. We just get all the parameters incorporated after entering the method, and returns the return value return to the caller when returned (of course, there is all REF) The value of the / OUT parameter) is good. In other words, because our advanced code cannot be manipulated directly, we can only interpret parameters at the level of the method and return the result, which is difficult to embed extra code for existing methods. Remember how we used Decorator mode to solve this problem? When the invoking code passes the input parameter to a method of Decorator, we can check even these parameters in this method, and then use the mechanism that uses the method call to call a method of forwarding a decorator, until the method Call the core object that arrives inside and returns. This process is actually a series of construction / parsing methods to call the stack process. Using the transparent proxy mechanism in .NET / CLR, the situation has changed fundamental changes (gradually recovering to color screen) ... When the call code acquires a transparent agent instance and treats it as a real object to issue any way to call This transparent agent will use the internal mechanism to intercept the method call and all related data related to the stack (incoming parameter values, parameter addresses, etc.), and store these data into a data structure that can be processed by advanced code. And forward this data structure to the code capable of processing it. As you imagined, the so-called "Senior Code can handle the data structure" is the iMessage we see before (more specific - in which the data dictionary provided); and that "can handle it" naturally Our real agent's code inside! That is, the transparent agent helps us intercept all methods calls from the calling code based on the stack, and packed it into a data dictionary to send us the real agent to our real agent to handle the real agent to process in the high-level language level. It is the core issue that this article is to be described, that is, using CLR's TP / RP mechanism to intercept method calls, implement basic AOP programming tasks - through the initial introduction here, you must have to have this mechanism with traditional-oriented objects (including The difference between the mechanism used by the Decorator design mode described above is preliminary.

In preliminary understanding of these theoretical knowledge, let's take a look at the transparent agent to pack what data on the calling method. First, we change the CREATEINSTANCE () method of the Calculator class to return a transparent agent that can imitate the Calculator class, and the real agent that this transparent agent relies on, it is just now what we wrote. (Is actually I can't do it) MyRealProxy!

public class Calculator: MarshalByRefObject {public static Calculator CreateInstance () {RealProxy realProxy = new MyRealProxy (typeof (Calculator)); object transparentProxy = realProxy.GetTransparentProxy (); return (Calculator) transparentProxy;}}

Now this code should be very easy to understand for you (or I have not written clearly)! After compiling, run the first TestCalculator test, hey ... an error! Looking at the call stack when you are wrong, you will find that it is very simple. We don't do anything in the innovoke () method of the real agent. You can do it! However, the error does not matter, we can first take a check in the end-entered the dictionary of attributes IMessage wisdom of which have their places: public class MyRealProxy: RealProxy {... public override IMessage Invoke (IMessage msg) {IDictionary properties = msg.Properties; foreach (Object Key In Properties.keys) {Console.WriteLine ("{0} = {1}", key, proties [key]);} return null;}}

We know that an IDictionary data dictionary is actually a key / value value to an array. In this newly added code, we enumerate each key value in the dictionary, and print out it and it in the dictionary (you said that I am stupid, every entry in the dictionary is a Dictionaryentry. It should be accessed with entry.key and entry.value to access to entry.key and entry.value ... Unfortunately, this dictionary is not top, so it's more quirky, interested. You can go see it. Source code :). Run the test TestCalculator node again, still an error! Also, we have not solved the problem yet. But even if I have already peek into the output result in the console.out window:

__Uri = __ MethodName = Add__MethodSignature = System.Type [] __ TypeName = AOP.Part.II.Calculator, AOP.Part.II, Version = 1.0 ... __Args = System.Object [] __ CallContext = System.Runtime.Remoting.Messaging.LogicalCallContext

Sure enough, this dictionary contains some information about this method call, guessing it is almost the same: __ methodname is obviously the name of the method being called, __ typeename is a full name of the type of this method, __ args is an Object [] It should be the parameter value passed in when the method is called? What __uri is the stuff? __Methodsignature this type [] What is it? There is also a __callcontext, it looks a bit like the context introduced in the decorator in Decorator, is it? Write two lines of code analysis:

public class MyRealProxy: RealProxy {... public override IMessage Invoke (IMessage msg) {... foreach (object arg in (object []) msg.Properties [ "__ Args"]) {Console.WriteLine ( "Arg: {0}", arg } Foreach (Type Type in (Type ") msg.properties [" __ methodsignature "]) {console.writeline (" Signature: {0} ", type);} return null;}} Run test, really see Expectative results: ... Arg: 3ARG: 5Signature: System.Int32Signature: system.int32

That is, in the data dictionary in the incoming iMessage, all the numerical sequences of all incoming parameters are included in __methodsignature, and the type sequence of the corresponding parameters (Method Signature is translated in many books). Signature method, in fact, its definition is very simple: it is a sequence of parameter types in the parameter list of methods, and its initial use is probably used to combine the method name to identify a specific method to be overloaded).

Now we hope to make the test code to run correctly, which requires us to return the method when calling the method on a real object from the invoke () method. Return to the call code. We write Return 8 ... I am afraid I can't do it. Because the return type of the invoke () method is also an iMessage, that is, the transparent agent wants us to put the return result is also wrapped in a message object - but how do I know how to pack such a data dictionary? Fortunately, I found a class named ReturnMessage, seeing it is dry. We can construct an instance of ReturnMessage, let it bring our return value to call the code back through the transparent agent! This class has two distinct constructors (you turn over the document), one is used to handle normal return (this is the RET parameter, it should be the actual return value), and the other The exception is handled (that is, that E). Outargs / outargscount is not used, it should be used to return output parameters. LogicalCallContext No matter in it, give a null first! What is IMETHODCALLMESSAGE? As the name, a message represented by the method - It turns out that it is an interface from iMessage (more exactful - imethodMessage). If you see the definition, you will understand that it uses many of the properties dictionary in iMessage. The properties and methods are released, so that we can more intuitively access the incoming news that represents the method called. So now we let Invoke () return to the "correct result" to test the test code:

public class MyRealProxy: RealProxy {public override IMessage Invoke (IMessage msg) {... IMethodCallMessage callMsg = msg as IMethodCallMessage; int x = (int) callMsg.InArgs [0]; int y = (int) callMsg.InArgs [1]; int Result = x y; Return New ReturnMessage (Result, NULL, 0, NULL, CALLMSG);}} Compiled and runs test, cool - green.咦,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, Fortunately, it's just a plus, if you count a circumference rate, you will have a good look! You said, this is still not good, I created a Calculator to work, don't work:

Public class myrealproxy: realproxy {public override iMessage Invoke (iMESSAGE MSG) {... Calculator Calc = Calculator.createInstance (); int result = cagc.add (x, y); ...}}}

Ok? It seems that it is not possible to die, because we are handling this add () method call, and the instance returned by CREATEINSTANCE () will also be a transparent agent (although not the same instance). Here if you don't have to transparent agents, we need the core realization of the truly work, this good office, when constructing the real agent, you will not be able to work in a real object.

public class Calculator: MarshalByRefObject {public static Calculator CreateInstance () {Calculator realCalculator = new Calculator (); RealProxy realProxy = new MyRealProxy (realCalculator); object transparentProxy = realProxy.GetTransparentProxy (); return (Calculator) transparentProxy;}}

In this case, we have to add a corresponding constructor for MyRealProxy:

Public class myrealproxy: realproxy {... private marshalbyrefObject target; public myRealProxy (MarshalByrefObject target): base (target.gettype ()) {this.target = target;}}

After such transformation, when we encounter Invoke () call, you should access the true work of the true and managed Calculator object that started to start and use it. But ..., etc., how should we forward the way to this object from the method you get there from the transparent agent? Can we do not operate the stack! I can't write int result = (Calculator) Target .Add (x, y)! We plan to let this real agent to serve the 1000 ways of 50 components ... Our answer is the remotingServices.executeMessage () method. RemotingServices is a tool class in the System.Runtime.Remoting Namespace, which provides a lot of practical auxiliary methods to help us implement a lot of underlying classes including real agents. Its ExecuteMessage () method is used to be super simple, and the effect is also a flash. With its help, we do not have their own touch those InArgs what it: public class MyRealProxy: RealProxy {public override IMessage Invoke (IMessage msg) {... IMethodCallMessage callMsg = msg as IMethodCallMessage; IMessage returnMsg = RemotingServices.ExecuteMessage (target , Callmsg; Return ReturnMsg;}}

Compile and run test, you can find everything is normal. However, things happening are the most important: we already have the basic means of intercept any method of any MarshalByrefObject object, then there are more things that are left! Here, it is like this, it is like this, the transparent agent is responsible for converting the stack of the method into a message and forwarding the real agent of the real agent () method that consulates it, and who returns the message Convert the stack and send it to the real object? Who is the result of the real object method to package the INVOKE () method from the result of the real object method from the stack to the message back to the invoke () method? This guy is actually StackBuildersink, and we will mention it later, and now make a look.

Go back the head to carefully observe the above code, you can find that the implementation of the truly real object method is to occur when the transutementage () method of calling RemotingServices. Before it, we can obtain (or even modify) all information recall by callmsg (the pre-processing of the AOP basic operation); after it, we can get (or even modifications) all about the method to return. Information (that is, AOP basic operation of post-processing! Remember two different situations - Normal return and throw an exception) - Tips you prompt you to see the iMethodReturnMessage interface corresponding to iMethodCallMessage, we are from ExecuteMessage The iMessage obtained by the method is to be converted to this interface.

Ok, please write a real agent class in accordance with the current information, such as call LoggingProxy. You can make this real agent to print a record in each method of the agent's object, such as:

[2004-02-16 12:34:56] Calculator.Add (3, 5) - (37ns) -> 8 should not be difficult? Write well, continue to look down ...

Now we have two real agent classes (what? Still not write? Don't be lazy :), one is myRealProxy, it is simple to output the contents of Msg.Properties when the method is called; one is you just written LoggingProxy, it should be able to record log information called each method. What should we do if we want to combine the functions provided by these two real agents like combined Decorator? With the knowledge and ideas of the previous text, we can first try again to connect the transparent agents constructed by several real agents to connect to each other with Decorator mode (okay? - how can you notice transparent agent? Magic - it is unlimited to the instance of calling the code. like this:

public class Calculator: MarshalByRefObject {public static Calculator CreateInstance () {Calculator realCalculator = new Calculator (); RealProxy realProxy = new MyRealProxy (realCalculator); Calculator fakeCalculator = (Calculator) realProxy.GetTransparentProxy (); RealProxy loggingProxy = new LoggingProxy (fakeCalculator) Calculator result = (calculator) LoggingProxy.getTransparentProxy (); returnrate;} ...}

The transparent agent returned by CreateInstance () is actually constructed by the LogGingProxy instance, and the real-working object inside the instance is a transparent agent constructed by the previous MyRealProxy and returned, and the final work is the first constructed Realcalculator. . When the call code is called to this transparent agent, the LogGingProxy's transparent agent first packs the information on the stack to the INVOKE () method of the LoggingProxy; then call RemotingServices.executeMedEMEMEMESSAGE () in the loggingProxy INVOKE () (Convert back to stack by StackBuildersink - Remember the friend mentioned earlier? :) Forward to the target object - the transparent agent constructed by MyRealProxy - however, this forwarding will be once by the message to the stack The process of the message (else don't forget, no matter how often returned from the invoke () method, the transparent agent converts back to the stack-based method call results - calling the code to this string of this road It's really unknowing)!

A strike? This can't help but think of another design pattern, that is, Chain of Responsibility (duty chain). We can package a series of processing code interested in the method to call the message to a separate, highly constructed message processing object, and form a duty chain by forming its string into a chain list, let the method call the message along this The bellows go all the way until the real object is arrived until the real object - and the post method returns the message and then returns each participant on the sequential channel. Through this mechanism, we avoid the additional overhead that repeatedly conversions between stacks and messages, thereby intercepting all method intercepts processing activities in a unified message-based world - that is, we need place a chain reaction - apparently, it should be a real agent, we might as well call it MessageChainProxy, namely news agency chain it: public class MessageChainProxy: RealProxy {private MarshalByRefObject target; public MessageChainProxy (MarshalByRefObject target): base ( Target.gettype ()) {this.target = target;} public override iMessage Invoke (IMESSAGE MSG) {Return Null;}}

How, this six lines realize a non-working REALPROXY skeleton code now you can also write it out? Now let's start writing substantive code. As mentioned earlier, if there are multiple pieces of code that need to be connected to the method call message, we want to encaps them, becoming a message processing and forwarder - just in the .NET Remoting has defined this. A semantics, we may wish to use it directly, this is the iMessageSink interface (same in system.Runtime.Remoting.Messaging namespace):

Public interface iMESSAGESINK {iMessage SyncProcessMessage (iMessage MSG); iMessageCtrl AsyncProcessMessage (iMessage MSG, IMESSAGESIN);}

Take a closer look. In fact, this interface is very simple: NextSink as the name suggests, it must be the next acceptor in the message processing chain; SyncProcessMessage is definitely a method of truly handling method messages (this is used for synchronization occasion, and the other A begins The asynchronous occasion-asynchronous method is also supported in .NET is also supported in .NET). Considering that we may need to write more and more messaging processors, you may wish to provide a basic implementation for this interface:

public abstract class MessageSinkBase: IMessageSink {private readonly IMessageSink nextSink; public MessageSinkBase (IMessageSink nextSink) {this.nextSink = nextSink;} public IMessageSink NextSink {get {return nextSink;}} public abstract IMessage SyncProcessMessage (IMessage msg); public virtual IMessageCtrl AsyncProcessMessage (IMessage MSG, IMESSAGESINK) {Return nextsink.asyncProcessMessage (msg, replysink);}} In this abstract base class, we implemented two methods in the iMessageSink interface: NextSink's getter because it is unlikely to be flexible Therefore, it is achieved as the default non-virtual method (um? How to make a way, don't you attribute? Don't forget the property is actually a one or a method! Logic (this is not a template method), so declares that it is still very natural; asyncProcessMessage, considering that all message receivers supports interception processing of asynchronous methods, it is better to provide a default implementation Forward to NextSink (or implementing NotSupportedException, this is also a common practice), that is, derived classes can be able to achieve or override this logic as needed. Now we can extract the Invoke () method in the original REALPROY as the syncprocessMessage () in iMessagesink, because there is nothing to say, this is no longer wasting network bandwidth 喽 (% $ ^ %%) $ #). Let's still see how MessageChainProxy implements the duties, because this block is not a topic of this article, so I will no longer be derived, I believe you can understand this part of this code:

public class MessageChainProxy: RealProxy {private MarshalByRefObject target; private IMessageSink headSink; public MessageChainProxy (MarshalByRefObject target): base (target.GetType ()) {this.target = target; this.headSink = new TerminatorSink (target);} public override IMessage Invoke (IMessage msg) {return headSink.SyncProcessMessage (msg);} public void AppendSinkType (Type sinkType) {object [] ctorArgs = new object [] {headSink}; IMessageSink newSink = (MessageSinkBase) Activator.CreateInstance (sinkType, ctorArgs) Headsink = newsink;}} code, Headsink is the head junction of the entire message processing chain, and the entire call chain is explicitly called by each Sink in its own xxxProcessMessage () method (MSG) To form it (this is called Decoratee.Method () in each decorator in Decorator mode). It is worth noting that when MessageChaInProxy is completed after the construct is completed, there is no call to any appendsinktype (), we hope that it will work properly (that is, nothing to do, as long as you do not throw out empty reference exception Ok, so we have to introduce a concept of TerminatorSink - this is the same as the Terminator concept in the SCSI device chain, is a terminator. We have achieved it as follows (note that the part of the bold is fine, I will no longer analyze - if you still can't understand, then my article is white, I :)

private class TerminatorSink: IMessageSink {private MarshalByRefObject target; public TerminatorSink (MarshalByRefObject target) {this.target = target;} IMessageSink IMessageSink.NextSink {get {return null;}} IMessage IMessageSink.SyncProcessMessage (IMessage msg) {return RemotingServices.ExecuteMessage ( Target, MSG as ImethodCallMessage);} iMessage IMESSAGESIN.ASYNCPROCESSMESSAGE (IMESSAGE MSG, IMESSAGSINK) {throw new notsupportedException ();}}

Think about it, the truth is actually very simple. This is also a very common object-oriented design pattern. Some places are called null object, in short, it is also an alternative to the occasion that may have an empty reference, thereby simplifying Complex conditions judgment logic - Write here, I am afraid there is a master to protest. In fact, I will give you more ideas to solve problems. How do you choose or put it in a specific environment? More choices are better than choosing to choose better (let alone this concept is also putting mats for some of the contents in the next item :) Well to write down ... Because this TerminatorSink is only used in our own MessageChainProxy , So it is appropriate to define it as a private embedded class.

Public Class MessageChainProxy: RealProxy {Private Class Terminatorsink: iMessagesink {...} ...}

Now we can use this message processing chain proxy class with scalable capabilities in the Factory Method of Calculator:

public class Calculator: MarshalByRefObject {public static Calculator CreateInstance () {Calculator realCalculator = new Calculator (); MessageChainProxy chainedProxy = new MessageChainProxy (realCalculator); chainedProxy.AppendSinkType (typeof (MyMessageSink1)); chainedProxy.AppendSinkType (typeof (MyMessageSink2)); ... Return (Calculator) ChainedProxy.getTransparentProxy ();} ...}

Here you need to pay attention to it, because it is an ordered call chain, the order of adding message processor nodes has a great impact on the final execution logic. For example, you have two message processors: one is to do method logs, the first addition to the processing chain (its nextsink will point to TerminatorSink); the second is to do access control (is based on the security identity of the code caller) And permission decisions whether this method is allowed to be executed, and then it is added to the processing chain (NextSink pointing to the front method log processor). At this time, when the calling code issues a call to the method's method, the stack-based call first is intercepted by the CLR's transparent agent, and converted into method call messages, and then sent to the corresponding real agent is our MessageChainProxy The invoke () method is handled, and the method immediately passes the message to Headsink, which is the SyncProcessMessage () method of the access control processor that is last added to the processing chain. At this time, if the access controller allows the method to continue, the same method call message is forwarded to the method log processor processing pointed to the nextsink, the final method message reaches TerminatorSink and is forwarded to transuteMessage () Method for RemotingServices - Method - I still remember the execution logic of this method: a transparent agent's "anti-transparent agent" is StackBuildersink (you see, its name has hints it is actually an IMESSAGESINK!) Ultimately use incoming method to call messages Reconstruction call stack and send our Calculator class to real work ... but if there is no pass in the access controller, it is thrown out of safety unusual (to remember to construct a representative method to call exceptions with ReturnMessage Return to the message 噢! Otherwise, the transparent agent is no longer transparent ...), obviously the approach is not to be executed at this part of the method (more 甭 甭 甭 甭 随 t t t 了Calculator will never see this time-free approach.). So, if you want to record all the method call requests, you should put the method log processor in front of the permission control, that is, the log processor will be added after adding the access controller. This truth is also relatively simple, and the implementation of the Decorator model said in front - I will look back in this article again here.

Broken to this (good), we have had a preliminary understanding of the method interception mechanism based on TP / RP and IMESSAGE, and uses these knowledge should have solved a lot of problems. Then there is any use of Decorator-based mechanism described above. actually not. The truse of these two mechanisms itself also implies that they will play different advantages in different occasions and in situations. First, it is undeniable that Decorator's stack-based method forwarding mechanism is definitely more efficient than iMessage-based conversion transfer mechanisms, of course, for many enterprise applications involving remote methods or desktop applications for local operations Performance may not be mainly contradictory, but you still have to remember this potential trap - especially in the starting phase of the selection technology. However, through a transparent agent-based mechanism we can focus some universal logic that is not related to specific object types or even methods in a real agent, and use the object build mode to dynamically (ie, runtime) "sew" to the target Every way of objects, this mechanism is very tempting for adding N more universal behavior for a large number of objects - even easy to make you compromise therefore a little performance! However, since it is very versatility, then for the need for targeted occasions, for example, according to the value of the parameter introduced in the method, it is more flexible to implement the Decorator interface-based approach to the Decorator interface. The mechanism designed for versions to deal with targeted occasions itself will definitely be lost. Therefore, the best ending may still need to integrate two mechanisms, which means that some of the functionally stacked features that need to be treated, applied to the core object, and uses some universal functions to utilize transparency Agent's magic effect on the object - this mechanism is in fact that it has been designed and adopted in our current project development, and it has brought a lot of benefits to our project development (reducing thousands of lines of code). Software system that is easy to maintain and flexible - this is not enough? :) Finally, put some small skills related to this part of the content, maybe it is useful to you:

in

IMethodMessage

Introduced in this interface

Methodbase

This property, through it, you can enter

REFLECTION

The type information on the worldview method includes custom properties. Use it you can make real agents

INVOKE ()

The method provides parameters, thereby increasing the flexibility of the system - remember: this is just

increase

A flexible mechanism does not replace other mechanisms - you can still read the relevant parameterized information from the configuration file, right

PROGAME

? :)

Real agents are not only for

MarshalByrefObject

Constructing a transparent agent, which can also construct a transparent agent for an interface. So you can use a real agent to provide methods to call messages based on many different interfaces - just like we are

Elegantdal

Like the method used, as long as the interface is defined, obtain the transparent agent, it is not necessary to provide the implementation class of the interface, you can complete the cumbersome features that you need to implement one by one. For details, please refer to us directly at the beginning.

ReturnMessage

Returns the implementation of the execution result, the principle is the same.

However, when a transparent agent agent is an interface, you will not be able to use it.

RemotingServices.executeMessage ()

Forward method call messages to it. Here you need these two helpers:

RemotingServices.istransparentProxy ()

with

RemotingServices.getRealProxy ()

. Once you have a real agent in your hand, how to forward the news?

More tips still leave you yourself to explore it in practice, I have said that I am not intended! :) Here, the content of this article has been basically completed, but the picky readers must have a lot of uncomfortable feelings, such as:

Want to intercept the constructor call, but the real object has been created in the real agent, what should I do?

To use

TP / RP

Packaging object, you must write

Factory Method

Package the entire construction process, can not use more intuitive

New

Command to create a proxy object directly?

If you are

Calculator

Some methods of classes will represent object instances

THIS

When passing to the outside of the object, this reference is a reference to the real object directly! So you carefully set the key than the access controller, etc. will be bypassed! How can I guarantee that the external call always has a heavy level I set up?

More unhappy, please send me by feedback :)

In fact, these contents are also scheduled to be completed in this article, but the space is limited (excuse!) I think it is still to continue to analyze and solve it in the next text! It is still as always, please tell me through the message or email, please tell me through the message or email, your support is the biggest movement I wrote! Thank you again! :)

# 回 t t o 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2

John_masen

I am studying a system that saves object configuration data through the database, supports running inheritance (can dynamically change the object behavior), I feel very harvest after I have seen this article, I and the landlord is two The road, but feeling very similar, all adopted the concept of attributes, and I hope to have the opportunity to explore this topic with the landlord. (Here is the wrap) briefly introduce my ideology: I save the object's definition by the concept of object and object properties, using hierarchical structures to save object definitions, the object's definition is a fully qualified name of Type, the next object The behavior of the superior object is automatically inherited, and the partial line can be rewritten (such a complete set is called the object template), the property of the object can point to another object (or object template), the object is responsible for modifying the object of the object, can say Very similar to the idea of ​​the landlord. Because the level of definition is completely in the database, it is very flexible. This happening is mainly ideas for business processes and business entity objects that are often modified in commercial systems. Now because there is still a project in your hand, you will take this thing. The problem encountered mainly how to achieve the self-data structure description of the object (for business entities), the cyclic references of the associated object, and some, I can't think of it. I hope to communicate with the landlord. MSN: bucherjiang@msn.com# (removed #)

# 回: a Taste of aop from Solving Problems with OOP and Design Patterns (Part II) 2/24/2004 3:32 PM By

PROGAME

What is the business object or an entity?

"Because the definition of the level is completely in the database, it is very flexible."

Is this level definition not to refer to "O / R mapping"

# 回: a taste of aop from Solving Problems with OOP AND Design Patterns (Part II) 2/24/2004 7:52 PM Byjgtm'2004 [MVP]

@Progame: What I want to know is whether this agent is not related to the distance?

I really didn't find the right opportunity in the article. In fact, why I always said that this is .NET Remoting Infrastructure, because .NET Remoting architecture The runtime section is actually an implementation on this infrastructure (this implementation is an unapproved internal type, name is RemotingProxy, It is also a real agent from REALPROXY. In addition to the part of the Runtime behavior, .NET Remoting also has a large piece of content responsible for remote object configuration management.

Therefore, the real agent mechanism itself is just the task of completing two world conversion: from the state of the stack to the news world, then returning from the news world to the stack world. In the news world, everything is dry, what you have a custom agent says - including location information of remote access.

In other words, since I wrote the real agent written in the text, there is no attempt to deal with the transparency of the object, and they are of course not to consider for object positions - actually with .NET Remoting has no relationship (we just with its The foundation has realized the method to intercept!

However, if you will be a .NET Remoting remote object (that is, a transparent agent object with RemotingProxy as a real agent) as the target into the REALPROXY described in my text as a Target, then method interception can act on the object. (This mechanism is actually implemented in RemotingServices.executeMessage (), ie, if the target is a transparent agent, the method to call information to be executed to the transparent agent's invoke () method to continue execution) .

Regarding this issue, I plan to write some text later, talk about the integration topic between AOP and .NET Remoting, I don't know if there is friends who are interested. :)

# 回: a taste of aop from Solving Problems with OOP and Design Patterns (Part II) 2/24/2004 8:03 PM By

JGTM'2004 [MVP]

@Kain: The first one does not have a second piece

Well, this may have a relationship to your technical background, or it is also related to the positioning of my article. If you have any questions about the first article with OOP and design patterns to solve the separation object responsibilities, you can contact me. :)

@Dreamaster: But it doesn't matter with AOP?

AOP's most basic mechanism is to separate the across object type ASPECT code logic to achieve higher cohesive objects by injecting the code mechanism (whether it is compiled or runtime). This article is to describe the runtime method to intercept the runtime method to intercept the runtime method in the .NET. However, there is really no flower level to explain AOP, because I just understand the fur, and I am not good at the door! :)

@Redmoon: It seems that you want to look at it, you can really understand it.

In this way, I wrote the article after I wrote the identity of the reader to leave it over again, spent about two hours. If you find out that the knowledge in this is what you need, then I suggest you spend two hours to follow, so I will balance! :) Of course, if there isn't use it now, just have a good collection, hehe! @John_Masen:

I haven't understood what you mean, feeling is a runtime that is defined through configuration data? A bit like explaining the BASIC? This way, because my MSN is often connected, please send me an email through the left "Contact" function, how do our emails? :)

# 回 t t o o 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2

Kain

As an initiator, I feel like I have read the second article.

Description of the use of IMESSAGE and other interfaces. In this way

I prefer CSDN development masters in CSDN.

The way.

# 回 tTE OF AOP from Solving Problems With OOP AND Design Patterns (Part II) 2/25/2004 10:44 AM BY

JGTM'2004 [MVP]

@Kain:

I am dizzy by you - I feel that the first one does not understand or understand the second article? However, seeking truth from facts, I suggest that beginners will first grasp the basic knowledge. The mechanism mentioned in this article is not suitable for all occasions, it just gives you more mechanisms that solve complex problems - especially if there is no way Too easy to use (so after the article I also wrote how to combine the specific question to choose a specific mechanism). After really understanding the internal mechanisms of these mechanisms, in the actual development or by refer to the MSDN Library documentation! :)

# 回: a taste of aop from Solving Problems with OOP and Design Patterns (Part II) 2/25/2004 12:14 PM By

Microhelper

On the code of the COPY article, I only read half :(

Spelling mistake

Calculator realcalculator = new caculator ();

Caculator should be Calculator

>> After such transformation, when we encounter invoke () call, you can access the true managed Calculator object that started to get started.

At this time is

....

Public Override iMessage Invoke (IMESSAGE MSG)

{

IMethodCallMessage Callmsg = msg as iMethodCallMessage;

INT x = (int) Callmsg.inargs [0];

INT Y = (int) Callmsg.inargs [1];

Calculator Calc = Calculator.createInstance ();

Int results = Calc.Add (x, y);

Return New ReturnMessage (Result, NULL, 0, NULL, CALLMSG);

//

// iMethodCallMessage Callmsg = MSG as IMETHODCALLMESSAGE;

// iMessage Returnmsg = RemotingServices.executeMessage (Target, Callmsg); // Return ReturnMsg;

}

....

....

Public Static Calculator CreateInstance ()

{

Calculator realcalculator = new calculator ();

Realproxy realproxy = new myRealProxy (realcalculator);

Object transparentProxy = realproxy.getTransparentProxy ();

Return (Calculator) TransparentProxy;

}

....

At this point, the running test is failed, because INVOKE calls int result = Calc.Add (x, y); actually only via Invoke, so a dead cycle,

RemotingServices.executeMessage does not have problems

>> Go back the head to carefully observe the above code, you can find that the execution of the truly real object (target) method is an ExecuteMessage () that occurs in call remotingservices.

The time of the method. Before it, we can obtain (or even modifying) all information calls (already the pre-processing of the AOP); in it

After we can obtain (or even modify) all information returned by ReturnMsg (also the basic-processing of the AOP basic operation!

>> [2004-02-16 12:34:56] Calculator.Add (3, 5) - (37ns) -> 8

Traversing parameters To access the iMessage MSG, if the interface change of Calculator.Add, such as adding a parameter, then the code of the log log is not working?

At the actual operation, you have to do a different action with the defined business logic, the business logic may be very complicated. For example, you borrow money to me, borrow a piece of money, I pretend to give you refreshing, borrow 10 yuan

, I want to find a book, borrow 100 pieces, I secretly looked at it, you have borrowed a coy in 10 years ago, more than 100 pieces, I also ask MM, after borrowing money, according to the money according to the money different

Sets different tip strategies. . These logic may change frequently

PRE-Processing / Post-Processing dutiful chain, is it still not convenient?

If some components just want to use Calculator in a normal way?

# 回: a Taste of aop from Solving Problems with OOP AND Design Patterns (Part II) 2/25/2004 2:16 PM by

Kain

Internal mechanism to .NET you can refer to MSDN

In fact, I mean, I want to learn through your article.

How to use AOP methods to discover, solve practical problems.

# 回: a Taste of aop from Solving Problems with OOP AND Design Patterns (Part II) 2/25/2004 10:57 PM By

Kaneboy

Sorry, I am sorry, I will pass this article tonight.

I feel:

1. Remember that there is a place behind that this is to use a complex method to explain the simple problem, objection, this article writes deeply, the principle is clear. 2, the return value of the syncprocessMessage () of MessagesinkBase should be the iMessage type.

# 回: a taste of aop from Solving Problems with OOP and Design Patterns (Part II) 2/25/2004 11:07 PM By

Flier

Very nice article, can be said to have a well-used simulation for AOP semantics on existing tools provided in BCL. However, the disadvantage is also very obvious compared to the development of the Java platform. 1. Not transparent; 2. Lack of simpleness; 3. Good efficiency.

Although this REALPROXY is known as the transparent agent, it is actually as you said, and its transparency is only limited to the one-way transparent transparency of ordinary methods. Therefore, it is necessary to implement the construction of the constructor, and the takeover of the object method is called within the object method, and other specific modes are required. On the other hand, it has increased the work, and on the other hand, it limits its applicable range (for example, it is not suitable for the type provided by others).

And simpleness is another important aspect. It is probably possible because the article is only given an example and does not consider too many simplicity and flexibility. Personally think that the dynamic adjustment mechanism based on attributes and external XML configuration files is indispensable, otherwise flexibility is greatly reduced. This needs to be adjusted to the current hard-coded implementation.

Finally, there is also an efficient loss. I have seen the relevant implementation in Rotor, the code efficiency of constructing the transparent agent is still very high, directly through the VTBL in the VM; But the price of the calling method will not be too big, first to encapsulate to an iMethodCallMessage, after entering It has to be called the stack through the StackBuildsink constructed, but it has to be sealed and removed. If this complex cut into business or security is acceptable, the cost of the ordinary such as write logs is too large.

All in all, individuals believe that this Remoting-based implementation can be simulated. I really want to use a large-scale use, or I have to develop .NET AOP Native implementation. After all, .NET provides powerful tools such as Reflection.emit, the starting point is higher than Java.

I probably refused to look at the realization of loom.net, and he actually constructed a lack of transparent agent using EMIT, which can solve some problems in simpleness and efficiency. But if you really want to completely solve, I still tend to use the implementation of Method Proxy, although I have some Dirty with UNSAFE CODE.

# 回: a taste of aop from Solving Problems with OOP and Design Patterns (Part II) 2/25/2004 11:35 PM By

Kaneboy

Just in the computer, I actually wrote a complete implementation code, then I would like to express my feelings:

3, personal feelings, not very suitable with ready-made iMessagesink interface, because it may be blurred conceptually. I feel like a similar thing that is defined, such as "IaopHandler", may be better:

Public Interface IaopHandler

{

Iaophandler nexthandler {get;}

IMeTHODCALLMESSAGE MSG;

}

Like the function, I feel that this name can react more.

Corresponding, additional classes are also renamed such as TerminatorHandler, ChainHandlerProxy ...

# 回: a Taste of aop from Solving Problems with OOP and Design Patterns (Part II) 2/26/2004 12:24 AM BYJOHN_MASEN

I just read the article, I used VB.NET to rewrite the sample code. Added code for implementing the SOA function through properties. For SOA through properties, I recommend that the SOA service wrapper is implemented, because all attribute efficiency is slower by reflection enumeration (all attribute object instances), and do not know which properties are used for SOA Which is the user's own properties, of course, you can use the Type.GetInterface scanning interface to find, but the efficiency is indeed a problem, you know that this thing happens when you call. Example:

Public Sub foo ()

'Do Something

End Sub [Recommended]

Public Sub foo ()

'Do Something

End Sub [Not recommended]

Furthermore, I found that it seems to be better through the SOA template, such as such code.

public sub foo ()

'Do Something

End Sub

The advantage of using the template is simple, and the template can be placed in the configuration file, the maintenance is simple, and the modification is easy. And in the template, different ways can be returned to different SOaservice configuration data, such as the object constructor, preferably use a separate configuration data section.

There is also a problem because the requesting SOA service has already been indicated in the properties. If you need to replace in actual use, you need to override SOaserviceFactory or recompile the code (this seems not realistic). In order to avoid implementing a strong type of service request, you can be implemented by requesting the SOA interface. SOaserviceFactory returns an instance by retrieving the already registered interface implementation. This can easily replace the SOA service class, even if new things are developed by other companies, it is easy to achieve your SOA interface, and it is easy to pass by Adapter. Soaservice can be registered as a Windows service, all clients do not have to write their own profiles, which is useful in engineering developed by many subsystems. Example:

definition:

Public Class Soaattribute

Public SUB (Paramarray ServiceInterface () AS TYPE

......

End Sub

END CLASS

-------------------------------------

use:

Public Sub foo ()

'Do Something

End Sub

Of course, the above method can also be used in conjunction with SOATEMPLATE.

About SOA how to use, because in the business process of the company, usually a business operation will correspond to an object call chain, so general, there is no need to enable the same SOA function to each object call, which increases the amount of code, and Use is also very inconvenient. Imagine, you have to add a lot of the same SOA properties in front of every method you write, it is not very troublesome. To simplify the operation, we can set the SOA template on the root object, and Proxy puts the SOaservice instance in the context of the object instance (derived from System.ContextBoundObject). Objects can avoid inheriting the SOA service properties by overwriting , or does not default to the SOA service properties by default. It is more troublesome that System.ContextBoundObject is considered to be internal objects by Microsoft, and does not provide documentation. To explore it takes a little time. Of course, you can also use the data slot, although this is relatively less than the habit of this Oo Freak :). Another way is to join the context object support in ObjectFactory, injecting the SOA context during initialization, but this requires that the object is derived from the specified object (such as soaframework.contextBoundObject), huh, huh. I think here, I will discuss it later :)

PS: [To the landlord: Mail I have already sent it. ]

# 回 t t o 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2

John_masen

Halo, write AOP as SOA.

# 回 t t o o 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2

John_masen

By the way, the previous article has a bad way.

SoatraceService and SoaperformenceTraceService are not the relationship between base classes and derived classes.

It should be written as SoaloggerService and SoaPerformencetraceService.

# 回 t t o f 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2

JGTM'2004 [MVP]

@Microhelper:

It's really flaming gold! It seems that I should declare it earlier, all the code is schematic, not guaranteed to copy paste, or understand the content in the text, I have written it independently - you see, the code when I write the article is not from vs. Net is copying it!嘿嘿 ;-)

When the text is to lead the remoteservices.executeMessage () method, there is indeed the intermediate state you said, I think it should be that I sent a sentence, I have changed into a question, prompting the reader The transformation has not been completed. I really want to thank you for your serious practice, and I believe that you must learn more from this literary! :)

>> If the interface change of Calculator.Add (), if you add a parameter, then the code of the log log is not working?

I estimate that you are, the more you don't be patient, and you blame my article too long (should be cut in 45 minutes - a class). First, the code of the log log is written to the reader, if your code rely on the number of parameters or, then, of course, you will appear. But I want to write, I will still go to enumerate the iMethodMessage.inargs array, so I don't have any questions you said? As follows: arraylist argstringlist = new arraylist ();

Foreach (Object Arg in Callmsg.inargs)

{

argstringlist.append (arg.toString ());

}

String [] argstrings = (string []) argstringlist.toArray (TypeOf (String));

String argliststring = string.join (",", argstrings);

Note that this code does not perform performance optimization, but it is easy to understand. In fact, think about it. Once the world enters the message, the method's Signature becomes unimportant, so the processing code for method messages is not very sensitive to the meaning of the method itself. This is exactly the problem to be solved by the AOP category. We have to transfer those non-functional code that is insensitive to object internal packages to the outside of the object, and can even reuse - the most easily understood is a code such as the method log.

Therefore, the problems you mention later are not a problem, because your business logic partial code is not part of this method, and reuses the part! But you want to independeate this part of the code from the original method code, how to solve this problem? Then please review the first part of this article, through the same method interface * and use the object factory to combine objects, your partial code can perform targeted processing in the semantic range of the method - non-embedded processing or this article The method is more suitable ("Behavior here" is not very clear about this question very clearly? :).

# 回: a Taste of aop from Solving Problems with OOP AND Design Patterns (Part II) 2/26/2004 12:03 PM by

JGTM'2004 [MVP]

@Kanaboy:

thank you for your feedback! Help me find a low-level mistake ... 愧! : '

In addition, your ideas about IAOPHANDAL are completely correct! In fact, I also repeatedly considering this matter many times, but in the end, I originally used the IMessagesink interface inside. Reason: First, this interface is a very important basic interface in .NET Remoting, familiar with .NET Remoting friends should be unfamiliar with him (and even if you don't know it, you will also develop in the future. Or less deal with it); second, compared to aophandler, it only has more support for asynchronous method messaging, should not understand the essence of the readers to have too much impact; third, I will next In the article, it is necessary to use the mechanism provided by this interface when context property is spent, so it is also buried a film, which also makes it written in another environment after IMESSAGESINK, and I hope that the brothers can understand even. Carefully. :-)

# 回: a Taste of aop from Solving Problems with OOP AND Design Patterns (Part II) 2/26/2004 12:57 PM Byjgtm'2004 [MVP]

@flier:

thank you for your feedback! The three problems you mention are indeed a few questions that this article tells the problem of solving the problem (but in the next text, I will continue to introduce .NET can solve the first two problems) . Here, I will explain it in detail on these issues.

In fact, the RP / TP mechanism is a touched constructor method (iMessageCallMessage / IconstructionReturnMallMessage / IconstructionReturnMessage), and this IACTIVATOR is still very clever, flexible! However, from the method of this article, only the new instruction is taken, it is possible to intercept the constructor method, and if this mechanism is used for all objects, it is bound to have a large overall impact on local object performance, so .NET / CLR only provides this support based on the type based on ContextBoundObject, and this is the core topic you want to explore in the next text. As for the types of ways to be intercepted on others, this may involve more problems: security, efficiency, etc. ... so CLR just provides a Profiler API at the level of COM, but the purpose is obviously not Solve the problem to be solved by AOP. As for the internal call within the object method, the current default mechanism is not supported (on the one hand is the reason for efficiency, the one hand is probably the inevitable result of this design), but I am studying this problem, see if there is any ideal Solution (RealProxy constructor provides an intPtr type Stub, which may be a problematic breakthrough).

As for the simpleness, I originally want to write to the article, but I thought I thought I would like to tell the basic principles first, and I will give the whole picture in the next article. In fact, in the practical application of our project, the mechanism that combines custom attributes and external configuration files provides a flexibility in the deployment phase (for example, you can detect SINK, dynamically switch debug mode, Component Shield Permissions Management Decorator ..., etc.). I think, have the basic mechanisms introduced in the text, these flexibility extensions should naturally not be here (custom attributes can be obtained via iMethodMessage.MethodBase; and support for XML profiles is simple to quote system.IO/ System.xml is developed, and there is nothing to do with the basic mechanism).

About efficiency issues, the design of the mechanisms in the text is very related! Why have I always said that it is .NET Remoting Infrastructure instead of .NET INFRASTRUCTURE? It is because it is originally designed to build a .NET Remoting layer, and does not take into account the development of so-called AOP development (although Remoting itself is an AOP: object position transparency) - and Remoting itself's performance overhead makes RP / TP's overhead is negligible (of course, for local objects or must be considered, I think this is why Microsoft has not officially mentioned the reason for the use of this mechanism to support AOP development. I have browsed a lot of online articles and found some clues. For example, after I have learned this mechanism, Com Interop should also build this basic architecture (using the transparent agent to forward the interface to the COM object)! actually not! Microsoft CLR is also said to be said because the CLR about the development of COM Interop is preceded on the .NET Remoting subsystem on the timeline, so it does not use RP / TP mechanism - and now, if it can be merged It is perfect to this mechanism, and more critical is that if Com Interop is on the RP / TP mechanism, Microsoft is bound to make greater investment in performance issues in this level (there is evidence that there is quite) Optimizable points provide a shortcut for local objects to achieve performance), so that it can be applied to non-Remoting locals, then this dead should not exist. However, history is history, we can only look forward to the future. It is said that this level of performance optimization of local objects will be improved in the performance of local objects in the future CLR implementation! Let us wait and see. So, the call of the brother is actually the software development, designer's call for enterprise-level applications, designers, hopes .NET can become a perfect platform for large, efficient, enterprise-level applications development development. - And support for AOP mechanisms Native is just one of the important links. We are also pleased to see that there will be major supplements to the .NET platform in 2004, which will be a good year of the monkey worth looking forward to! :)

BTW: Your blog wrote a great, I have already told! :-)

# 回: a Taste of aop from Solving Problems with OOP and Design Patterns (Part II) 2/26/2004 1:03 PM By

JGTM'2004 [MVP]

@John_Masen:

Thoughts are right! Such as Mu Chunfeng! Welcome to continue to comment on related questions! :)

PS: Email, discuss with you later!

# 回: a taste of aop from Solving Problems with OOP AND Design Patterns (Part II) 2/28/2004 1:13 AM BY

John_masen

I accidentally saw the CallContext object today, and it is estimated that this thing may be able to send it.

Hey, the TMD project is too hurried, and the April 1 is going to go online now to order the demand. Programmers in state-owned enterprises are not people!

# Unit Testing with .NET QUIZ: Adaptable Mock Objects? 3/2/2004 9:10 PM by

JGTM'2004 .NET Blog

# DynamicPorxy for .NET 3/26/2004 12:27 PM by

HBifts

DynamicPorxy for .NET

# 回: a taste of aop from Solving Problems with OOP and Design Patterns (Part II) 3/29/2004 9:02 PM By

JGTM'2004 [MVP]

@ Your AOP article I have seen three times, now I understand most of the ideas inside. But still some don't understand, I hope I can give you a point.

ChainedProxy.AppendsinkType (TypeOf (mymessagesink1));

ChainedProxy.AppendsinkType (TypeOf (MyMessagesink2);

There is no implementation method in myMessagesink1 and MyMessagesink1 and MyMessagesink2 in the above code. I think I can't think of it for a long time. Can I send me an example, so let me understand how this step is achieved, thank you!

reply:

Note that in the AppendsinkType method, we use the .NET's Activator to dynamically construct a given object instance while incoming a constructor representing NEXTSINK. That is to say, the type we give in the appendsinktype method should have a constructor that can accept iMessageSink as NextSink. Note that we convert instances of constructive success to MessageSinkBase, so you can only get your message processor from this class. For example, what is the easiest thing is not done:

Public class mymessagesink: MessagesinkBase

{

Public mymessagesink (iMessagesink NextSink): base (nextsink) {}

Public override iMessage SyncProcessMessage (IMESSAGE MSG)

{

Return nextsink.syncProcessMessage (MSG);

}

}

Based on this, you can expand your own message processing logic very simple.

# DynamicPorxy for .NET 4/5/2004 2:59 PM by

HBifts

DynamicPorxy for .NET

# 关于用 效用 效用 效用 效用 的 使用 使用

Marshine

Againing the views of JGTM, in fact, from the current application, AOP still acts on a coarse particle size object, a COM component or Remoting object, so the efficiency of the access and the efficiency of the ContexTboundObject object, the performance impact of RP / TP is acceptable.

转载请注明原文地址:https://www.9cbs.com/read-16484.html

New Post(0)