static void VerifyMethodDefinitions(MethodDefinition[] definitions) { var map = new Dictionary <int, MethodDefinition>(definitions.Length); foreach (var item in definitions) { var methodId = item.MethodInfo.GetCustomAttribute <MethodIdAttribute>()?.MethodId ?? FNV1A32.GetHashCode(item.MethodInfo.Name); if (map.ContainsKey(methodId)) { throw new Exception($"TStreamingHub does not allows duplicate methodId(hash code). Please change name or use MethodIdAttribute. {map[methodId].MethodInfo.Name} and {item.MethodInfo.Name}"); } map.Add(methodId, item); if (!(item.MethodInfo.ReturnType.IsGenericType && item.MethodInfo.ReturnType.GetGenericTypeDefinition() == typeof(Task <>)) && item.MethodInfo.ReturnType != typeof(Task)) { throw new Exception($"Invalid definition, TStreamingHub's return type must only be `Task` or `Task<T>`. {item.MethodInfo.Name}."); } item.MethodId = methodId; if (item.RequestType == null) { item.RequestType = MagicOnionMarshallers.CreateRequestType(item.MethodInfo.GetParameters()); } } }
static IMyFirstServiceClient() { SumAsyncMethod = new Method <byte[], byte[]>(MethodType.Unary, "IMyFirstService", "SumAsync", MagicOnionMarshallers.ByteArrayMarshaller, MagicOnionMarshallers.ByteArrayMarshaller); SumAsyncRequestMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(new DynamicArgumentTupleFormatter <ZeroFormatter.Formatters.DefaultResolver, int, int>(default(int), default(int))); SumAsyncResponseMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(Formatter <ZeroFormatter.Formatters.DefaultResolver, string> .Default); SumAsync2Method = new Method <byte[], byte[]>(MethodType.Unary, "IMyFirstService", "SumAsync2", MagicOnionMarshallers.ByteArrayMarshaller, MagicOnionMarshallers.ByteArrayMarshaller); SumAsync2RequestMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(new DynamicArgumentTupleFormatter <ZeroFormatter.Formatters.DefaultResolver, int, int>(default(int), default(int))); SumAsync2ResponseMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(Formatter <ZeroFormatter.Formatters.DefaultResolver, string> .Default); StreamingOneMethod = new Method <byte[], byte[]>(MethodType.ClientStreaming, "IMyFirstService", "StreamingOne", MagicOnionMarshallers.ByteArrayMarshaller, MagicOnionMarshallers.ByteArrayMarshaller); StreamingOneRequestMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(ZeroFormatter.Formatters.Formatter <ZeroFormatter.Formatters.DefaultResolver, int> .Default); StreamingOneResponseMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(Formatter <ZeroFormatter.Formatters.DefaultResolver, string> .Default); StreamingTwoMethod = new Method <byte[], byte[]>(MethodType.ServerStreaming, "IMyFirstService", "StreamingTwo", MagicOnionMarshallers.ByteArrayMarshaller, MagicOnionMarshallers.ByteArrayMarshaller); StreamingTwoRequestMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(new DynamicArgumentTupleFormatter <ZeroFormatter.Formatters.DefaultResolver, int, int, int>(default(int), default(int), default(int))); StreamingTwoResponseMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(Formatter <ZeroFormatter.Formatters.DefaultResolver, string> .Default); StreamingTwo2Method = new Method <byte[], byte[]>(MethodType.ServerStreaming, "IMyFirstService", "StreamingTwo2", MagicOnionMarshallers.ByteArrayMarshaller, MagicOnionMarshallers.ByteArrayMarshaller); StreamingTwo2RequestMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(new DynamicArgumentTupleFormatter <ZeroFormatter.Formatters.DefaultResolver, int, int, int>(default(int), default(int), 9999)); StreamingTwo2ResponseMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(Formatter <ZeroFormatter.Formatters.DefaultResolver, string> .Default); StreamingThreeMethod = new Method <byte[], byte[]>(MethodType.DuplexStreaming, "IMyFirstService", "StreamingThree", MagicOnionMarshallers.ByteArrayMarshaller, MagicOnionMarshallers.ByteArrayMarshaller); StreamingThreeRequestMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(ZeroFormatter.Formatters.Formatter <ZeroFormatter.Formatters.DefaultResolver, int> .Default); StreamingThreeResponseMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(Formatter <ZeroFormatter.Formatters.DefaultResolver, string> .Default); }
static IHeartbeatClient() { ConnectMethod = new Method <byte[], byte[]>(MethodType.DuplexStreaming, "IHeartbeat", "Connect", MagicOnionMarshallers.ByteArrayMarshaller, MagicOnionMarshallers.ByteArrayMarshaller); ConnectRequestMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(ZeroFormatter.Formatters.Formatter <ZeroFormatter.Formatters.DefaultResolver, global::SharedLibrary.Nil> .Default); ConnectResponseMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(Formatter <ZeroFormatter.Formatters.DefaultResolver, global::SharedLibrary.Nil> .Default); TestSendMethod = new Method <byte[], byte[]>(MethodType.Unary, "IHeartbeat", "TestSend", MagicOnionMarshallers.ByteArrayMarshaller, MagicOnionMarshallers.ByteArrayMarshaller); TestSendRequestMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(ZeroFormatter.Formatters.Formatter <ZeroFormatter.Formatters.DefaultResolver, string> .Default); TestSendResponseMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(Formatter <ZeroFormatter.Formatters.DefaultResolver, global::SharedLibrary.Nil> .Default); }
static void DefineStaticFields(TypeBuilder typeBuilder, MethodDefinition[] definitions) { foreach (var item in definitions) { item.FieldMethod = typeBuilder.DefineField(item.MethodInfo.Name + "Method", bytesMethod, FieldAttributes.Private | FieldAttributes.Static); item.ResponseType = UnwrapResponseType(item, out item.MethodType, out item.ResponseIsTask, out item.RequestType); if (item.RequestType == null) { item.RequestType = MagicOnionMarshallers.CreateRequestType(item.MethodInfo.GetParameters()); } } }
static IArgumentPatternClient() { Unary1Method = new Method <byte[], byte[]>(MethodType.Unary, "IArgumentPattern", "Unary1", MagicOnionMarshallers.ByteArrayMarshaller, MagicOnionMarshallers.ByteArrayMarshaller); Unary1RequestMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(new DynamicArgumentTupleFormatter <ZeroFormatter.Formatters.DefaultResolver, int, int, string, global::SharedLibrary.MyEnum, global::SharedLibrary.MyStructResponse, ulong, global::SharedLibrary.MyRequest>(default(int), default(int), "unknown", SharedLibrary.MyEnum.Orange, default(global::SharedLibrary.MyStructResponse), 9, null)); Unary1ResponseMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(Formatter <ZeroFormatter.Formatters.DefaultResolver, global::SharedLibrary.MyHugeResponse> .Default); Unary2Method = new Method <byte[], byte[]>(MethodType.Unary, "IArgumentPattern", "Unary2", MagicOnionMarshallers.ByteArrayMarshaller, MagicOnionMarshallers.ByteArrayMarshaller); Unary2RequestMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(ZeroFormatter.Formatters.Formatter <ZeroFormatter.Formatters.DefaultResolver, global::SharedLibrary.MyRequest> .Default); Unary2ResponseMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(Formatter <ZeroFormatter.Formatters.DefaultResolver, global::SharedLibrary.MyResponse> .Default); Unary3Method = new Method <byte[], byte[]>(MethodType.Unary, "IArgumentPattern", "Unary3", MagicOnionMarshallers.ByteArrayMarshaller, MagicOnionMarshallers.ByteArrayMarshaller); Unary3RequestMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(ZeroFormatter.Formatters.Formatter <ZeroFormatter.Formatters.DefaultResolver, byte[]> .Default); Unary3ResponseMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(Formatter <ZeroFormatter.Formatters.DefaultResolver, global::SharedLibrary.MyResponse> .Default); Unary5Method = new Method <byte[], byte[]>(MethodType.Unary, "IArgumentPattern", "Unary5", MagicOnionMarshallers.ByteArrayMarshaller, MagicOnionMarshallers.ByteArrayMarshaller); Unary5RequestMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(ZeroFormatter.Formatters.Formatter <ZeroFormatter.Formatters.DefaultResolver, global::SharedLibrary.MyStructRequest> .Default); Unary5ResponseMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(Formatter <ZeroFormatter.Formatters.DefaultResolver, global::SharedLibrary.MyStructResponse> .Default); ServerStreamingResult1Method = new Method <byte[], byte[]>(MethodType.ServerStreaming, "IArgumentPattern", "ServerStreamingResult1", MagicOnionMarshallers.ByteArrayMarshaller, MagicOnionMarshallers.ByteArrayMarshaller); ServerStreamingResult1RequestMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(new DynamicArgumentTupleFormatter <ZeroFormatter.Formatters.DefaultResolver, int, int, string>(default(int), default(int), "unknown")); ServerStreamingResult1ResponseMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(Formatter <ZeroFormatter.Formatters.DefaultResolver, global::SharedLibrary.MyResponse> .Default); ServerStreamingResult2Method = new Method <byte[], byte[]>(MethodType.ServerStreaming, "IArgumentPattern", "ServerStreamingResult2", MagicOnionMarshallers.ByteArrayMarshaller, MagicOnionMarshallers.ByteArrayMarshaller); ServerStreamingResult2RequestMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(ZeroFormatter.Formatters.Formatter <ZeroFormatter.Formatters.DefaultResolver, global::SharedLibrary.MyRequest> .Default); ServerStreamingResult2ResponseMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(Formatter <ZeroFormatter.Formatters.DefaultResolver, global::SharedLibrary.MyResponse> .Default); ServerStreamingResult3Method = new Method <byte[], byte[]>(MethodType.ServerStreaming, "IArgumentPattern", "ServerStreamingResult3", MagicOnionMarshallers.ByteArrayMarshaller, MagicOnionMarshallers.ByteArrayMarshaller); ServerStreamingResult3RequestMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(ZeroFormatter.Formatters.Formatter <ZeroFormatter.Formatters.DefaultResolver, byte[]> .Default); ServerStreamingResult3ResponseMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(Formatter <ZeroFormatter.Formatters.DefaultResolver, global::SharedLibrary.MyResponse> .Default); ServerStreamingResult4Method = new Method <byte[], byte[]>(MethodType.ServerStreaming, "IArgumentPattern", "ServerStreamingResult4", MagicOnionMarshallers.ByteArrayMarshaller, MagicOnionMarshallers.ByteArrayMarshaller); ServerStreamingResult4RequestMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(ZeroFormatter.Formatters.Formatter <ZeroFormatter.Formatters.DefaultResolver, byte[]> .Default); ServerStreamingResult4ResponseMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(Formatter <ZeroFormatter.Formatters.DefaultResolver, global::SharedLibrary.Nil> .Default); ServerStreamingResult5Method = new Method <byte[], byte[]>(MethodType.ServerStreaming, "IArgumentPattern", "ServerStreamingResult5", MagicOnionMarshallers.ByteArrayMarshaller, MagicOnionMarshallers.ByteArrayMarshaller); ServerStreamingResult5RequestMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(ZeroFormatter.Formatters.Formatter <ZeroFormatter.Formatters.DefaultResolver, global::SharedLibrary.MyStructRequest> .Default); ServerStreamingResult5ResponseMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(Formatter <ZeroFormatter.Formatters.DefaultResolver, global::SharedLibrary.MyStructResponse> .Default); UnaryS1Method = new Method <byte[], byte[]>(MethodType.Unary, "IArgumentPattern", "UnaryS1", MagicOnionMarshallers.ByteArrayMarshaller, MagicOnionMarshallers.ByteArrayMarshaller); UnaryS1RequestMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(new DynamicArgumentTupleFormatter <ZeroFormatter.Formatters.DefaultResolver, global::System.DateTime, global::System.DateTimeOffset>(default(global::System.DateTime), default(global::System.DateTimeOffset))); UnaryS1ResponseMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(Formatter <ZeroFormatter.Formatters.DefaultResolver, bool> .Default); UnaryS2Method = new Method <byte[], byte[]>(MethodType.Unary, "IArgumentPattern", "UnaryS2", MagicOnionMarshallers.ByteArrayMarshaller, MagicOnionMarshallers.ByteArrayMarshaller); UnaryS2RequestMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(ZeroFormatter.Formatters.Formatter <ZeroFormatter.Formatters.DefaultResolver, int[]> .Default); UnaryS2ResponseMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(Formatter <ZeroFormatter.Formatters.DefaultResolver, bool> .Default); UnaryS3Method = new Method <byte[], byte[]>(MethodType.Unary, "IArgumentPattern", "UnaryS3", MagicOnionMarshallers.ByteArrayMarshaller, MagicOnionMarshallers.ByteArrayMarshaller); UnaryS3RequestMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(new DynamicArgumentTupleFormatter <ZeroFormatter.Formatters.DefaultResolver, int[], string[], global::SharedLibrary.MyEnum[]>(default(int[]), default(string[]), default(global::SharedLibrary.MyEnum[]))); UnaryS3ResponseMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(Formatter <ZeroFormatter.Formatters.DefaultResolver, bool> .Default); }
public UnaryResult <MyResponse> Unary1(int x, int y, string z = "unknown") { var tuple = new DynamicArgumentTuple <int, int>(x, y); var formatter = new DynamicArgumentTupleFormatter <DefaultResolver, int, int>(0, 0); var requestMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(formatter); var method = new Method <byte[], byte[]>(MethodType.Unary, "IArgumentPattern", "Unary1", MagicOnionMarshallers.ByteArrayMarshaller, MagicOnionMarshallers.ByteArrayMarshaller); var request = requestMarshaller.Serializer(tuple); var callResult = invoker.AsyncUnaryCall(method, null, default(CallOptions), request); var responseMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(ZeroFormatter.Formatters.Formatter <DefaultResolver, MyResponse> .Default); return(new UnaryResult <MyResponse>(callResult, responseMarshaller)); }
static IStandardClient() { Unary1AsyncMethod = new Method <byte[], byte[]>(MethodType.Unary, "IStandard", "Unary1Async", MagicOnionMarshallers.ByteArrayMarshaller, MagicOnionMarshallers.ByteArrayMarshaller); Unary1AsyncRequestMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(new DynamicArgumentTupleFormatter <ZeroFormatter.Formatters.DefaultResolver, int, int>(default(int), default(int))); Unary1AsyncResponseMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(Formatter <ZeroFormatter.Formatters.DefaultResolver, int> .Default); ClientStreaming1AsyncMethod = new Method <byte[], byte[]>(MethodType.ClientStreaming, "IStandard", "ClientStreaming1Async", MagicOnionMarshallers.ByteArrayMarshaller, MagicOnionMarshallers.ByteArrayMarshaller); ClientStreaming1AsyncRequestMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(ZeroFormatter.Formatters.Formatter <ZeroFormatter.Formatters.DefaultResolver, int> .Default); ClientStreaming1AsyncResponseMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(Formatter <ZeroFormatter.Formatters.DefaultResolver, string> .Default); ServerStreamingAsyncMethod = new Method <byte[], byte[]>(MethodType.ServerStreaming, "IStandard", "ServerStreamingAsync", MagicOnionMarshallers.ByteArrayMarshaller, MagicOnionMarshallers.ByteArrayMarshaller); ServerStreamingAsyncRequestMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(new DynamicArgumentTupleFormatter <ZeroFormatter.Formatters.DefaultResolver, int, int, int>(default(int), default(int), default(int))); ServerStreamingAsyncResponseMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(Formatter <ZeroFormatter.Formatters.DefaultResolver, int> .Default); DuplexStreamingAsyncMethod = new Method <byte[], byte[]>(MethodType.DuplexStreaming, "IStandard", "DuplexStreamingAsync", MagicOnionMarshallers.ByteArrayMarshaller, MagicOnionMarshallers.ByteArrayMarshaller); DuplexStreamingAsyncRequestMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(ZeroFormatter.Formatters.Formatter <ZeroFormatter.Formatters.DefaultResolver, int> .Default); DuplexStreamingAsyncResponseMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(Formatter <ZeroFormatter.Formatters.DefaultResolver, int> .Default); }
public StreamingHubHandler(Type classType, MethodInfo methodInfo, StreamingHubHandlerOptions handlerOptions, IServiceProvider serviceProvider) { var hubInterface = classType.GetInterfaces().First(x => x.GetTypeInfo().IsGenericType&& x.GetGenericTypeDefinition() == typeof(IStreamingHub <,>)).GetGenericArguments()[0]; var interfaceMethod = GetInterfaceMethod(classType, hubInterface, methodInfo.Name); this.serviceProvider = serviceProvider; this.HubType = classType; this.HubName = hubInterface.Name; this.MethodInfo = methodInfo; // Validation for Id if (methodInfo.GetCustomAttribute <MethodIdAttribute>() != null) { throw new InvalidOperationException($"Hub Implementation can not add [MethodId], you should add hub `interface`. {classType.Name}/{methodInfo.Name}"); } this.MethodId = interfaceMethod.GetCustomAttribute <MethodIdAttribute>()?.MethodId ?? FNV1A32.GetHashCode(interfaceMethod.Name); this.UnwrappedResponseType = UnwrapResponseType(methodInfo); var resolver = handlerOptions.SerializerOptions.Resolver; var parameters = methodInfo.GetParameters(); this.RequestType = MagicOnionMarshallers.CreateRequestTypeAndSetResolver(classType.Name + "/" + methodInfo.Name, parameters, ref resolver); this.serializerOptions = handlerOptions.SerializerOptions.WithResolver(resolver); this.AttributeLookup = classType.GetCustomAttributes(true) .Concat(methodInfo.GetCustomAttributes(true)) .Cast <Attribute>() .ToLookup(x => x.GetType()); this.filters = handlerOptions.GlobalStreamingHubFilters .OfType <IMagicOnionFilterFactory <StreamingHubFilterAttribute> >() .Concat(classType.GetCustomAttributes <StreamingHubFilterAttribute>(true).Select(x => new StreamingHubFilterDescriptor(x, x.Order))) .Concat(classType.GetCustomAttributes(true).OfType <IMagicOnionFilterFactory <StreamingHubFilterAttribute> >()) .Concat(methodInfo.GetCustomAttributes <StreamingHubFilterAttribute>(true).Select(x => new StreamingHubFilterDescriptor(x, x.Order))) .Concat(methodInfo.GetCustomAttributes(true).OfType <IMagicOnionFilterFactory <StreamingHubFilterAttribute> >()) .OrderBy(x => x.Order) .ToArray(); // validation filter if (methodInfo.GetCustomAttribute <MagicOnionFilterAttribute>(true) != null) { throw new InvalidOperationException($"StreamingHub method can not add [MagicOnionFilter], you should add [StreamingHubFilter]. {classType.Name}/{methodInfo.Name}"); } this.toStringCache = HubName + "/" + MethodInfo.Name; this.getHashCodeCache = HubName.GetHashCode() ^ MethodInfo.Name.GetHashCode() << 2; // ValueTask (StreamingHubContext context) => // { // T request = LZ4MessagePackSerializer.Deserialize<T>(context.Request, context.FormatterResolver); // Task<T> result = ((HubType)context.HubInstance).Foo(request); // return WriteInAsyncLockInTaskWithMessageId(result) || return new ValueTask(result) // } try { var flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; var contextArg = Expression.Parameter(typeof(StreamingHubContext), "context"); var requestArg = Expression.Parameter(RequestType, "request"); var getSerializerOptions = Expression.Property(contextArg, typeof(StreamingHubContext).GetProperty("SerializerOptions", flags) !); var contextRequest = Expression.Property(contextArg, typeof(StreamingHubContext).GetProperty("Request", flags) !); var noneCancellation = Expression.Default(typeof(CancellationToken)); var getInstanceCast = Expression.Convert(Expression.Property(contextArg, typeof(StreamingHubContext).GetProperty("HubInstance", flags) !), HubType); var callDeserialize = Expression.Call(messagePackDeserialize.MakeGenericMethod(RequestType), contextRequest, getSerializerOptions, noneCancellation); var assignRequest = Expression.Assign(requestArg, callDeserialize); Expression[] arguments = new Expression[parameters.Length]; if (parameters.Length == 1) { arguments[0] = requestArg; } else { for (int i = 0; i < parameters.Length; i++) { arguments[i] = Expression.Field(requestArg, "Item" + (i + 1)); } } var callBody = Expression.Call(getInstanceCast, methodInfo, arguments); var finalMethod = (methodInfo.ReturnType.IsGenericType) ? typeof(StreamingHubContext).GetMethod(nameof(StreamingHubContext.WriteResponseMessage), flags) !.MakeGenericMethod(UnwrappedResponseType !) : typeof(StreamingHubContext).GetMethod(nameof(StreamingHubContext.WriteResponseMessageNil), flags) !; callBody = Expression.Call(contextArg, finalMethod, callBody); var body = Expression.Block(new[] { requestArg }, assignRequest, callBody); var compiledBody = Expression.Lambda(body, contextArg).Compile(); this.MethodBody = BuildMethodBodyWithFilter((Func <StreamingHubContext, ValueTask>)compiledBody); } catch (Exception ex) { throw new InvalidOperationException($"Can't create handler. Path:{ToString()}", ex); } }
static PingClient() { Method = new Method <byte[], byte[]>(MethodType.DuplexStreaming, "IMagicOnionEmbeddedPing", "Ping", MagicOnionMarshallers.ByteArrayMarshaller, MagicOnionMarshallers.ByteArrayMarshaller); RequestMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(ZeroFormatter.Formatters.Formatter <ZeroFormatter.Formatters.DefaultResolver, DateTime> .Default); ResponseMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(Formatter <ZeroFormatter.Formatters.DefaultResolver, double> .Default); }
public async Task Invoke(HttpContext httpContext) { try { var path = httpContext.Request.Path.Value; MethodHandler handler; if (!handlers.TryGetValue(path, out handler)) { await next(httpContext); return; } // from form... object deserializedObject; if (httpContext.Request.ContentType == "application/x-www-form-urlencoded") { //object parameters var args = new List <object>(); var typeArgs = new List <Type>(); foreach (var p in handler.MethodInfo.GetParameters()) { typeArgs.Add(p.ParameterType); StringValues stringValues; if (httpContext.Request.Form.TryGetValue(p.Name, out stringValues)) { if (p.ParameterType == typeof(string)) { args.Add((string)stringValues); } else if (p.ParameterType.GetTypeInfo().IsEnum) { args.Add(Enum.Parse(p.ParameterType, (string)stringValues)); } else { var collectionType = GetCollectionType(p.ParameterType); if (stringValues.Count == 1 || collectionType == null) { var values = (string)stringValues; if (p.ParameterType == typeof(DateTime) || p.ParameterType == typeof(DateTimeOffset) || p.ParameterType == typeof(DateTime?) || p.ParameterType == typeof(DateTimeOffset?)) { values = "\"" + values + "\""; } args.Add(JsonConvert.DeserializeObject(values, p.ParameterType)); } else { string serializeTarget; if (collectionType == typeof(string)) { serializeTarget = "[" + string.Join(", ", stringValues.Select(x => JsonConvert.SerializeObject(x))) + "]"; // escape serialzie } else if (collectionType.GetTypeInfo().IsEnum || collectionType == typeof(DateTime) || collectionType == typeof(DateTimeOffset) || collectionType == typeof(DateTime?) || collectionType == typeof(DateTimeOffset?)) { serializeTarget = "[" + string.Join(", ", stringValues.Select(x => "\"" + x + "\"")) + "]"; } else { serializeTarget = "[" + (string)stringValues + "]"; } args.Add(JsonConvert.DeserializeObject(serializeTarget, p.ParameterType)); } } } else { if (p.HasDefaultValue) { args.Add(p.DefaultValue); } else { args.Add(null); } } } deserializedObject = MagicOnionMarshallers.InsantiateDynamicArgumentTuple(typeArgs.ToArray(), args.ToArray()); } else { string body; using (var sr = new StreamReader(httpContext.Request.Body, Encoding.UTF8)) { body = sr.ReadToEnd(); } if (handler.RequestType == typeof(byte[]) && string.IsNullOrWhiteSpace(body)) { body = "[]"; } deserializedObject = Newtonsoft.Json.JsonConvert.DeserializeObject(body, handler.RequestType); } // JSON to C# Object to MessagePack var requestObject = handler.BoxedSerialize(deserializedObject); var method = new Method <byte[], byte[]>(MethodType.Unary, handler.ServiceName, handler.MethodInfo.Name, MagicOnionMarshallers.ThroughMarshaller, MagicOnionMarshallers.ThroughMarshaller); // create header var metadata = new Metadata(); foreach (var header in httpContext.Request.Headers) { metadata.Add(header.Key, header.Value); } var invoker = new DefaultCallInvoker(channel); var rawResponse = await invoker.AsyncUnaryCall(method, null, default(CallOptions).WithHeaders(metadata), requestObject); // MessagePack -> Object -> Json var obj = handler.BoxedDeserialize(rawResponse); var v = JsonConvert.SerializeObject(obj, new[] { new Newtonsoft.Json.Converters.StringEnumConverter() }); httpContext.Response.ContentType = "application/json"; await httpContext.Response.WriteAsync(v); } catch (Exception ex) { httpContext.Response.StatusCode = 500; await httpContext.Response.WriteAsync(ex.ToString()); } }
public MethodHandler(MagicOnionOptions options, Type classType, MethodInfo methodInfo) { this.ServiceType = classType; this.ServiceName = classType.GetInterfaces().First(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IService <>)).GetGenericArguments()[0].Name; this.MethodInfo = methodInfo; MethodType mt; this.UnwrappedResponseType = UnwrapResponseType(methodInfo, out mt, out responseIsTask, out this.RequestType); this.MethodType = mt; this.resolver = options.FormatterResolver; var parameters = methodInfo.GetParameters(); if (RequestType == null) { this.RequestType = MagicOnionMarshallers.CreateRequestTypeAndSetResolver(classType.Name + "/" + methodInfo.Name, parameters, ref resolver); } this.AttributeLookup = classType.GetCustomAttributes(true) .Concat(methodInfo.GetCustomAttributes(true)) .Cast <Attribute>() .ToLookup(x => x.GetType()); this.filters = options.GlobalFilters .Concat(classType.GetCustomAttributes <MagicOnionFilterAttribute>(true)) .Concat(methodInfo.GetCustomAttributes <MagicOnionFilterAttribute>(true)) .OrderBy(x => x.Order) .ToArray(); // options this.isReturnExceptionStackTraceInErrorDetail = options.IsReturnExceptionStackTraceInErrorDetail; this.logger = options.MagicOnionLogger; // prepare lambda parameters var contextArg = Expression.Parameter(typeof(ServiceContext), "context"); var contextBind = Expression.Bind(classType.GetProperty("Context"), contextArg); var instance = Expression.MemberInit(Expression.New(classType), contextBind); switch (MethodType) { case MethodType.Unary: case MethodType.ServerStreaming: // (ServiceContext context) => // { // var request = LZ4MessagePackSerializer.Deserialize<T>(context.Request, context.Resolver); // var result = new FooService() { Context = context }.Bar(request.Item1, request.Item2); // return MethodHandlerResultHelper.SerializeUnaryResult(result, context); // }; try { var flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; var staticFlags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; var requestArg = Expression.Parameter(RequestType, "request"); var getResolver = Expression.Property(contextArg, typeof(ServiceContext).GetProperty("FormatterResolver", flags)); var contextRequest = Expression.Property(contextArg, typeof(ServiceContext).GetProperty("Request", flags)); var callDeserialize = Expression.Call(messagePackDeserialize.MakeGenericMethod(RequestType), contextRequest, getResolver); var assignRequest = Expression.Assign(requestArg, callDeserialize); Expression[] arguments = new Expression[parameters.Length]; if (parameters.Length == 1) { arguments[0] = requestArg; } else { for (int i = 0; i < parameters.Length; i++) { arguments[i] = Expression.Field(requestArg, "Item" + (i + 1)); } } var callBody = Expression.Call(instance, methodInfo, arguments); if (MethodType == MethodType.Unary) { var finalMethod = (responseIsTask) ? typeof(MethodHandlerResultHelper).GetMethod("SerializeTaskUnaryResult", staticFlags).MakeGenericMethod(UnwrappedResponseType) : typeof(MethodHandlerResultHelper).GetMethod("SerializeUnaryResult", staticFlags).MakeGenericMethod(UnwrappedResponseType); callBody = Expression.Call(finalMethod, callBody, contextArg); } else { if (!responseIsTask) { callBody = Expression.Call(typeof(Task).GetMethod("FromResult").MakeGenericMethod(MethodInfo.ReturnType), callBody); } } var body = Expression.Block(new[] { requestArg }, assignRequest, callBody); var compiledBody = Expression.Lambda(body, contextArg).Compile(); this.methodBody = BuildMethodBodyWithFilter((Func <ServiceContext, Task>)compiledBody); } catch (Exception ex) { throw new InvalidOperationException($"Can't create handler. Path:{ToString()}", ex); } break; case MethodType.ClientStreaming: case MethodType.DuplexStreaming: if (parameters.Length != 0) { throw new InvalidOperationException($"{MethodType} does not support method parameters. If you need to send initial parameter, use header instead. Path:{ToString()}"); } // (ServiceContext context) => new FooService() { Context = context }.Bar(); try { var body = Expression.Call(instance, methodInfo); if (MethodType == MethodType.ClientStreaming) { var staticFlags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; var finalMethod = (responseIsTask) ? typeof(MethodHandlerResultHelper).GetMethod("SerializeTaskClientStreamingResult", staticFlags).MakeGenericMethod(RequestType, UnwrappedResponseType) : typeof(MethodHandlerResultHelper).GetMethod("SerializeClientStreamingResult", staticFlags).MakeGenericMethod(RequestType, UnwrappedResponseType); body = Expression.Call(finalMethod, body, contextArg); } else { if (!responseIsTask) { body = Expression.Call(typeof(Task).GetMethod("FromResult").MakeGenericMethod(MethodInfo.ReturnType), body); } } var compiledBody = Expression.Lambda(body, contextArg).Compile(); this.methodBody = BuildMethodBodyWithFilter((Func <ServiceContext, Task>)compiledBody); } catch (Exception ex) { throw new InvalidOperationException($"Can't create handler. Path:{ToString()}", ex); } break; default: throw new InvalidOperationException("Unknown MethodType:" + MethodType + $"Path:{ToString()}"); } }
static HeartbeatClient() { DuplexStreamingAsyncMethod = new Method <byte[], byte[]>(MethodType.DuplexStreaming, "IMagicOnionEmbeddedHeartbeat", "Connect", MagicOnionMarshallers.ByteArrayMarshaller, MagicOnionMarshallers.ByteArrayMarshaller); DuplexStreamingAsyncRequestMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(ZeroFormatter.Formatters.Formatter <ZeroFormatter.Formatters.DefaultResolver, bool> .Default); DuplexStreamingAsyncResponseMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(Formatter <ZeroFormatter.Formatters.DefaultResolver, bool> .Default); }
public MethodHandler(MagicOnionOptions options, Type classType, MethodInfo methodInfo) { this.ServiceType = classType; this.ServiceName = classType.GetInterfaces().First(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IService <>)).GetGenericArguments()[0].Name; this.MethodInfo = methodInfo; MethodType mt; this.UnwrappedResponseType = UnwrapResponseType(methodInfo, out mt, out responseIsTask, out this.RequestType); this.MethodType = mt; var parameters = methodInfo.GetParameters(); if (RequestType == null) { this.RequestType = MagicOnionMarshallers.CreateRequestTypeAndMarshaller(options.ZeroFormatterTypeResolverType, classType.Name + "/" + methodInfo.Name, parameters, out requestMarshaller); } else { this.requestMarshaller = MagicOnionMarshallers.CreateZeroFormattertMarshallerReflection(options.ZeroFormatterTypeResolverType, RequestType); } this.responseMarshaller = MagicOnionMarshallers.CreateZeroFormattertMarshallerReflection(options.ZeroFormatterTypeResolverType, UnwrappedResponseType); this.AttributeLookup = classType.GetCustomAttributes(true) .Concat(methodInfo.GetCustomAttributes(true)) .Cast <Attribute>() .ToLookup(x => x.GetType()); this.filters = options.GlobalFilters .Concat(classType.GetCustomAttributes <MagicOnionFilterAttribute>(true)) .Concat(methodInfo.GetCustomAttributes <MagicOnionFilterAttribute>(true)) .OrderBy(x => x.Order) .ToArray(); // options this.isReturnExceptionStackTraceInErrorDetail = options.IsReturnExceptionStackTraceInErrorDetail; this.logger = options.MagicOnionLogger; // prepare lambda parameters var contextArg = Expression.Parameter(typeof(ServiceContext), "context"); var contextBind = Expression.Bind(classType.GetProperty("Context"), contextArg); var instance = Expression.MemberInit(Expression.New(classType), contextBind); switch (MethodType) { case MethodType.Unary: case MethodType.ServerStreaming: // (ServiceContext context) => // { // var request = ((Marshaller<TRequest>)context.RequestMarshaller).Deserializer.Invoke(context.Request); // return new FooService() { Context = context }.Bar(request.Item1, request.Item2); // }; { var flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; var marshallerType = typeof(Marshaller <>).MakeGenericType(RequestType); var requestArg = Expression.Parameter(RequestType, "request"); var requestMarshalleExpr = Expression.Convert(Expression.Property(contextArg, typeof(ServiceContext).GetProperty("RequestMarshaller", flags)), marshallerType); var deserializer = Expression.Property(requestMarshalleExpr, "Deserializer"); var callDeserialize = Expression.Call(deserializer, typeof(Func <,>).MakeGenericType(typeof(byte[]), RequestType).GetMethod("Invoke"), Expression.Property(contextArg, typeof(ServiceContext).GetProperty("Request", flags))); var assignRequest = Expression.Assign(requestArg, callDeserialize); Expression[] arguments = new Expression[parameters.Length]; if (parameters.Length == 1) { arguments[0] = requestArg; } else { for (int i = 0; i < parameters.Length; i++) { arguments[i] = Expression.Field(requestArg, "Item" + (i + 1)); } } var callBody = Expression.Call(instance, methodInfo, arguments); if (!responseIsTask) { callBody = Expression.Call(typeof(Task).GetMethod("FromResult").MakeGenericMethod(MethodInfo.ReturnType), callBody); } var body = Expression.Block(new[] { requestArg }, assignRequest, callBody); var compiledBody = Expression.Lambda(body, contextArg).Compile(); this.methodBody = BuildMethodBodyWithFilter((Func <ServiceContext, Task>)compiledBody); } break; case MethodType.ClientStreaming: case MethodType.DuplexStreaming: if (parameters.Length != 0) { throw new InvalidOperationException($"{MethodType} does not support method parameters. If you need to send initial parameter, use header instead."); } // (ServiceContext context) => new FooService() { Context = context }.Bar(); { var body = Expression.Call(instance, methodInfo); if (!responseIsTask) { body = Expression.Call(typeof(Task).GetMethod("FromResult").MakeGenericMethod(MethodInfo.ReturnType), body); } var compiledBody = Expression.Lambda(body, contextArg).Compile(); this.methodBody = BuildMethodBodyWithFilter((Func <ServiceContext, Task>)compiledBody); } break; default: throw new InvalidOperationException("Unknown MethodType:" + MethodType); } // Utility { // (object requestMarshaller, object value) => ((Marshaller<TRequest>)requestMarshaller).Serializer.Invoke((TRequest)value); var marshallerType = typeof(Marshaller <>).MakeGenericType(RequestType); var requestMarshallerArg = Expression.Parameter(typeof(object), "requestMarshaller"); var valueArg = Expression.Parameter(typeof(object), "value"); var serializer = Expression.Property(Expression.Convert(requestMarshallerArg, marshallerType), "Serializer"); var callSerialize = Expression.Call(serializer, typeof(Func <,>).MakeGenericType(RequestType, typeof(byte[])).GetMethod("Invoke"), Expression.Convert(valueArg, RequestType)); boxedRequestSerialize = Expression.Lambda <Func <object, object, byte[]> >(callSerialize, requestMarshallerArg, valueArg).Compile(); } { // (object responseMarshaller, byte[] value) => ((Marshaller<TResponse>)requestMarshaller).Deserializer.Invoke(value); var marshallerType = typeof(Marshaller <>).MakeGenericType(UnwrappedResponseType); var responseMarshallerArg = Expression.Parameter(typeof(object), "responseMarshaller"); var valueArg = Expression.Parameter(typeof(byte[]), "value"); var deserializer = Expression.Property(Expression.Convert(responseMarshallerArg, marshallerType), "Deserializer"); var callDeserialize = Expression.Convert(Expression.Call(deserializer, typeof(Func <,>).MakeGenericType(typeof(byte[]), UnwrappedResponseType).GetMethod("Invoke"), valueArg), typeof(object)); boxedResponseDeserialize = Expression.Lambda <Func <object, byte[], object> >(callDeserialize, responseMarshallerArg, valueArg).Compile(); } }
static ISendMetadataClient() { PangPongMethod = new Method <byte[], byte[]>(MethodType.Unary, "ISendMetadata", "PangPong", MagicOnionMarshallers.ByteArrayMarshaller, MagicOnionMarshallers.ByteArrayMarshaller); PangPongRequestMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(ZeroFormatter.Formatters.Formatter <ZeroFormatter.Formatters.DefaultResolver, byte[]> .Default); PangPongResponseMarshaller = MagicOnionMarshallers.CreateZeroFormatterMarshaller(Formatter <ZeroFormatter.Formatters.DefaultResolver, int> .Default); }