Three Implementations of AOP in.NET

Keywords: Programming

Three Implementations of AOP in.NET

Preface

Has been busy with the code, rare time, study the next AOP, share with you, also easy to view later. ()~*
Because the IOC container integrated in. NET CORE is Castle, Autofac is commonly used everyday, so I only studied the default implementation of. NET Emoting, Castle and Autofac. Castle has two plug-ins, Castle.Windsor (IOC container) and Castle.Core (core). Autofac's interceptor is the dynamic proxy of Castle.Core.

Basic concepts

AOP

AOP(Aspect Oriented Programming): Aspect Oriented Programming is the continuation of OOP, which is used to add functions dynamically without modifying the code, separating core logic from non-core logic. Logging is one of the most common usage scenarios of AOP.

IOC and DI

DI(Dependency Injection) dependency injection is actually an implementation of IOC (Controlled Flip). It is called dependency injection because the dependency relationship between the caller and the callee is injected through a third party, which is usually called IOC container. IOC is a kind of idea. The principle of inversion of dependence advocates that programs should rely on abstraction rather than on concrete implementation in order to reduce coupling. The interface that controls the implementation is usually the caller. There is still a dependency between the caller and the concrete implementation. Now, the idea of IOC is to give this control to a third party. The reason for this is that the implementation of dynamic proxy often relies on IOC containers.

Ways of realization

AOP interceptors can be implemented in two ways: dynamic proxy and static proxy.

Dynamic Agent:

It is the dynamic addition of entry points in the running of programs, which is the reason why IOC containers are usually needed.
Advantages and disadvantages: Compared with static proxy, efficiency is lower, but flexibility is strong, and no additional compilation is required.
The three ways we talk about are all implemented by dynamic agents.

Static proxy:

It is inserted in the pre-compiler stage of the program.
Advantages and disadvantages: Compared with dynamic proxy, performance is higher, but flexibility is poor, and additional compilation is required.

Remoting implementation

  1. Namespaces to be referenced
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Proxies;
  1. Because the implementation is relatively simple, I pasted all the code below.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Proxies;
using System.Text;
using System.Threading.Tasks;

/// <summary>
/// Default implementation (Remoting)
/// </summary>
namespace DefaultDemo
{

    class Program
    {
        static void Main(string[] args)
        {
            var per = new Proxy<King>(new King()).GetTransparentProxy() as King;
            if (per != null)
            {
                var str = per.RuleTheCastle("fffff");
            }
            Console.ReadKey();
        }
    }


    /// <summary>
    /// Basic types
    /// </summary>
    class King : MarshalByRefObject
    {
        public string RuleTheCastle(string str)
        {
            str = "hello word," + str;
            return str;
        }
    }


    public class Proxy<T> : RealProxy where T : new()
    {
        private object _obj;
        public Proxy(object obj)
            : base(typeof(T))
        {
            _obj = obj;
        }
        public override IMessage Invoke(IMessage msg)
        {
            IDictionary oProperties = msg.Properties;

            object oMethodName = null;
            if (oProperties.Contains("__MethodName"))
            {
                oMethodName = oProperties["__MethodName"];
            }
            Console.WriteLine("Method name:{0}", oMethodName);

            //Participation
            object[] oArguments;
            if (oProperties.Contains("__Args"))
            {
                oArguments = oProperties["__Args"] as object[];
            }
            else
            {
                oArguments = new object[0];
            }
            foreach (var oArgument in oArguments)
            {
                Console.WriteLine("Participation:{0}", oArgument);
            }


            //Invocation and parameterization
            object oReturnValue = ((IMethodCallMessage)msg).MethodBase.Invoke(_obj, oArguments);
            Console.WriteLine("Ginseng production:{0}", oReturnValue);

            return new ReturnMessage(oReturnValue, null, 0, null, null);
        }
    }

}

Castle implementation

  1. Install the Castle.Windsor package in NuGet Manager

    The Castle.Windsor and Castle.Core class libraries are automatically referenced when the installation is complete
  2. Reference to the corresponding namespace
using Castle.Core;
using Castle.DynamicProxy;
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;

Implementation of Dependency Injection

  1. Add an abstract interface and its implementation class
	public interface IKing
    {
        string RuleTheCastle(string name);
    }


    class King : IKing
    {
        public string Name { get; set; }

        public int Age { get; set; }

        public string RuleTheCastle(string name)
        {
            Console.WriteLine("Method executed");
            return "Hello Word," + name;
        }
    }

