// Helper to build an argument binder for IAsyncCollector<TMessageSrc>
        static Func <TContext, ValueBindingContext, IValueProvider> BuildIAsyncCollectorArgument <TContext, TMessageSrc, TMessage>(
            IConverterManager cm,
            Func <TContext, ValueBindingContext, IFlushCollector <TMessage> > builder,
            string invokeString
            )
        {
            Func <TMessageSrc, TMessage> convert = cm.GetConverter <TMessageSrc, TMessage>();
            Func <TContext, ValueBindingContext, IValueProvider> argumentBuilder = (context, valueBindingContext) =>
            {
                IFlushCollector <TMessage>    raw = builder(context, valueBindingContext);
                IAsyncCollector <TMessageSrc> obj = new TypedAsyncCollectorAdapter <TMessageSrc, TMessage>(raw, convert);
                return(new CommonAsyncCollectorValueProvider <IAsyncCollector <TMessageSrc>, TMessage>(obj, raw, invokeString));
            };

            return(argumentBuilder);
        }
Esempio n. 2
0
 // raw is the underlying object (exposes a Flush method).
 // obj is athe front-end veneer to pass to the user function.
 // calls to obj will trickle through adapters to be calls on raw.
 public CommonAsyncCollectorValueProvider(TUser obj, IFlushCollector <TMessage> raw, string invokeString)
 {
     _raw          = raw;
     _object       = obj;
     _invokeString = invokeString;
 }
 public TypedAsyncCollectorAdapter(IFlushCollector <TDest> inner, Func <TSrc, TDest> convert)
 {
     _inner   = inner;
     _convert = convert;
 }
        // Bind an IAsyncCollector<TMessage> to a user parameter.
        // This handles the various flavors of parameter types and will morph them to the connector.
        // parameter  - parameter being bound.
        // TContext - helper object to pass to the binding the configuration state. This can point back to context like secrets, configuration, etc.
        // builder - function to create a new instance of the underlying Collector object to pass to the parameter.
        //          This binder will wrap that in any adpaters to make it match the requested parameter type.
        public static IBinding BindCollector <TMessage, TContext>(
            ParameterInfo parameter,
            IConverterManager converterManager,
            TContext client,
            Func <TContext, ValueBindingContext, IFlushCollector <TMessage> > builder,
            string invokeString,
            Func <string, TContext> invokeStringBinder)
        {
            Type parameterType = parameter.ParameterType;

            Func <TContext, ValueBindingContext, IValueProvider> argumentBuilder = null;

            if (parameterType.IsGenericType)
            {
                var genericType = parameterType.GetGenericTypeDefinition();
                var elementType = parameterType.GetGenericArguments()[0];

                if (genericType == typeof(IAsyncCollector <>))
                {
                    if (elementType == typeof(TMessage))
                    {
                        // Bind to IAsyncCollector<TMessage>. This is the "purest" binding, no adaption needed.
                        argumentBuilder = (context, valueBindingContext) =>
                        {
                            IFlushCollector <TMessage> raw = builder(context, valueBindingContext);
                            return(new CommonAsyncCollectorValueProvider <IAsyncCollector <TMessage>, TMessage>(raw, raw, invokeString));
                        };
                    }
                    else
                    {
                        // Bind to IAsyncCollector<T>
                        // Get a converter from T to TMessage
                        argumentBuilder = DynamicInvokeBuildIAsyncCollectorArgument(elementType, converterManager, builder, invokeString);
                    }
                }
                else if (genericType == typeof(ICollector <>))
                {
                    if (elementType == typeof(TMessage))
                    {
                        // Bind to ICollector<TMessage> This just needs an Sync/Async wrapper
                        argumentBuilder = (context, valueBindingContext) =>
                        {
                            IFlushCollector <TMessage> raw = builder(context, valueBindingContext);
                            ICollector <TMessage>      obj = new SyncAsyncCollectorAdapter <TMessage>(raw);
                            return(new CommonAsyncCollectorValueProvider <ICollector <TMessage>, TMessage>(obj, raw, invokeString));
                        };
                    }
                    else
                    {
                        // Bind to ICollector<T>.
                        // This needs both a conversion from T to TMessage and an Sync/Async wrapper
                        argumentBuilder = DynamicInvokeBuildICollectorArgument(elementType, converterManager, builder, invokeString);
                    }
                }
            }

            if (parameter.IsOut)
            {
                Type elementType = parameter.ParameterType.GetElementType();

                if (elementType.IsArray)
                {
                    if (elementType == typeof(TMessage[]))
                    {
                        argumentBuilder = (context, valueBindingContext) =>
                        {
                            IFlushCollector <TMessage> raw = builder(context, valueBindingContext);
                            return(new OutArrayValueProvider <TMessage>(raw, invokeString));
                        };
                    }
                    else
                    {
                        // out TMessage[]
                        var e2 = elementType.GetElementType();
                        argumentBuilder = DynamicBuildOutArrayArgument(e2, converterManager, builder, invokeString);
                    }
                }
                else
                {
                    // Single enqueue
                    //    out TMessage
                    if (elementType == typeof(TMessage))
                    {
                        argumentBuilder = (context, valueBindingContext) =>
                        {
                            IFlushCollector <TMessage> raw = builder(context, valueBindingContext);
                            return(new OutValueProvider <TMessage>(raw, invokeString));
                        };
                    }
                    else
                    {
                        // use JSon converter
                        // out T
                        argumentBuilder = DynamicInvokeBuildOutArgument(elementType, converterManager, builder, invokeString);
                    }
                }
            }

            if (argumentBuilder != null)
            {
                ParameterDescriptor param = new ParameterDescriptor {
                    Name         = parameter.Name,
                    DisplayHints = new ParameterDisplayHints
                    {
                        Description = "output"
                    }
                };
                return(new CommonCollectorBinding <TMessage, TContext>(client, argumentBuilder, param, invokeStringBinder));
            }

            string msg = string.Format(CultureInfo.CurrentCulture, "Can't bind to {0}.", parameter);

            throw new InvalidOperationException(msg);
        }
 // raw is the underlying object (exposes a Flush method).
 // obj is athe front-end veneer to pass to the user function.
 // calls to obj will trickle through adapters to be calls on raw.
 public OutArrayValueProvider(IFlushCollector <TMessage> raw, string invokeString)
 {
     _raw          = raw;
     _invokeString = invokeString;
 }