Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Example Analysis of .NET context-oriented AOP Architecture pattern

2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article introduces the example analysis of .NET context-oriented and AOP architecture pattern. The content is very detailed. Interested friends can use it for reference. I hope it will be helpful to you.

1. Analysis of contextual Context and aspect-oriented programming AOP Model

In my article, .NET context-oriented AOP Architectural pattern (Overview), we have a general idea of how context assists in the management of objects at runtime. In many cases, we urgently need to control objects within a certain logical range when running, and when necessary, we can let them reflect the concept of centralization, such as people, vehicles, animals and so on. Context is closely related to AOP. Context represents the scope of logical abstraction and AOP describes how to control within this logical scope. In fact, both of them are design patterns outside the design pattern, and have nothing to do with the specific technical implementation.

So what is the logical concept of Context and AOP? It seems that only pictures can best express people's understanding. The following figure shows a conceptual model of close cooperation between Context and AOP.

Context figure: 1

Objects are managed in context at run time, and all managed objects can be easily obtained in context, which paves the way for later AOP. Only after the Context starts, can the claw of the AOP manager reach into the runtime of the object to establish a communication relationship with the connection point of the AOP, and can the object face the aspect successfully.

In the model diagram, the Context center is responsible for managing all Object, while Object shows that multifaceted attributes and multifaceted behaviors will include multifaceted characteristics, and the runtime behavior of objects will be controlled by connecting with the AOP manager.

AOP figure: 2

Transfer control to the "face" implemented by the customer as much as possible through a reasonable AOP abstract interface of the contract object. For example, when calling a certain kind of method, you may need to control all the execution rights of the method as much as possible. Therefore, it is very difficult to define the concrete abstraction.

In the figure above, we connect with the "face" of the object through the AOP core manager, and make dynamic calls according to the specific "face" type, such as attributes, which may need to be rendered according to the business link at run time, dynamic binding, and so on, all of which can be implemented through AOP. For methods, you may need to record the current client call information in the SOA-oriented architecture, as well as some unique business authentication, and so on. Different "faces" require logical abstraction, which is also in line with the principle of object-oriented design. Many times we need to "agree" instead of providing extension mechanisms as much as possible. the more extension points, the more complex the system is, and it is relatively difficult to control.

two。 Implementation of context

We roughly analyze the context and AOP model, and the model diagram also vividly reflects the main working principles of context and AOP. Let's build a physical code model through specific analysis.

Object-oriented is the physical modeling of the abstract logical model, whether it can really reflect the model, we need to analyze carefully.

2.1 context Model implementation

We abstract the context model into a code model. So we need an object that logically represents the context, which I call ContextRuntime here, and the life cycle of the context is controlled in the code snippet of the Using () statement, so ContextRuntime needs to implement the Idisposable interface for the Using () statement to work.

Using (ContextModule.ContextRuntime.BeginContextRuntime ()) {/ / Lifecycle of context}

Why design the lifecycle of the context in this way? this design is the most flexible. Entrances to many of Microsoft's internal context lifecycles are also designed in this way, the most classic of which is System.Transaction transaction processing.

When the Using () code snippet ends, we need to release the current context instance, so we need to complete the implementation of the IDisposable interface.

Void IDisposable.Dispose () {_ currentContextRuntime = null;}

_ currentContextRuntime represents the global private object of the context object instance.

Because the entry point of the multithreaded application framework is beyond our control, we need to use thread local storage to solve the problem of thread unsafe access when using context mode.

[ThreadStatic]

Private static ContextRuntime _ currentContextRuntime

Let's take a look at all the ContextRuntime object code:

View Code / * author: in-depth training * blog: http://wangqingpei557.blog.51cto.com/ * * / using System; using System.Collections.Generic; using System.Text; namespace ContextModule {/ context runtime environment. / / context logic runtime environment, the functions in the environment can be attached. / public class ContextRuntime: IDisposable {# region IDisposable member void IDisposable.Dispose () {_ currentContextRuntime = null;} # endregion protected ContextRuntime () {} private DateTime _ initTime = DateTime.Now / get the time when the context was created at runtime / public virtual DateTime InitTime {get {return _ initTime;}} private Dictionary _ runTimeResource = new Dictionary (); private ContextFilterHandlerMap _ filterMap = new ContextFilterHandlerMap () / get the method and class filter mapping table in the context / public ContextFilterHandlerMap FilterMap {get {return _ filterMap;}} private Guid _ initPrimaryKey = Guid.NewGuid () / get the unique identity of the runtime creation context / public virtual Guid InitPrimaryKey {get {return _ initPrimaryKey }} / get data in the context sharing area / data Key / object data object public virtual object GetValue (object key) {return _ runTimeResource [key] } / set the data in the context sharing area / data Key / the data object public virtual void SetValue (object key, object value) {_ runTimeResource{ _ runTimeResource] = value to be set } [ThreadStatic] private static ContextRuntime _ currentContextRuntime; / get the current context runtime object. / public static ContextRuntime CurrentContextRuntime {get {return _ currentContextRuntime;}} / start runtime context / ContextRuntime public static ContextRuntime BeginContextRuntime () {/ / you can configure the parameters of the context runtime environment through the configuration file. This is just a simple simulation. _ currentContextRuntime = new ContextRuntime (); return _ currentContextRuntime;}

This is only for the implementation of the basic model prototype, and will not involve too many functions. The context is mainly opened in the current thread, and then maintained in the static object of multi-thread safe access, * is the stable release of the object.

2.2 context object binding implementation

With the context, how to make the object dynamically bind to the context at runtime. This requires determining whether the object is bound to the current context for management at the time of pre-coding.

Then we need to make an abstraction of the objects used by the customer, so that all the objects that need to be bound implement the abstraction that we define at a high level. Here I will be named ContextModuleBaseObject, because we need to provide AOP with the connection point of the "face" of the object, so we need to reflect to get some basic information of the bound object at run time, such as: the "face" of the attribute, the "face" of the behavior, including the "face" of the object itself, these faces we need to establish their correspondence in order to make the following AOP work.

So we define ContextModuleBaseObject as a generic class and need to be constrained by Class. Once the bound object enters the lifecycle management of context at runtime, it needs to be flexibly represented as ContextRuntime object, so the design accords with the concept of treating context equally, and it is more convenient for ContextModuleBaseObject object to dynamically use the internal storage area of context at run time.

Here we need to inherit the ContextModuleBaseObject object from the ContextRuntime object. Using the classic decorator pattern, let the ContextModuleBaseObject object use the ContextRuntime behavior.

View Code / * author: in-depth training * blog: http://wangqingpei557.blog.51cto.com/ * * / using System; using System.Collections.Generic; using System.Text; using System.Reflection; namespace ContextModule {/ bind base classes up and down to force derived classes to bind to context. / / the policy construction of the logical context takes place here. / / managed context-bound object type, usually a ContextModuleBaseObject derived class. Public class ContextModuleBaseObject: ContextRuntime where T: class {/ the physical object instance of the context to which the current context binding object is bound. / / private ContextRuntime _ contextRunTime; public ContextModuleBaseObject () {if (typeof (T) .GetCustomAttributes (typeof (ContextEveningBoundAttribute), false)! = null) {_ IsEvening = true; return } / / previous static binding context if (ContextRuntime.CurrentContextRuntime = = null) throw new Exception ("the context failed to initialize, please check whether the ContextRuntime object is enabled in your code entry.") ; _ contextRunTime = ContextRuntime.CurrentContextRuntime; _ InitContextHandler (); construct the class filter and method filter mapping table for the context. / / private void _ InitContextHandler () where ChildType: class {/ / construct a class filter ContextOperationBaseAttribute [] classattr = typeof (ChildType) .GetCustomAttributes (typeof (ContextOperationBaseAttribute), false) as ContextOperationBaseAttribute []; if (classattr.Length > 0) {ContextOperationBaseAttribute joinoper = _ JoinOperation (classattr) _ contextRunTime.FilterMap.MapOperation (typeof (T). FullName, joinoper);} / / Constructor filter foreach (MethodInfo method in typeof (ChildType). GetMethods ()) {ContextOperationBaseAttribute [] methodattr = method.GetCustomAttributes (typeof (ContextOperationBaseAttribute), false) as ContextOperationBaseAttribute [] If (methodattr.Length operationarray [j + 1] .OperationSort) {ContextOperationBaseAttribute oper = operationarray [j]; operationarray [j] = operationarray [j + 1]; operationarray [j + 1] = oper } ContextOperationBaseAttribute opernext = operationarray [0]; for (int I = 1; I < operationarray.Length; iTunes +) {opernext.NextOperation = operationarray [I]; opernext = operationarray [I]; / / maintains a reference to the parent object of the current loop object. } return operationarray [0];} public MethodInfo GetMethodInfo (string methodname) {return this.GetType () .GetMethod (methodname);} public override Guid InitPrimaryKey {get {return _ contextRunTime.InitPrimaryKey }} public override DateTime InitTime {get {return _ contextRunTime.InitTime;}} public override object GetValue (object key) {return _ contextRunTime.GetValue (key) } public override void SetValue (object key, object value) {_ contextRunTime.SetValue (key, value);}