2. To add an installation class Repositories Installer, you need to inherit the IWindsor Installer interface and register components in it.

    public class RepositoriesInstaller : IWindsorInstaller
    {
        public void Install(IWindsorContainer container, IConfigurationStore store)
        {
            container.Register(
                Component.For<IKing>().ImplementedBy<King>().LifestyleSingleton()
                );
        }
    }
  1. Instantiate a container and run the installer so that they can register components in the container
	IWindsorContainer container = new WindsorContainer();

    container.Install(new RepositoriesInstaller());
  1. Get component instances, dependency injection
	var king = container.Resolve<IKing>();
	string ret = king.RuleTheCastle("tzj");
  1. Release IOC container
	container.Dispose();

Adding interceptors

  1. Declare a log interceptor class LoggingInterceptor and let him inherit the IInterceptor interface
 public class LoggingInterceptor : IInterceptor
    {
        public void Intercept(IInvocation invocation)
        {
            try
            {
                //type
                var type = invocation.TargetType;

                //object
                var oObject = invocation.InvocationTarget;

                //Method
                string strMethodName = invocation.Method.Name;
                Console.WriteLine("The method invoked is:" + strMethodName);

                //Participation
                var oArguments = invocation.Arguments;
                if (oArguments != null && oArguments.Length > 0)
                {
                    for (int i = 0; i < oArguments.Length; i++)
                    {
                        Console.WriteLine("Participation{0}:{1}", i, oArguments[i]);
                    }

                }

                //Execute this method, formally invoke the method
                //Access before execution
                //After successful execution, parameters are available
                invocation.Proceed();

                //Output parameters and ref can only be achieved by comparing them.

                //Ginseng production
                var oReturnValue = invocation.ReturnValue;
                Console.WriteLine("Participants:" + oReturnValue);
            }
            catch (Exception ex)
            {
                //Whether it's an error in the intercepted method or an error in the intercepted method, it's going to be here.
                Console.WriteLine("error message:" + ex.ToString());
            }
        }
    }

2. To add the corresponding interceptor property to the implementation class, it is important to note that the implementation class must be controlled by the IOC container.

[Interceptor(typeof(LoggingInterceptor))]
  1. The interceptor will also be registered in the container
 Component.For<LoggingInterceptor>()

That's done.

Complete code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Castle.Core;
using Castle.DynamicProxy;
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;

namespace CastleDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            IWindsorContainer container = new WindsorContainer();

            container.Install(new RepositoriesInstaller());

            var king = container.Resolve<IKing>();

            string ret = king.RuleTheCastle("tzj");
            Console.WriteLine(ret);

            container.Dispose();

            Console.ReadKey();
        }
    }

    public interface IKing
    {
        string RuleTheCastle(string name);
    }

    //The class of the section must be controlled by the container.
    [Interceptor(typeof(LoggingInterceptor))]
    class King : IKing
    {
        public string Name { get; set; }

        public int Age { get; set; }

        public string RuleTheCastle(string name)
        {
            Console.WriteLine("Method executed");
            return "Hello Word," + name;
        }
    }

    public class RepositoriesInstaller : IWindsorInstaller
    {
        public void Install(IWindsorContainer container, IConfigurationStore store)
        {
            container.Register(
                Component.For<LoggingInterceptor>(),
                Component.For<IKing>().ImplementedBy<King>().LifestyleSingleton()
                );
        }
    }


    public class LoggingInterceptor : IInterceptor
    {
        public void Intercept(IInvocation invocation)
        {
            try
            {
                //type
                var type = invocation.TargetType;

                //object
                var oObject = invocation.InvocationTarget;

                //Method
                string strMethodName = invocation.Method.Name;
                Console.WriteLine("The method invoked is:" + strMethodName);

                //Participation
                var oArguments = invocation.Arguments;
                if (oArguments != null && oArguments.Length > 0)
                {
                    for (int i = 0; i < oArguments.Length; i++)
                    {
                        Console.WriteLine("Participation{0}:{1}", i, oArguments[i]);
                    }

                }

                //Execute this method, formally invoke the method
                //Access before execution
                //After successful execution, parameters are available
                invocation.Proceed();

                //Output parameters and ref can only be achieved by comparing them.

                //Ginseng production
                var oReturnValue = invocation.ReturnValue;
                Console.WriteLine("Participants:" + oReturnValue);
            }
            catch (Exception ex)
            {
                //Whether it's an error in the intercepted method or an error in the intercepted method, it's going to be here.
                Console.WriteLine("error message:" + ex.ToString());
            }
        }
    }
}

