Example #1
0
 public ListenableMethod(MethodInfo method, ListenerAttribute listener, Type requestType, Type responseType, Type parameterType, bool usesEnvelope)
 {
     Method        = method;
     Listener      = listener;
     RequestType   = requestType;
     ResponseType  = responseType;
     ParameterType = parameterType;
     UsesEnvelope  = usesEnvelope;
 }
Example #2
0
        // TODO: Change this method to return something like Option<T> with a Success flag and an error message.
        private ListenableMethod GetListenableMethod(MethodInfo method, ListenerAttribute listener)
        {
            Type requestType  = listener.Request.UnwrapEnvelopeType();
            Type responseType = listener.Response.UnwrapEnvelopeType();

            if (method.IsGenericMethodDefinition)
            {
                var numTypeArgs = method.GetGenericArguments().Length;
                if (numTypeArgs > 2)
                {
                    _logger.Error($"Cannot subscribe method {method.Name} because method is generic and there is not enough information to construct it");
                    return(null);
                }

                if (numTypeArgs == 2 && requestType != null && responseType != null)
                {
                    method = method.MakeGenericMethod(requestType, responseType);
                }
                if (numTypeArgs == 1 && (requestType ?? responseType) != null)
                {
                    var typeToUse = requestType ?? responseType;
                    _logger.Warn($"Method {method.Name} has one type argument. Assuming to use {typeToUse.Name}");
                    method = method.MakeGenericMethod(requestType);
                }
            }

            Type parameterType = method.GetParameters().FirstOrDefault()?.ParameterType;

            if (responseType != null && !responseType.IsAssignableFrom(method.ReturnType))
            {
                _logger.Error($"Conflicting response types. {responseType.Name} not assignable from {method.ReturnType.Name}");
                return(null);
            }

            // If the request type implements IRequest<TResponse> we can get the response type from there
            if (responseType == null)
            {
                var definedResponseType = requestType.GetRequestResponseType();
                if (definedResponseType != null)
                {
                    responseType = definedResponseType;
                }
                else
                {
                    responseType = method.ReturnType;
                }
            }

            // Response MyMethod()
            // There is no parameter, so see if we have enough information to construct a trampoline
            if (parameterType == null)
            {
                // We have no type information at all, so we can't do anything
                if (requestType == null)
                {
                    _logger.Error($"Could not determine which channel to use because payload type is not provided and there is no parameter");
                    return(null);
                }

                // This is not a fully-constructed type, so we can't determine a channel for it
                if (requestType.IsGenericType && !requestType.IsConstructedGenericType)
                {
                    _logger.Error($"Payload type {requestType.Name} is not fully-constructed and cannot be used to define a channel");
                    return(null);
                }

                // Use the payload type from the attribute to create a trampoline to a method with no parameters
                return(new ListenableMethod(method, listener, requestType, responseType, null, false));
            }

            // parameterType is the type of the raw parameter, which may include Envelope<>
            // parameterPayloadType is the type of the payload without Envelope<>

            bool isEnvelope           = parameterType.IsEnvelopeType();
            Type parameterPayloadType = parameterType.UnwrapEnvelopeType();

            if (requestType == null)
            {
                requestType = parameterPayloadType;
            }

            // void MyMethod<T>(T payload) or void MyMethod<T>(Envelope<T> payload)
            // This is not a fully-constructed type, so we can't determine a channel for it
            if (requestType.IsGenericType && !requestType.IsConstructedGenericType)
            {
                _logger.Error($"Payload type {requestType.Name} is not fully-constructed and cannot be used");
                return(null);
            }

            // Check that the type information between parameter and specified payload type are assignable
            if (!parameterPayloadType.IsAssignableFrom(requestType))
            {
                _logger.Error($"Cannot subscribe method {method.Name} because specified payload type {requestType.Name} is not assignable to parameter type {parameterPayloadType.Name}");
                return(null);
            }

            return(new ListenableMethod(method, listener, requestType, responseType, parameterType, isEnvelope));
        }