The main function of the ContextModuleBaseObject class is to dynamically add objects to the current context. Then do some auxiliary work for AOP, including caching the property metadata of classes, attributes, and behaviors. Here, only the property caching of behaviors is implemented. You can extend the functionality of AOP according to your needs, marking properties on the attributes of objects to make them work as well. The feature here is the specified interface published by AOP.

We'll leave the interpretation of the _ JoinOperation method later, which is a data structure. ContextOperationBaseAttribute

The type is strung into a linked list, allowing the execution of the method to pass through all ContextOperationBaseAttribute processing classes.

2.3 implementation of late binding of context objects

In order for the bound object to support late context binding, a feature is required as a representation.

View Code / * author: in-depth training * blog: http://wangqingpei557.blog.51cto.com/ * * / using System; using System.Collections.Generic; using System.Text; namespace ContextModule {/ determine whether the setting class needs to be dynamically bound to the context later. / / classes that use this feature will be context active, and the current context is determined only when it is used. / / [AttributeUsage (AttributeTargets.Class, AllowMultiple = false, Inherited = true)] public class ContextEveningBoundAttribute: Attribute {public ContextEveningBoundAttribute () {} private bool _ isEvening; / specifies whether the object requires a late dynamic binding context. / / public bool IsEvening {set {_ isEvening = value;} get {return _ isEvening;}}

Just to identify the late binding description. You can see this in the constructor of the ContextModuleBaseObject object.

View Code public ContextModuleBaseObject () {if (typeof (T) .GetCustomAttributes (typeof (ContextEveningBoundAttribute), false)! = null) {_ IsEvening = true; return } / / previous static binding context if (ContextRuntime.CurrentContextRuntime = = null) throw new Exception ("the context failed to initialize, please check whether the ContextRuntime object is enabled in your code entry.") ; _ contextRunTime = ContextRuntime.CurrentContextRuntime; _ InitContextHandler ();}

Now that we have implemented the dynamic binding of objects to the context, let's analyze how Context uses AOP to complete aspect-oriented programming.

Contract Design and implementation of object behavior in 2.4.AOP

In fact, the contract design here is the agreement for the "face" in AOP in figure 2.

The full name of AOP is aspect-oriented programming. Objects have multiple aspects at run time, but in. Net we habitually use Attribute to express this concept. Because you don't need to change any code to add features to any element of the object, you can dynamically rotate the elements in different business links or functional links to reflect the advantage of "aspect". Of course, there may be many kinds of specific implementations, which are done here.

It is agreed here that any "faces" that deal with object methods will be abstracted. Here I will name it ContextOperationBaseAttribute, which represents the base class of all features attached to the method, an abstraction of "faces".

Then different types of faces will have different operations, such as logging, computing performance, authentication security, they all have different behaviors and attributes. so here we also need to extract a top-level interface to deal with abstraction as the characteristics of the behavior class. Here I will name it IContextOperationHandler, which serves as a high-level dependency for uniform execution behavior features. In fact, it also reflects the principle of relying on inversion, relying on abstraction and not on concrete implementation.

The complete ContextOperationBaseAttribute class:

View Code / * author: in-depth training * blog: http://wangqingpei557.blog.51cto.com/ * * / using System; using System.Collections.Generic; using System.Text; namespace ContextModule {/ context operation action characterization base class. / / all filtering operations on classes and methods in context must inherit this class. / public abstract class ContextOperationBaseAttribute: Attribute, IContextOperationHandler {/ filter processing order, from small to large. / public int OperationSort {get; set;} / next filter operation class / internal ContextOperationBaseAttribute NextOperation {get; set } / start processing filter object / method return value type / / method wrapper / / method wrapper / / method ordered parameter / public virtual Result ResultAction (ContextMethodInfo actionmethod, params object [] paramarray) {object result = null If (! actionmethod.IsPost) {result = (this as IContextOperationHandler) .operation (actionmethod, paramarray); if (this.NextOperation! = null) return this.NextOperation.ResultAction (actionmethod, paramarray);} if (result! = null) return (Result) result Return default (Result);} public abstract object Operation (ContextMethodInfo contextmethod, params object [] paramarray);}}

As an abstract top-level class, you need to do the repetitive work of derived classes. A ResultAction generic method is implemented here, which is the entry point when the method of the bound object is called externally. But the specific implementation difference lies in the definition of the IContextOperationHandler interface.

Because there may be multiple properties of the behavior, a finished feature needs to end the entire call list and return a value. In the ResultAction virtual method, the call is made to the Operation method of the IContextOperationHandler interface, which will be implemented in the implementation of specific behavior characteristics, which in turn reflects the "template method" design pattern. Stipulate behavior in an abstract class and implement concrete in a derived class.

What's interesting here is that features are no longer the simple logos that people use to implement ORM. In fact, the real power of the feature is that it can be obtained dynamically at run time, thanks to .NET metadata. And dynamically instantiate and then use it as a normal object instance. This is an idea that many .NET programmers should not change.

ContextOperationBaseAttribute here describes another data structure, "one-way linked list". In order to implement the behavior of the bound object in the feature, we pass the method call to the implementation feature completely. So how to pass through the characteristics of multiple functions on the method, and can ensure the normal transmission and return of the data. There are two points we need to pay attention to, one is the order of the function of the feature, and the other is whether the execution of the method is completed. We have to take these two points into consideration, so in the ContextOperationBaseAttribute class, we use the public int OperationSort {get; set;} attribute to represent the execution order of the features, the characteristics of logging and computing performance, it is difficult for us to decide here, depending on the execution of the later program, for example, I want to record the log first and then execute the method.

So how do we concatenate ContextOperationBaseAttribute types? In ContextModuleBaseObject

When we construct a generic binding class, we will use ContextOperationBaseAttribute. The OperationSort property initializes the property handling linked list.

So how do we associate a specific object with a property? There may be multiple ContextOperationBaseAttribute implementations for a behavior. So here we need a data structure that satisfies the relationship between behavior and characteristics.

Here I define it as the ContextFilterHandlerMap class that inherits from the Dictionary generic dictionary class and uses KEY-VALUE to store the correspondence between behavior and ContextOperationBaseAttribute processing properties.

View Code / * author: in-depth training * blog: http://wangqingpei557.blog.51cto.com/ * * / using System; using System.Collections.Generic; using System.Text; namespace ContextModule {/ context-specific filter mapping table. / / any method in the context that requires context management is managed using a derived class of the ContextModule.ContextOperationBaseAttribute attribute. / / all feature management classes attached to methods and classes will be mapped to ContextModule.ContextFilterHandlerMap instances. / public class ContextFilterHandlerMap: Dictionary {public ContextFilterHandlerMap () {} / get the filter processing feature corresponding to the method / Mapping Key / ContextOperationBaseAttribute property instance public ContextOperationBaseAttribute MapOperation (string mapname) {return this [mapname] } / set the mapping between filter and specific method / Mapping Key / filter property base class ContextOperationBaseAttribute public void MapOperation (string mapname, ContextOperationBaseAttribute operationlist) {this.Add (mapname, operationlist);}

* you only need to provide IContextOperationHandler interface to realize the concatenation of methods and processing features.

View Code / * author: in-depth training * blog: http://wangqingpei557.blog.51cto.com/ * / using System; using System.Collections.Generic; using System.Text; using System.IO Namespace ContextModule {/ context operation management interface / public interface IContextOperationHandler {/ start context processing / CRL is currently executing the context method information. / / you can obtain the method details through the ContextMethodInfo instance. / / Parameter array object Operation (ContextMethodInfo contextmethod, params object [] paramarray);}}

