/// <summary> /// Register GrpcClient /// </summary> /// <param name="hostBuilder">The host builder context</param> /// <param name="builderAction">The client options builder action</param> /// <param name="configurationKeyName">The client optios key in appsetting.json</param> /// <returns></returns> public static IHostBuilder UseGrpcClient(this IHostBuilder hostBuilder, Action <HostBuilderContext, IServiceCollection, ClientBuilder> builderAction = null, string configurationKeyName = "GrpcClient") { hostBuilder.ConfigureServices((context, services) => { var builder = context.Configuration.GetSection(configurationKeyName).Get <ClientBuilder>() ?? new ClientBuilder(); builder.Configuration = context.Configuration; builder.Services = services; builderAction?.Invoke(context, services, builder); var client = builder.Build(); var codeBuilder = new CodeBuilder("CodeGenerate"); foreach (var proxyer in client.Proxyers) { codeBuilder.CreateClass(new ServicerProxyGenerator(proxyer.Options.PackageName, proxyer.ServicerTypes.ToList()).Generate().ToArray()); codeBuilder.AddAssemblyRefence(proxyer.Options.Assemblies.ToArray()); } codeBuilder.AddAssemblyRefence(Assembly.GetExecutingAssembly()) .AddAssemblyRefence(typeof(ServerServiceDefinition).Assembly) .AddAssemblyRefence(typeof(ServiceProviderServiceExtensions).Assembly) .AddAssemblyRefence(typeof(Console).Assembly) .AddAssemblyRefence(typeof(KadderBuilder).Assembly) .AddAssemblyRefence(typeof(GrpcServerOptions).Assembly) .AddAssemblyRefence(builder.GetType().Assembly); var codeAssembly = codeBuilder.BuildAsync().Result; foreach (var servicerProxyer in codeBuilder.Classes) { var namespaces = $"{servicerProxyer.Namespace}.{servicerProxyer.Name}"; var proxyerType = codeAssembly.Assembly.GetType(namespaces); var servicerType = proxyerType.GetInterfaces().FirstOrDefault(); if (servicerType == null) { services.AddSingleton(proxyerType); } else { services.AddSingleton(servicerType, proxyerType); } } foreach (var proxyerOptions in client.ProxyerOptions) { foreach (var interceptor in proxyerOptions.Interceptors) { services.AddSingleton(interceptor); } } services.AddSingleton(client); services.AddSingleton <IBinarySerializer, ProtobufBinarySerializer>(); services.AddSingleton <ServicerInvoker>(); services.AddSingleton <IObjectProvider, ObjectProvider>(); var provider = services.BuildServiceProvider(); KadderOptions.KadderObjectProvider = provider.GetService <IObjectProvider>(); }); return(hostBuilder); }
public IDictionary <Type, string> GenerateHandler( GrpcOptions options, GrpcClient client, ref CodeBuilder codeBuilder) { var types = RefelectionHelper.GetImplInterfaceTypes( typeof(IMessagingServicer), true, options.GetScanAssemblies()); var grpcServiceDic = new Dictionary <Type, string>(); foreach (var typeService in types) { var className = typeService.Name.Remove(0, 1); var classDescripter = new ClassDescripter( className, codeBuilder.Namespace) .SetBaseType(typeService.Name) .AddUsing("System.Threading.Tasks", typeService.Namespace) .AddUsing("Kadder") .SetAccess(AccessType.Public); grpcServiceDic.Add(typeService, $"{codeBuilder.Namespace}.{className}"); var baseInterfaces = typeService.GetInterfaces(); foreach (var method in typeService.GetMethods()) { var notGrpcMethodCount = method.CustomAttributes .Count(p => p.AttributeType == typeof(NotGrpcMethodAttribute)); if (notGrpcMethodCount > 0) { continue; } var parameters = method.GetParameters(); if (parameters.Length != 1) { continue; } var requestName = parameters[0].ParameterType.Name.ToLower(); var responseType = GetMethodReturn(method.ReturnType); var methodName = method.Name.Replace("Async", ""); classDescripter.CreateMember( new MethodDescripter(method.Name, true) .SetAccess(AccessType.Public) .SetReturn($"Task<{responseType.Name}>") .SetParams( new ParameterDescripter( parameters[0].ParameterType.Name, requestName)) .AppendCode($@"var client=GrpcClientExtension.ClientDic[""{client.ID.ToString()}""];") .AppendCode($@"return await client.CallAsync<{parameters[0].ParameterType.Name},{responseType.Name}>({requestName}, ""{methodName}"");")) .AddUsing(responseType.Namespace) .AddUsing(parameters[0].ParameterType.Namespace); } codeBuilder.CreateClass(classDescripter) .AddAssemblyRefence(typeService.Assembly.Location); } codeBuilder.AddAssemblyRefence(this.GetType().Assembly.Location); return(grpcServiceDic); }
private void GenerateGrpcCallCode(MethodInfo method, RpcParameterInfo parameter, string namespaceName, CodeBuilder codeBuilder, ref StringBuilder bindServicesCode) { bindServicesCode.AppendLine($@" .AddMethod(new Method<{parameter.ParameterType.Name}, {GrpcServiceBuilder.GetMethodReturn(method).Name}>( MethodType.Unary, ""{namespaceName}.{method.DeclaringType.Name}"", ""{method.Name.Replace("Async", "")}"", new Marshaller<{parameter.ParameterType.Name}>( _binarySerializer.Serialize, _binarySerializer.Deserialize<{parameter.ParameterType.Name}> ), new Marshaller<{GrpcServiceBuilder.GetMethodReturn(method).Name}>( _binarySerializer.Serialize, _binarySerializer.Deserialize<{GrpcServiceBuilder.GetMethodReturn(method).Name}>) ), {method.Name.Replace("Async", "")})"); codeBuilder .AddAssemblyRefence(parameter.ParameterType.Assembly) .AddAssemblyRefence(GrpcServiceBuilder.GetMethodReturn(method).Assembly); }
public IDictionary <Type, string> GenerateHandler( GrpcOptions options, GrpcClient client, ref CodeBuilder codeBuilder) { var types = options.GetKServicers(); var grpcServiceDic = new Dictionary <Type, string>(); foreach (var typeService in types) { var className = $"{typeService.Name}GrpcService"; var classDescripter = new ClassDescripter(className, codeBuilder.Namespace) .SetBaseType(typeService.Name) .AddUsing("System.Threading.Tasks", typeService.Namespace) .AddUsing("Kadder") .SetAccess(AccessType.Public); grpcServiceDic.Add(typeService, $"{codeBuilder.Namespace}.{className}"); var baseInterfaces = typeService.GetInterfaces(); foreach (var method in typeService.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly)) { var notGrpcMethodCount = method.CustomAttributes.Count( p => p.AttributeType == typeof(NotGrpcMethodAttribute)); if (notGrpcMethodCount > 0) { continue; } var parameters = RpcParameterInfo.Convert(method.GetParameters()); if (parameters.Count == 0) { var emptyMessageType = typeof(EmptyMessage); parameters.Add(new RpcParameterInfo() { Name = emptyMessageType.Name, ParameterType = emptyMessageType, IsEmpty = true }); } var requestName = parameters[0].ParameterType.Name.ToLower(); var responseType = GetMethodReturn(method); var returnTypeCode = $"new Task<{responseType.Name}>"; var returnCode = "return "; var requestCode = requestName; if (parameters[0].IsEmpty) { requestCode = "new EmptyMessage()"; } if (responseType.IsEmpty) { returnTypeCode = $"new {method.ReturnType.Name}"; returnCode = string.Empty; } var methodName = method.Name.Replace("Async", ""); var methodDescripter = new MethodDescripter(method.Name, true) .SetAccess(AccessType.Public) .SetReturn(returnTypeCode) .AppendCode($@"var client = GrpcClientExtension.ClientDic[""{client.ID.ToString()}""];") .AppendCode($@"{returnCode}await client.CallAsync<{parameters[0].ParameterType.Name},{responseType.Name}>({requestCode}, ""{methodName}"", ""{typeService.Name}"");"); if (!parameters[0].IsEmpty) { methodDescripter.SetParams(new ParameterDescripter(parameters[0].ParameterType.Name, requestName)); } classDescripter.CreateMember(methodDescripter) .AddUsing(responseType.Namespace).AddUsing(parameters[0].ParameterType.Namespace); } codeBuilder.CreateClass(classDescripter) .AddAssemblyRefence(typeService.Assembly.Location); } codeBuilder.AddAssemblyRefence(this.GetType().Assembly.Location); return(grpcServiceDic); }
public static IHostBuilder UseGrpcServer(this IHostBuilder hostBuilder, Action <HostBuilderContext, IServiceCollection, GrpcServerBuilder> builderAction = null, string configurationKeyName = "GrpcServer") { hostBuilder.ConfigureServices((context, services) => { var log = services.BuildServiceProvider().GetService <ILogger <GrpcServerBuilder> >(); var builder = context.Configuration.GetSection(configurationKeyName).Get <GrpcServerBuilder>() ?? new GrpcServerBuilder(); builderAction?.Invoke(context, services, builder); var server = new Server(builder.Options.ChannelOptions); foreach (var port in builder.Options.Ports) { server.Ports.Add(new ServerPort(port.Host, port.Port, port.Credentials)); } foreach (var interceptor in builder.Interceptors) { services.AddSingleton(interceptor); } foreach (var assemblyName in builder.AssemblyNames) { builder.Assemblies.Add(Assembly.Load(assemblyName)); } builder.Assemblies.Add(Assembly.GetEntryAssembly()); if (log.IsEnabled(LogLevel.Debug)) { log.LogDebug(builder.ToString()); } var servicerTypes = ServicerHelper.GetServicerTypes(builder.Assemblies); if (servicerTypes == null || servicerTypes.Count == 0) { throw new ArgumentNullException("Not found any grpc servicer!"); } var servicerProxyers = new ServicerProxyGenerator(builder.Options.PackageName, servicerTypes).Generate(); var codeBuilder = new CodeBuilder("Kadder.Grpc.Server"); codeBuilder.CreateClass(servicerProxyers.ToArray()); codeBuilder.AddAssemblyRefence(Assembly.GetExecutingAssembly()) .AddAssemblyRefence(typeof(ILogger).Assembly) .AddAssemblyRefence(typeof(ServerServiceDefinition).Assembly) .AddAssemblyRefence(typeof(ServiceProviderServiceExtensions).Assembly) .AddAssemblyRefence(typeof(Console).Assembly) .AddAssemblyRefence(servicerTypes.Select(p => p.Assembly).Distinct().ToArray()) .AddAssemblyRefence(typeof(KadderBuilder).Assembly) .AddAssemblyRefence(typeof(GrpcServerOptions).Assembly) .AddAssemblyRefence(builder.GetType().Assembly); var codeAssembly = codeBuilder.BuildAsync().Result; foreach (var servicerProxyer in servicerProxyers) { var namespaces = $"{servicerProxyer.Namespace}.{servicerProxyer.Name}"; var proxyerType = codeAssembly.Assembly.GetType(namespaces); services.AddSingleton(proxyerType); builder.GrpcServicerProxyers.Add(proxyerType); } services.AddSingleton(server); services.AddSingleton(builder); services.AddSingleton <IBinarySerializer, ProtobufBinarySerializer>(); services.AddSingleton(typeof(KadderBuilder), builder); services.AddSingleton <IObjectProvider, ObjectProvider>(); }); return(hostBuilder); }
private static MethodDescripter GenerateNoGrpcMethod(MethodInfo method, ClassDescripter classDescripter, CodeBuilder codeBuilder) { var methodDescripter = new MethodDescripter(method.Name) .SetAccess(AccessType.Public) .SetReturn(GetReturnName(method.ReturnType)) .AppendCode("throw new System.NotImplementedException();"); var parameterDescripters = new List <ParameterDescripter>(); foreach (var param in method.GetParameters()) { parameterDescripters.Add(new ParameterDescripter(GetReturnName(param.ParameterType), param.Name)); codeBuilder.AddAssemblyRefence(param.ParameterType.Assembly); } methodDescripter.SetParams(parameterDescripters.ToArray()); return(methodDescripter); string GetReturnName(Type type) { codeBuilder.AddAssemblyRefence(type.Assembly); if (type.IsGenericType) { var typeName = $"{type.FullName.Split('`')[0]}<"; foreach (var itemType in type.GenericTypeArguments) { typeName += $"{GetReturnName(itemType)},"; } return($"{typeName.Remove(typeName.Length-1)}>"); } else if (type.IsValueType || type.Name.StartsWith("String")) { switch (type.Name) { case "Int16": return("short"); case "Int32": return("int"); case "Int64": return("long"); case "UInt16": return("ushort"); case "UInt32": return("uint"); case "UInt64": return("ulong"); case "String": return("string"); case "Double": return("double"); case "Single": return("float"); case "Decimal": return("decimal"); case "Boolean": return("bool"); default: return(string.Empty); } } else { return(type.FullName); } } }
public List <ClassDescripter> GenerateGrpcProxy(GrpcServerOptions options, CodeBuilder codeBuilder = null) { if (codeBuilder == null) { codeBuilder = CodeBuilder.Default; } var implInterfaceTypes = options.GetKServicers(); var classDescripterList = new List <ClassDescripter>(); var protoMessageCode = new StringBuilder(); var protoServiceCode = new StringBuilder(); foreach (Type service in implInterfaceTypes) { var bindServicesCode = new StringBuilder("return ServerServiceDefinition.CreateBuilder()\n"); protoServiceCode.AppendLine($"service {service.Name} {{"); var @class = this.GenerateGrpcService(service); var interfaces = service.GetInterfaces(); foreach (var method in service.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)) { if (method.CustomAttributes.FirstOrDefault(p => p.AttributeType == typeof(NotGrpcMethodAttribute)) != null) { continue; } var parameters = RpcParameterInfo.Convert(method.GetParameters()); if (parameters.Count == 0) { var emptyMessageType = typeof(EmptyMessage); parameters.Add(new RpcParameterInfo() { Name = emptyMessageType.Name, ParameterType = emptyMessageType, IsEmpty = true }); } @class = GenerateGrpcMethod(@class, method, parameters[0], interfaces); GenerateGrpcCallCode(method, parameters[0], options.NamespaceName, codeBuilder, ref bindServicesCode); GenerateGrpcCallCodeForOldVersion(method, parameters[0], options.NamespaceName, options.ServiceName, codeBuilder, ref bindServicesCode); if (options.IsGeneralProtoFile) { GenerateProtoCode(method, parameters[0], ref protoServiceCode, ref protoMessageCode); } } bindServicesCode.AppendLine(".Build();"); protoServiceCode.AppendLine(); protoServiceCode.AppendLine("}"); @class.CreateMember(new MethodDescripter("BindServices", false).SetCode(bindServicesCode.ToString()).SetReturn("ServerServiceDefinition").SetAccess(AccessType.Public)); codeBuilder.AddAssemblyRefence(Assembly.GetExecutingAssembly()) .AddAssemblyRefence(typeof(ServerServiceDefinition).Assembly) .AddAssemblyRefence(typeof(ServerServiceDefinition).Assembly) .AddAssemblyRefence(typeof(ServiceProviderServiceExtensions).Assembly) .AddAssemblyRefence(typeof(Console).Assembly) .AddAssemblyRefence(service.Assembly); codeBuilder.CreateClass(@class); classDescripterList.Add(@class); } if (options.IsGeneralProtoFile) { if (string.IsNullOrWhiteSpace(options.PackageName)) { options.PackageName = options.NamespaceName; } var stringBuilder = new StringBuilder(); stringBuilder.AppendLine("syntax = \"proto3\";"); stringBuilder.AppendLine($@"option csharp_namespace = ""{options.NamespaceName}"";"); stringBuilder.AppendLine($"package {options.PackageName};\n"); stringBuilder.Append(protoServiceCode); stringBuilder.AppendLine(); var messageCode = protoMessageCode.ToString(); if (messageCode.Contains(".bcl.")) { protoMessageCode.Replace(".bcl.", ""); protoMessageCode.AppendLine(Bcl.Proto); } stringBuilder.Append(protoMessageCode); var path = $"{Environment.CurrentDirectory}/{options.NamespaceName}.proto"; if (File.Exists(path)) { File.Delete(path); } File.WriteAllText(path, stringBuilder.ToString()); _messages = null; } return(classDescripterList); }
public ClassDescripter GenerateHandlerProxy( Assembly[] assemblies, CodeBuilder codeBuilder = null) { if (codeBuilder == null) { codeBuilder = CodeBuilder.Default; } var types = RefelectionHelper.GetImplInterfaceTypes( typeof(IMessagingServicer), true, assemblies); var codeClass = new ClassDescripter("MessageServicerProxy", "Kadder") .SetAccess(AccessType.Public) .SetBaseType("IMessageServicerProxy") .AddUsing( "using System;", "using Kadder.Utilies;", "using System.Threading.Tasks;", "using Microsoft.Extensions.DependencyInjection;"); var needResult = new StringBuilder(); var noResult = new StringBuilder(); foreach (var type in types) { var methods = type.GetMethods(); foreach (var method in methods) { var parameters = method.GetParameters(); if (parameters.Length != 1) { continue; } var requestName = GetRequestName(method); if (method.ReturnType == typeof(void)) { noResult.AppendLine( $@"if(string.Equals(message.GetTypeFullName(),""{requestName}"")) {{ return async (m)=>await {{serviceProvider.GetService<{type.Name}>().{method.Name}(message as {parameters[0].ParameterType.FullName});}} ; }}"); } else { needResult.AppendLine( $@"if(string.Equals(message.GetTypeFullName(),""{requestName}"")) {{ return async (m)=>{{return (await serviceProvider.GetService<{type.Name}>().{method.Name}(message as {parameters[0].ParameterType.FullName})) as TMessageResult;}} ; }}"); } codeBuilder.AddAssemblyRefence(parameters[0].ParameterType.Assembly.Location); } codeClass.AddUsing($"using {type.Namespace};"); codeBuilder.AddAssemblyRefence(type.Assembly.Location); } noResult.Append("return null;"); needResult.Append("return null;"); codeClass.CreateMember( new MethodDescripter("GetHandleDelegate<TMessage,TMessageResult>") .SetAccess(AccessType.Public) .SetReturn("Func<TMessage,Task<TMessageResult>>") .SetCode(needResult.ToString()) .SetParams( new ParameterDescripter("TMessage", "message"), new ParameterDescripter("IServiceProvider", "serviceProvider")) .SetTypeParameters( new TypeParameterDescripter("TMessageResult", "class"), new TypeParameterDescripter("TMessage", "BaseMessage")), new MethodDescripter("GetHandleDelegate<TMessage>") .SetAccess(AccessType.Public) .SetReturn("Func<TMessage,Task>") .SetCode(noResult.ToString()) .SetParams( new ParameterDescripter("TMessage", "message"), new ParameterDescripter("IServiceProvider", "serviceProvider")) .SetTypeParameters( new TypeParameterDescripter("TMessage", "BaseMessage"))); codeBuilder .AddAssemblyRefence(assemblies.Select(p => p.Location).ToArray()) .AddAssemblyRefence(Assembly.GetExecutingAssembly().Location) .AddAssemblyRefence(typeof(ServiceProviderServiceExtensions).Assembly.Location) .CreateClass(codeClass); return(codeClass); }
public ClassDescripter GenerateGrpcProxy( GrpcServerOptions options, CodeBuilder codeBuilder = null) { if (codeBuilder == null) { codeBuilder = CodeBuilder.Default; } var types = RefelectionHelper.GetImplInterfaceTypes( typeof(IMessagingServicer), true, options.GetScanAssemblies()); var codeClass = new ClassDescripter("GrpcService", "Kadder") .SetAccess(AccessType.Public) .SetBaseType("IGrpcServices") .AddUsing("using Grpc.Core;") .AddUsing("using System.Threading.Tasks;") .AddUsing("using Kadder;") .AddUsing("using Kadder.Utilies;") .AddUsing("using Microsoft.Extensions.DependencyInjection;") .CreateFiled( new FieldDescripter("_binarySerializer") .SetAccess(AccessType.PrivateReadonly) .SetType(typeof(IBinarySerializer)), new FieldDescripter("_messageServicer") .SetAccess(AccessType.PrivateReadonly) .SetType(typeof(GrpcMessageServicer))) .CreateConstructor( new ConstructorDescripter("GrpcService") .SetCode("_binarySerializer=GrpcServerBuilder.ServiceProvider.GetService<IBinarySerializer>();\n_messageServicer=GrpcServerBuilder.ServiceProvider.GetService<GrpcMessageServicer>();") .SetAccess(AccessType.Public)); var bindServicesCode = new StringBuilder("return ServerServiceDefinition.CreateBuilder()\n"); var protoServiceCode = new StringBuilder($"service {options.ServiceName} {{"); var protoMessageCode = new StringBuilder(); protoServiceCode.AppendLine(); foreach (var item in types) { var baseInterfaces = item.GetInterfaces(); foreach (var method in item.GetMethods()) { if (method.CustomAttributes.FirstOrDefault(p => p.AttributeType == typeof(NotGrpcMethodAttribute)) != null) { continue; } var parameters = method.GetParameters(); if (parameters.Length != 1) { continue; } CreateCallCode(method, parameters[0], baseInterfaces); CreateGrpcCallCode(method, parameters[0]); if (options.IsGeneralProtoFile) { CreateProtoCode(method, parameters[0]); } } } bindServicesCode.AppendLine(".Build();"); codeClass.CreateMember( new MethodDescripter("BindServices") .SetCode(bindServicesCode.ToString()) .SetReturn("ServerServiceDefinition") .SetAccess(AccessType.Public)); codeBuilder.AddAssemblyRefence(Assembly.GetExecutingAssembly().Location) .AddAssemblyRefence(typeof(ServerServiceDefinition).Assembly.Location) .AddAssemblyRefence(typeof(ServerServiceDefinition).Assembly.Location) .AddAssemblyRefence(typeof(ServiceProviderServiceExtensions).Assembly.Location); if (options.IsGeneralProtoFile) { protoServiceCode.Append("\n}\n"); var protoStr = new StringBuilder(); protoStr.AppendLine(@"syntax = ""proto3"";"); protoStr.AppendLine($@"option csharp_namespace = ""{options.NamespaceName}"";"); protoStr.AppendLine($"package {options.PackageName};\n"); protoStr.Append(protoServiceCode); protoStr.AppendLine(); protoStr.Append(protoMessageCode); var fileName = $"{Environment.CurrentDirectory}/{options.NamespaceName}.proto"; if (File.Exists(fileName)) { File.Delete(fileName); } File.WriteAllText(fileName, protoStr.ToString()); _messages = null; } codeBuilder.CreateClass(codeClass); return(codeClass); void CreateCallCode(MethodInfo method, ParameterInfo parameter, Type[] baseInterfaces) { var requestName = GetRequestName(method); codeClass .CreateMember( new MethodDescripter($"{method.Name.Replace("Async", "")}", true) .AppendCode( $@"request.SetTypeFullName(""{requestName}""); return await _messageServicer.ProcessAsync<{parameter.ParameterType.Name},{GetMethodReturn(method.ReturnType).Name}>(request,context);") .SetReturn($"Task<{GetMethodReturn(method.ReturnType).Name}>") .SetParams( new ParameterDescripter(parameter.ParameterType.Name, "request"), new ParameterDescripter("ServerCallContext", "context")) .SetAccess(AccessType.Public)) .AddUsing($"using {parameter.ParameterType.Namespace};") .AddUsing($"using {GetMethodReturn(method.ReturnType).Namespace};"); } void CreateGrpcCallCode(MethodInfo method, ParameterInfo parameter) { bindServicesCode.AppendLine($@".AddMethod(new Method<{parameter.ParameterType.Name},{GetMethodReturn(method.ReturnType).Name}>( MethodType.Unary, ""{options.NamespaceName}.{options.ServiceName}"", ""{method.Name.Replace("Async", "")}"", new Marshaller<{parameter.ParameterType.Name}>( _binarySerializer.Serialize, _binarySerializer.Deserialize<{parameter.ParameterType.Name}> ), new Marshaller<{GetMethodReturn(method.ReturnType).Name}>( _binarySerializer.Serialize, _binarySerializer.Deserialize<{GetMethodReturn(method.ReturnType).Name}>) ), {method.Name.Replace("Async", "")})"); codeBuilder.AddAssemblyRefence(parameter.ParameterType.Assembly.Location) .AddAssemblyRefence(GetMethodReturn(method.ReturnType).Assembly.Location); } void CreateProtoCode(MethodInfo method, ParameterInfo parameter) { protoServiceCode.AppendLine(); protoServiceCode.AppendLine($"\trpc {method.Name.Replace("Async", "")}({parameter.ParameterType.Name}) returns({GetMethodReturn(method.ReturnType).Name});"); if (!_messages.Contains(parameter.ParameterType.Name)) { protoMessageCode.AppendLine(CreateProtoMessageCode(parameter.ParameterType)); _messages.Add(parameter.ParameterType.Name); } if (!_messages.Contains(GetMethodReturn(method.ReturnType).Name)) { protoMessageCode.AppendLine(CreateProtoMessageCode(GetMethodReturn(method.ReturnType))); _messages.Add(GetMethodReturn(method.ReturnType).Name); } } string CreateProtoMessageCode(Type messageType) { // Serializer.GetProto(messageType); if (_messages.Contains(messageType.Name)) { return(""); } var messageCode = new StringBuilder($"message {messageType.Name} {{"); var enumCode = new StringBuilder(); var refenceCode = new StringBuilder(); messageCode.AppendLine(); var properties = messageType.GetProperties().Where(p => p.DeclaringType == messageType); var isNeedAutoIndex = !(properties.FirstOrDefault(p => p.GetCustomAttribute(typeof(ProtoMemberAttribute)) != null) != null); int index = 1; foreach (var item in properties.OrderBy(p => p.Name, new ProtoPropertyCompare())) { if (item.GetCustomAttribute(typeof(ProtoIgnoreAttribute)) != null) { continue; } if (!isNeedAutoIndex) { var memberAttribute = item.GetCustomAttribute <ProtoMemberAttribute>(); if (memberAttribute == null) { continue; } messageCode.Append($"\t{GetFiledType(item.PropertyType)} {item.Name} = {memberAttribute.Tag};\n"); } else { if (item.GetCustomAttribute(typeof(ProtoIgnoreAttribute)) != null) { continue; } messageCode.Append($"\t{GetFiledType(item.PropertyType)} {item.Name} = {index};\n"); index++; } if (!item.PropertyType.IsGenericType && string.Equals(item.PropertyType.BaseType.Name.ToLower(), "enum") && !_messages.Contains(item.PropertyType.Name)) { GeneralEnumCode(item.PropertyType); _messages.Add(item.PropertyType.Name); } if (item.PropertyType.IsClass && item.PropertyType.GetCustomAttribute <ProtoContractAttribute>() != null) { refenceCode.AppendLine(CreateProtoMessageCode(item.PropertyType)); } if (item.PropertyType.IsArray && item.PropertyType.GetElementType().GetCustomAttribute <ProtoContractAttribute>() != null) { refenceCode.AppendLine(CreateProtoMessageCode(item.PropertyType.GetElementType())); } } _messages.Add(messageType.Name); return(messageCode.Append("}\n\n").Append(enumCode).Append(refenceCode).ToString()); string GetFiledType(Type type) { switch (type.Name.ToLower()) { case "int": return("int32"); case "int32": return("int32"); case "int64": return("int64"); case "long": return("int64"); case "string": return("string"); case "datetime": return("bcl.DateTime"); case "bool": return("bool"); case "boolean": return("bool"); case "double": return("double"); case "float": return("float"); default: if (type.Name.Contains("[]")) { return($"repeated {GetFiledType(type.GetElementType())}"); } return(type.Name); } } void GeneralEnumCode(Type type) { var zeroCode = "\tZERO = 0;"; var enumFiledCode = new StringBuilder(); var hasDefault = false; foreach (var item in type.GetFields()) { if (item.Name.Equals("value__")) { continue; } var values = (int)item.GetValue(null); if (values <= 0) { hasDefault = true; } enumFiledCode.AppendLine($"\t{item.Name} = {values};"); } if (hasDefault) { enumCode.Append($"enum {type.Name}{{\n{enumFiledCode}}}\n"); } else { enumCode.Append($"enum {type.Name}{{\n{zeroCode}\n{enumFiledCode}}}\n"); } } } }