• <八>实现服务代理,利用特性自动封装服务路由


    上一节我们把服务路由改由客户端传入了,但是每次都要在客户端这里写命名空间啥的比较麻烦,这应该在写方法的时候就应该规定好。这时候特性就派上用场了。

    想要了解特性的使用的请参考这篇文章:【.net 深呼吸】自定义特性(Attribute)的实现与检索方法

    1、首先添加两个特性类,一个用于接口,一个用于方法

    namespace AidenGRPC.RPCBase.CommonAttribute
    {
        [AttributeUsage(AttributeTargets.Interface, Inherited = false, AllowMultiple = false)]
        public class ServiceRouteAttribute : Attribute
        {
            public ServiceRouteAttribute(string _namespace,string _classname)
            {
                NameSpace = _namespace;
                ClassName = _classname;
            }
    
            public string NameSpace { get; set; }
            public string ClassName { get; set; }
           
        }
    }
    namespace AidenGRPC.RPCBase.CommonAttribute
    {
        [AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
        public class ServerMethodAttribute : Attribute
        {
            public ServerMethodAttribute(string _methodname)
            {
                MethodName = _methodname;
            }
            public string MethodName { get; set; }
        }
    }

    2、添加一个存放接口的程序集,新增一个接口并添加上特性,绑定好此接口的实现类和实现方法名。

    namespace AidenGRPC.IModule
    {
        [ServiceRoute("AidenGRPC.Module", "SayHelleServer")]
        public interface ISayHelleServer
        {
            [ServerMethod("SayHello")]
            string SayHello(string name);
        }
    }

     3、接下来就是要解析这个接口的特性,并将解析完的特性添加到dictionary里面并作为参数直接调用服务端服务。

           那么在给接口的实例调用sayhello的时候自动反射调用服务端服务呢?Castle.DynamicProxy这个dll里提供了一种叫动态代理的东西。

      ProxyGenerator这个类实现了一个叫 CreateInterfaceProxyWithoutTarget的方法,这个方法需要传入一个实现IInterceptor接口的类。

           这样,只需要将接口的实现绑定成这个方法,就可以完成自动解析attribute的功能。

        public class ServicesProxy
        {
            private static ProxyGenerator generator = new ProxyGenerator();
            public static TInterface GetService<TInterface>(string ip, int port) where TInterface : class
            {
                return generator.CreateInterfaceProxyWithoutTarget<TInterface>(new GRPCInterceptor(ip, port));
            }
        }
    public class GRPCInterceptor : IInterceptor
        {
            public string Ip { get; set; }
            public int Port { get; set; }
            public GRPCInterceptor(string ip, int port)
            {
                Ip = ip;
                Port = port;
            }
            public void Intercept(IInvocation invocation)
            {
                Dictionary<string, string> dictionary = new Dictionary<string, string>();
                ServerMethodAttribute methodAttr = invocation.Method.GetCustomAttributes<ServerMethodAttribute>().FirstOrDefault<ServerMethodAttribute>();
                ServiceRouteAttribute routeAttr = invocation.Method.DeclaringType.GetCustomAttributes<ServiceRouteAttribute>().FirstOrDefault<ServiceRouteAttribute>();
                if (methodAttr != null)
                {
                    if (!string.IsNullOrWhiteSpace(methodAttr.MethodName))
                    {
                        dictionary.Add(ServicesRoute.METHODNAME, methodAttr.MethodName);
                    }
                }
                if (routeAttr != null)
                {
                    if (!string.IsNullOrWhiteSpace(routeAttr.NameSpace))
                    {
                        dictionary.Add(ServicesRoute.NAMESPACE, routeAttr.NameSpace);
                    }
                    if (!string.IsNullOrWhiteSpace(routeAttr.ClassName))
                    {
                        dictionary.Add(ServicesRoute.CLASSNAME, routeAttr.ClassName);
                    }
                }
                ParameterInfo[] parameters = invocation.Method.GetParameters();
                for (int i = 0; i < parameters.Length; i++)
                {
                    ParameterInfo parameterInfo = parameters[i];
                    if (!dictionary.ContainsKey(parameterInfo.Name))
                    {
                        dictionary.Add(parameterInfo.Name, invocation.Arguments[i].ToString());  //不完善,如果参数是个类,那么这里需要用转成json再添加
                    }
                    else
                    {
                        dictionary[parameterInfo.Name] = invocation.Arguments[i].ToString();
                    }
                }
                if (invocation.Method.ReturnType == typeof(void)))
                {
                    new Request(Ip, Port).Invoke(dictionary);
                    return;
                }
                GrpcResponse responseMsg = new Request(Ip, Port).Invoke(dictionary);
                invocation.ReturnValue = responseMsg.ResponseMsg;
            }
        }

    4、依赖注入,我们在客户端main函数里面直接注入一下,试试看效果。

      static void Main(string[] args)
            {
                var serviceProvider = new ServiceCollection()
                     .AddSingleton(typeof(ISayHelleServer), ServicesProxy.GetService<ISayHelleServer>("127.0.0.1", 30052))
                     .BuildServiceProvider();
                var server = serviceProvider.GetService<ISayHelleServer>();
                string rp = server.SayHello("Aiden");
                Console.WriteLine(rp);
                Console.WriteLine("Press any key to exit client...");
                Console.ReadKey();
            }

    5、运行试试看,如下图,能够走通,这样代理就完成了。

     

  • 相关阅读:
    caffe:使用C++来提取任意一张图片的特征(从内存读取数据)
    python:控制鼠标和键盘
    .dll 文件编写和使用
    python:打包成exe程序
    python:小乌龟turtle
    python:input()和raw_input()
    C++:哈希
    C++:线程(std::thread)
    GitHub:Git的使用
    链表
  • 原文地址:https://www.cnblogs.com/choii/p/14608975.html
Copyright © 2020-2023  润新知