By exposing the interface to the public, the client that implements the "face" is allowed to complete the execution of specific object methods. The ContextMethodInfo type is wrapper System.Reflection. MethodInfo method metadata, will be called inside the method here basically achieve AOP multi-faceted support for behavior, let's take a look at if dynamically cut into the method.

2.5. Implementation of dynamic entry

Calling all methods will be a headache. Because generally context-oriented and aspect-oriented, the writer controls the call to the method, which can be easily called implicitly through the background. However, there are three main ways to implement the entry call as a common method.

1): delegate implementation entry

The call to the method is accomplished by using System.Delegate dynamically derived types, but the delegate must be strongly typed for the method's signature, so it is difficult to achieve a general invocation entry.

2): reflection implementation entry (add a method to get the MethodInfo object in the OBJECT base class through the extension method, and use this method to obtain the information of the calling method)

Through the extension method to add an extension method to the System.Object to obtain the information of the calling method, and then reflect the dynamic call, this method is only more commonly used. But how the framework is used in .NET 2.0 extension method can not be implemented, here I am in the ContextModuleBaseObject base class to add a similar extension method. The binding object can easily get the MethodInfo object that calls the method.

3): dynamic compilation of * * (salute to abstraction, polymorphism)

The most * is the extension code generation provider, which derives a class in the object used for polymorphic transfer, allowing high-level calls to enter the derived class smoothly. But it's complicated.

This is used in the second way:

View Code / * author: in-depth training * blog: http://wangqingpei557.blog.51cto.com/ * * / using System; using System.Collections.Generic; using System.Text; using System.Reflection; namespace ContextModule {/ context-oriented operation class. / / A pair of context-initiated method calls need to be called through this base class to make our extension point use possible. / public static class ContextAction {/ makes method calls in a context-oriented environment. The information object MethodInfo of the calling context binding object type / / method return type / the calling context binding object instance / method is automatically obtained by the Oject.GetContextMethodInfo method. / / the ordered parameter collection of the method / the return instance public static ResultType PostMethod (PostObjectType post, MethodInfo method, params object [] paramarray) where PostObjectType specified by the ResultType generic type: ContextModuleBaseObject {_ LockPostObejctIsEveningBound (post); string key = string.Format ("{0}. {1}", method.DeclaringType.FullName, method.Name) If (! ContextRuntime.CurrentContextRuntime.FilterMap.ContainsKey (key)) {throw new Exception ("method {0}) is not managed by context." , key);} ContextMethodInfo contextmethod = new ContextMethodInfo (method, post); return ContextRuntime.CurrentContextRuntime.FilterMap [key] .ResultAction (contextmethod, paramarray);} / check whether the calling instance class belongs to late binding. / / specify the late binding context by using ContextModule.ContextEveningBound (IsEvening = true). / / private static void _ LockPostObejctIsEveningBound (PostObjectType post) where PostObjectType: ContextModuleBaseObject {ContextModuleBaseObject contextclass = post as ContextModuleBaseObject; if (contextclass._IsEvening) contextclass._EveningBoundChildClass ();}}

All calls are initiated using the PostMethod generic method. The _ LockPostObejctIsEveningBound private method is used to determine whether the current type is late-bound. If so, you need to cut into the base class and call the _ EveningBoundChildClass method to construct the linked list of the ContextOperationBaseAttribute type, and then call it directly through the header object. [copyright Wang Qingpei, please give your signature for reprint]

3. Instance context and static context

For instance context, there is also the concept of static context, so it is difficult to induce the logic of static objects, because static objects are difficult to abstract in object-oriented design. Static objects can only be forcibly pulled into the context by feature injection. But in the case of multithreading, it is indeed possible to study. All static objects are stored locally by thread, and the management of entity-like objects is mandatory.

4. Context-oriented domain model (DMM)

Context-based usage patterns can be used for the preliminary construction of the domain model, can be close to a large proportion of the structure in the domain, the logic of the business model can be summarized into a certain Context, and the modular carding of the business is also an implementation.

The business logic layer in a hierarchical architecture may need to add context management to control the business model at run time. Such as order processing, the model objects related to the order business process are grouped together. For example, user-related, it is really interesting to group the model objects related to user-managed business processes into one.

This is the end of the sample analysis of .NET context-oriented and AOP architecture patterns. I hope the above content can be of some help and learn more knowledge. If you think the article is good, you can share it for more people to see.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report