private static BinderConfiguration CreateBinderConfiguration() { return(BinderConfiguration.Create(new[] { ProtoBufMarshallerFactory.Create(CreateModel(), ProtoBufMarshallerFactory.Options.None) })); }
public static BinderConfiguration CreateBinderConfiguration(ServiceBinder?serviceBinder = null) => BinderConfiguration.Create(new[] { ProtoBufMarshallerFactory.Create(ProtoBufSerializer.TypeModel) }, serviceBinder);
internal static Func <CallInvoker, TService> EmitFactory <TService>(BinderConfiguration binderConfig) { Type baseType = typeof(ClientBase); var callInvoker = baseType.GetProperty("CallInvoker", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)?.GetGetMethod(true); if (callInvoker == null || callInvoker.ReturnType != typeof(CallInvoker) || callInvoker.GetParameters().Length != 0) { throw new ArgumentException($"The base-type {baseType} for service-proxy {typeof(TService)} lacks a suitable CallInvoker API"); } lock (s_module) { // private sealed class IFooProxy... var type = s_module.DefineType(ProxyIdentity + "." + baseType.Name + "." + typeof(TService).Name + "_Proxy_" + _typeIndex++, TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.NotPublic | TypeAttributes.BeforeFieldInit); type.SetParent(baseType); // public IFooProxy(CallInvoker callInvoker) : base(callInvoker) { } var ctorCallInvoker = WritePassThruCtor <CallInvoker>(MethodAttributes.Public); // override ToString { var baseToString = typeof(object).GetMethod(nameof(object.ToString)) !; var toString = type.DefineMethod(nameof(ToString), baseToString.Attributes, baseToString.CallingConvention, typeof(string), Type.EmptyTypes); var il = toString.GetILGenerator(); if (!binderConfig.Binder.IsServiceContract(typeof(TService), out var primaryServiceName)) { primaryServiceName = typeof(TService).Name; } il.Emit(OpCodes.Ldstr, primaryServiceName + " / " + typeof(CallInvoker).Name); il.Emit(OpCodes.Ret); type.DefineMethodOverride(toString, baseToString); } const string InitMethodName = "Init"; var cctor = type.DefineMethod(InitMethodName, MethodAttributes.Static | MethodAttributes.Public).GetILGenerator(); var ops = ContractOperation.FindOperations(binderConfig, typeof(TService), null); int marshallerIndex = 0; Dictionary <Type, (FieldBuilder Field, string Name, object Instance)> marshallers = new Dictionary <Type, (FieldBuilder, string, object)>(); FieldBuilder Marshaller(Type forType) { if (marshallers.TryGetValue(forType, out var val)) { return(val.Field); } var instance = s_marshallerCacheGenericMethodDef.MakeGenericMethod(forType).Invoke(binderConfig.MarshallerCache, Array.Empty <object>()) !; var name = "_m" + marshallerIndex++; var field = type.DefineField(name, typeof(Marshaller <>).MakeGenericType(forType), FieldAttributes.Static | FieldAttributes.Private); // **not** readonly, we need to set it afterwards! marshallers.Add(forType, (field, name, instance)); return(field); } int fieldIndex = 0; foreach (var iType in ContractOperation.ExpandInterfaces(typeof(TService))) { bool isService = binderConfig.Binder.IsServiceContract(iType, out var serviceName); // : TService type.AddInterfaceImplementation(iType); // add each method of the interface foreach (var iMethod in iType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) { var pTypes = Array.ConvertAll(iMethod.GetParameters(), x => x.ParameterType); var impl = type.DefineMethod(iType.Name + "." + iMethod.Name, MethodAttributes.HideBySig | MethodAttributes.Final | MethodAttributes.NewSlot | MethodAttributes.Private | MethodAttributes.Virtual, iMethod.CallingConvention, iMethod.ReturnType, pTypes); // mark it as the interface implementation type.DefineMethodOverride(impl, iMethod); var il = impl.GetILGenerator(); if (!(isService && ContractOperation.TryIdentifySignature(iMethod, binderConfig, out var op, null))) { il.ThrowException(typeof(NotSupportedException)); continue; } Type[] fromTo = new Type[] { op.From, op.To }; // private static Method<from, to> s_{i} var field = type.DefineField("s_op_" + fieldIndex++, typeof(Method <,>).MakeGenericType(fromTo), FieldAttributes.Static | FieldAttributes.Private); // = new Method<from, to>(methodType, serviceName, opName, requestMarshaller, responseMarshaller); Ldc_I4(cctor, (int)op.MethodType); // methodType cctor.Emit(OpCodes.Ldstr, serviceName ?? ""); // serviceName cctor.Emit(OpCodes.Ldstr, op.Name); // opName cctor.Emit(OpCodes.Ldsfld, Marshaller(op.From)); // requestMarshaller cctor.Emit(OpCodes.Ldsfld, Marshaller(op.To)); // responseMarshaller cctor.Emit(OpCodes.Newobj, typeof(Method <,>).MakeGenericType(fromTo) .GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).Single()); // new Method cctor.Emit(OpCodes.Stsfld, field); // implement the method switch (op.Context) { case ContextKind.CallOptions: // we only support this for signatures that match the exat google pattern, but: // defer for now il.ThrowException(typeof(NotImplementedException)); break; case ContextKind.NoContext: case ContextKind.CallContext: case ContextKind.CancellationToken: // typically looks something like (where this is an extension method on Reshape): // => context.{ReshapeMethod}(CallInvoker, {method}, request, [host: null]); var method = op.TryGetClientHelper(); if (method == null) { // unexpected, but... il.ThrowException(typeof(NotSupportedException)); } else { switch (op.Context) { case ContextKind.CallContext: Ldarga(il, op.VoidRequest ? (ushort)1 : (ushort)2); break; case ContextKind.CancellationToken: var callContext = il.DeclareLocal(typeof(CallContext)); Ldarg(il, op.VoidRequest ? (ushort)1 : (ushort)2); il.EmitCall(OpCodes.Call, s_CallContext_FromCancellationToken, null); Stloc(il, callContext); Ldloca(il, callContext); break; case ContextKind.NoContext: il.Emit(OpCodes.Ldsflda, s_CallContext_Default); break; default: // shouldn't get here - we checked above! this is in case of code maintenance errors throw new NotImplementedException($"Unhandled context kind: {op.Context}"); } il.Emit(OpCodes.Ldarg_0); // this. il.EmitCall(OpCodes.Callvirt, callInvoker, null); // get_CallInvoker il.Emit(OpCodes.Ldsfld, field); // {method} if (op.VoidRequest) { il.Emit(OpCodes.Ldsfld, s_Empty_Instance); // Empty.Instance } else { il.Emit(OpCodes.Ldarg_1); // request } il.Emit(OpCodes.Ldnull); // host (always null) il.EmitCall(OpCodes.Call, method, null); il.Emit(OpCodes.Ret); // return } break; case ContextKind.ServerCallContext: // server call? we're writing a client! default: // who knows! il.ThrowException(typeof(NotSupportedException)); break; } } } cctor.Emit(OpCodes.Ret); // end the type initializer (after creating all the field types) #if NETSTANDARD2_0 var finalType = type.CreateTypeInfo() !; #else var finalType = type.CreateType() !; #endif // assign the marshallers and invoke the init foreach ((var field, var name, var instance) in marshallers.Values) { finalType.GetField(name, BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Public) !.SetValue(null, instance); } finalType.GetMethod(InitMethodName, BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Public) !.Invoke(null, Array.Empty <object>()); // return the factory var p = Expression.Parameter(typeof(CallInvoker), "channel"); return(Expression.Lambda <Func <CallInvoker, TService> >( Expression.New(finalType.GetConstructor(new[] { typeof(CallInvoker) }) !, p), p).Compile()); ConstructorBuilder?WritePassThruCtor <T>(MethodAttributes accessibility) { var signature = new[] { typeof(T) }; var baseCtor = baseType.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, signature, null); if (baseCtor == null) { return(null); } var ctor = type.DefineConstructor(accessibility, CallingConventions.HasThis, signature); var il = ctor.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Call, baseCtor); il.Emit(OpCodes.Ret); return(ctor); } } }
public IBinder(BinderConfiguration configuration) { Configuration = configuration; }