<六>添加自定义服务模块寄宿到server中

由上一节可以看到我们每次新增加一个服务都需要添加一个proto文件,并且需要手动生成服务端和客户端的代码。

这样是不是很麻烦呢?那么可不可以定义一个公共的proto文件生成一个基础的方法,让所有的自定义方法都通过这个基础方法来执行自定义服务呢。

我们动手看看。

1、在上一节的基础上,在proto里面新增一个Invoke基础方法,定义两个公共参数。代码如下:

syntax="proto3";

package AidenGRPC.RPCBase;

service TestServer {
  rpc GetFeature(Point) returns (Feature) {}
  rpc Invoke(GrpcRequest) returns (GrpcResponse){}
  }

message GrpcRequest{
     string requestMsg=1;
 } 

 message GrpcResponse{
    string responseMsg=1;
 }


message Point {
int32 latitude = 1;
int32 longitude = 2;
}

message Feature {
  string name = 1;
  Point location = 2;
}

2、双击此bat文件重新生成服务端和客户端类,TestServerBase类里面出现了一个新的方法,就是重新生成成功了。

3、新建一个module类库来保存(给每一个模块单独新建一个module类库,后面每个模块可以单独部署,比如后台的服务就叫adminModule),我这里就随便命名了一个module。里面建了一个SayHelloServer的

 SayHelloSever里面建一个方法

  public class SayHelleServer
    {
        public string SayHello(string name)
        {
            return $"{name} Say Hello World";
        }
    }

 4、服务端新增实现Invoke方法,服务端引用module 项目,这样就把module的dll引入到server的bin目录下了。目的是为了简单的反射执行该方法。新增一个BulidServices的方法来反射执行SayHelloServer的SayHello方法

 public static T GetInvokeMethod<T>(GrpcRequest r)
        {
            try
            {
                string nameSpace = "AidenGRPC.Module";
                string className = "SayHelloServer";
                string methodName = "SayHello";
                //命名空间.类名,程序集               
                object instance = Assembly.Load(nameSpace).CreateInstance(nameSpace + "." + className);
                Type type = instance.GetType();
                //加载类型
                // Type type = Type.GetType(path);
                //根据类型创建实例
                object obj = Activator.CreateInstance(type, true);
                //加载方法参数类型及方法
                MethodInfo method = null;
                if (r != null && !string.IsNullOrEmpty(r.RequestMsg))
                {
                    //加载方法参数类型
                    Type[] paratypes = new Type[1];
                    paratypes[0] = r.RequestMsg.GetType();

                    method = type.GetMethod(methodName, paratypes); //加载有参方法
                    return (T)method.Invoke(obj, new object[] { r.RequestMsg })
                }
                else
                {
                    //加载无参方法
                    method = type.GetMethod(methodName);
                    return (T)method.Invoke();
} //类型转换并返回  } catch (Exception ex) { //发生异常时,返回类型的默认值。 return default(T); } }

5、在实现方法中添加相关Invoke的实现

 public class TestImpl:AidenGRPC.RPCBase.TestServer.TestServerBase
    {
        public override Task<Feature> GetFeature(Point request, ServerCallContext context)
        {
            return Task.FromResult(new Feature { Name = "aiden", Location = request });
        }

        public override Task<GrpcResponse> Invoke(GrpcRequest r, ServerCallContext context)
        {
            GrpcResponse re = new GrpcResponse();
            re.ResponseMsg= BuildServices.GetInvokeMethod<string>(r);
            return Task.FromResult(re);
        }

6、运行服务端,能够正常启动

7、再客户端写调用Invoke服务的代码,由于服务端定死了Invoke指向的是Sayhello方法,那么我们传一个名字过去,SayHello方法返回的是“Aiden Say Hello World”

 Channel channel = new Channel("127.0.0.1:30052", ChannelCredentials.Insecure);
            var client = new AidenGRPC.RPCBase.TestServer.TestServerClient(channel) ;
            //Point p = new Point() { Latitude = 409146, Longitude = -88906 };
            //Feature f= client.GetFeature(p);
            GrpcRequest re = new GrpcRequest();
            re.RequestMsg = "Aiden";

            GrpcResponse rp = client.Invoke(re);
            Console.WriteLine(rp.ResponseMsg);
           // Console.WriteLine(string.Format("Name:{0},Latitude:{1},Longitude:{2}", f.Name, f.Location.Latitude, f.Location.Longitude));
            channel.ShutdownAsync().Wait();
            Console.WriteLine("Press any key to exit client...");
            Console.ReadKey();        

运行一下客户端,效果如下:

ok这样整个路都走通了,上面我把命名空间,类型,方法名,端口啥的都写死了,这肯定不行的,调用哪个方法应该由客户端传给服务端,服务端根据客户端想要调用的方法信息反射执行后返回相应的值

下一节我们看怎么封装好一些。

原文地址:https://www.cnblogs.com/choii/p/14530270.html