Exemple #1
0
        public virtual IConsumer Resolve(ConsumerDescriptor descriptor)
        {
            if (descriptor.ModuleDescriptor == null || IsActiveForStore(descriptor.ModuleDescriptor))
            {
                return(_container.Value.ResolveKeyed <IConsumer>(descriptor.ContainerType));
            }

            return(null);
        }
Exemple #2
0
        public virtual IConsumer Resolve(ConsumerDescriptor descriptor)
        {
            if (descriptor.ModuleDescriptor == null || IsActiveForStore(descriptor.ModuleDescriptor))
            {
                return(EngineContext.Current.Scope.ResolveKeyed <IConsumer>(descriptor.ContainerType));
            }

            return(null);
        }
        public virtual Task InvokeAsync <TMessage>(
            ConsumerDescriptor descriptor,
            IConsumer consumer,
            ConsumeContext <TMessage> envelope,
            CancellationToken cancelToken = default) where TMessage : class
        {
            var d           = descriptor;
            var p           = descriptor.WithEnvelope ? (object)envelope : envelope.Message;
            var fastInvoker = FastInvoker.GetInvoker(d.Method);
            var ct          = cancelToken;

            Task task;

            if (d.IsAsync && !d.FireForget)
            {
                // The all async case.
                ct   = _asyncRunner.CreateCompositeCancellationToken(cancelToken);
                task = ((Task)InvokeCore(null, ct));
                task.ContinueWith(t =>
                {
                    if (t.IsFaulted)
                    {
                        HandleException(t.Exception, d);
                    }
                }, TaskContinuationOptions.None);
            }
            else if (d.FireForget)
            {
                // Sync or Async without await. Needs new dependency scope.
                task = d.IsAsync
                    ? _asyncRunner.RunTask((scope, ct) => ((Task)InvokeCore(scope, ct)))
                    : _asyncRunner.Run((scope, ct) => InvokeCore(scope, ct));
                task.ConfigureAwait(false);
            }
            else
            {
                // The all sync case
                try
                {
                    InvokeCore(null, ct);
                }
                catch (Exception ex)
                {
                    HandleException(ex, d);
                }

                task = Task.CompletedTask;
            }

            return(task);

            object InvokeCore(IComponentContext c = null, CancellationToken cancelToken = default)
Exemple #4
0
        public ConsumerRegistry(IEnumerable <Lazy <IConsumer, EventConsumerMetadata> > consumers)
        {
            foreach (var consumer in consumers)
            {
                var metadata = consumer.Metadata;

                if (!metadata.IsActive)
                {
                    continue;
                }

                var methods      = FindMethods(metadata);
                var messageTypes = new Dictionary <Type, MethodInfo>();

                foreach (var method in methods)
                {
                    var descriptor = new ConsumerDescriptor(metadata)
                    {
                        IsAsync    = method.ReturnType == typeof(Task),
                        FireForget = method.HasAttribute <FireForgetAttribute>(false)
                    };

                    //if (descriptor.IsAsync && descriptor.FireForget)
                    //{
                    //	throw new NotSupportedException($"An asynchronous message consumer method cannot be called as fire & forget. Method: '{method}'.");
                    //}

                    if (method.ReturnType != typeof(Task) && method.ReturnType != typeof(void))
                    {
                        throw new NotSupportedException($"A message consumer method's return type must either be 'void' or '${typeof(Task).FullName}'. Method: '{method}'.");
                    }

                    if (method.Name.EndsWith("Async") && !descriptor.IsAsync)
                    {
                        throw new NotSupportedException($"A synchronous message consumer method name should not end with 'Async'. Method: '{method}'.");
                    }

                    var parameters = method.GetParameters();
                    if (parameters.Length == 0)
                    {
                        throw new NotSupportedException($"A message consumer method must have at least one parameter identifying the message to consume. Method: '{method}'.");
                    }

                    if (parameters.Any(x => x.ParameterType.IsByRef || x.IsOut || x.IsOptional))
                    {
                        throw new NotSupportedException($"'out', 'ref' and optional parameters are not allowed in consumer methods. Method: '{method}'.");
                    }

                    var p           = parameters[0];
                    var messageType = p.ParameterType;

                    if (messageType.IsGenericType && messageType.GetGenericTypeDefinition() == typeof(ConsumeContext <>))
                    {
                        messageType             = messageType.GetGenericArguments()[0];
                        descriptor.WithEnvelope = true;
                    }

                    if (messageTypes.TryGetValue(messageType, out var method2))
                    {
                        // We won't allow methods with different signatures, but same message type: there can only be one!
                        throw new AmbigousConsumerException(method2, method);
                    }

                    messageTypes.Add(messageType, method);

                    if (messageType.IsPublic && (messageType.IsClass || messageType.IsInterface))
                    {
                        // The method signature is valid: add to dictionary.
                        descriptor.MessageParameter = p;
                        descriptor.Parameters       = parameters.Skip(1).ToArray();
                        descriptor.MessageType      = messageType;
                        descriptor.Method           = method;

                        _descriptorMap.Add(messageType, descriptor);
                    }
                    else
                    {
                        // TODO: message
                        throw new NotSupportedException();
                    }
                }
            }
        }