Implementation of Autofac

  1. Install the Autofac.Extras.DynamicProxy package in NuGet Manager

    Programs are automatically referenced
  2. Referencing the required namespace
using Autofac;
using Autofac.Extras.DynamicProxy;
using Castle.DynamicProxy;

Implementation of Dependency Injection

This one is similar to the one above. Paste the code directly.

private static IContainer Container { get; set; }
        static void Main(string[] args)
        {
            var builder = new ContainerBuilder();
            
            builder.RegisterType<King>().As<IKing>();

            Container = builder.Build();

            using (var scope = Container.BeginLifetimeScope())
            {
                var writer = scope.Resolve<IKing>();

                writer.RuleTheCastle("aaa");
            }

            Console.Read();
        }

    }

    public interface IKing
    {
        string RuleTheCastle(string name);
    }

    public class King : IKing
    {
        public string Name { get; set; }

        public int Age { get; set; }

        public string RuleTheCastle(string name)
        {
            Console.WriteLine("Method executed");
            return "Hello Word," + name;
        }

    }

Adding interceptors

Interceptors are similar

  1. Add interceptor attributes
[Intercept(typeof(LoggingInterceptor))]
  1. Enable proxies when registering components

Enabling class proxy requires that the permissions of the faceted class be public and that the method is virtual

builder.RegisterType<King>().As<IKing>().EnableClassInterceptors();

Enabling Interface Agent

builder.RegisterType<King>().As<IKing>().EnableInterfaceInterceptors();
  1. The interceptor also needs to be injected into the container.
builder.RegisterType<LoggingInterceptor>();

Complete code

using Autofac;
using Autofac.Extras.DynamicProxy;
using Castle.DynamicProxy;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AutofacDemo
{
    class Program
    {
        private static IContainer Container { get; set; }
        static void Main(string[] args)
        {
            var builder = new ContainerBuilder();

            builder.RegisterType<LoggingInterceptor>();

            //EnableClassInterceptors Enables Class Agent Requirements Method is virtual
            //builder.RegisterType<King>().As<IKing>().EnableClassInterceptors();

            //Enable Interface Interceptors Enables Interface Agents
            builder.RegisterType<King>().As<IKing>().EnableInterfaceInterceptors();

            Container = builder.Build();

            using (var scope = Container.BeginLifetimeScope())
            {
                var writer = scope.Resolve<IKing>();

                writer.RuleTheCastle("aaa");
            }

            Console.Read();
        }

    }

    public interface IKing
    {
        string RuleTheCastle(string name);
    }

    //The class of the section must be controlled by the container.
    [Intercept(typeof(LoggingInterceptor))]
    public class King : IKing
    {
        public string Name { get; set; }

        public int Age { get; set; }

        public string RuleTheCastle(string name)
        {
            Console.WriteLine("Method executed");
            return "Hello Word," + name;
        }

    }

    public class LoggingInterceptor : IInterceptor
    {
        public void Intercept(IInvocation invocation)
        {
            try
            {
                //type
                var type = invocation.TargetType;

                //object
                var oObject = invocation.InvocationTarget;

                //Method
                string strMethodName = invocation.Method.Name;
                Console.WriteLine("The method invoked is:" + strMethodName);

                //Participation
                var oArguments = invocation.Arguments;
                if (oArguments != null && oArguments.Length > 0)
                {
                    for (int i = 0; i < oArguments.Length; i++)
                    {
                        Console.WriteLine("Participation{0}:{1}", i, oArguments[i]);
                    }

                }

                //Execute this method, formally invoke the method
                //Access before execution
                //After successful execution, parameters are available
                invocation.Proceed();

                //Output parameters and ref can only be achieved by comparing them.


                //Ginseng production
                var oReturnValue = invocation.ReturnValue;
                Console.WriteLine("Participants:" + oReturnValue);


            }
            catch (Exception ex)
            {
                //Whether it's an error in the intercepted method or an error in the intercepted method, it's going to be here.
                Console.WriteLine("error message:" + ex.ToString());
            }
        }
    }
}

Epilogue

Some parts of the article are not so detailed, but most of the notes are, I will be sorry if I have time to add more details. (_)
For the first time, I wrote a blog. If there are any problems, I would like to ask the big guys to give me advice. ()

Posted by FangerZero on Thu, 29 Aug 2019 02:44:22 -0700