public virtual WebMethodContract ResolveMethod(MethodInfo method)
        {
            if (_contracts.ContainsKey(method))
            {
                return(_contracts[method] as WebMethodContract);
            }

            WebMethodAttribute attribute = method.GetCustomAttribute <WebMethodAttribute>() ?? new WebMethodAttribute();

            ParameterInfo[]   parameters = method.GetParameters();
            WebMethodContract contract   = new WebMethodContract(method)
            {
                Method      = attribute.Method,
                Name        = string.IsNullOrWhiteSpace(attribute.Name) ? method.Name : attribute.Name,
                Version     = attribute.Version,
                Return      = ResolveReturn(method.ReturnParameter),
                Parameters  = method.GetParameters().Select(p => ResolveParameter(p)).ToArray(),
                RequiresKey = attribute.RequireKey,
                HasOptions  = parameters.LastOrDefault()?.ParameterType == typeof(RequestOptions) ||
                              (parameters.LastOrDefault()?.ParameterType?.IsSubclassOf(typeof(RequestOptions)) ?? false),
                CanInvoke = method.ReturnType == typeof(void) ||
                            method.ReturnType == typeof(Task) ||
                            method.ReturnType.GetGenericTypeDefinition() == typeof(Task <>)
            };

            _contracts[method] = contract;
            return(contract);
        }
        protected override object Invoke(MethodInfo targetMethod, object[] args)
        {
            WebInterfaceContract @interface = _resolver.ResolveInterface(targetMethod.DeclaringType);
            WebMethodContract    method     = _resolver.ResolveMethod(targetMethod);

            if (!method.CanInvoke)
            {
                throw new MissingMethodException(targetMethod.DeclaringType.Name, targetMethod.Name);
            }

            return(_invoker.InvokeMethod(@interface, method, args));
        }
        public virtual object InvokeMethod(WebInterfaceContract @interface, WebMethodContract method, object[] parameters)
        {
            Type returnType = method.Return.ParameterInfo.ParameterType;

            if (returnType != typeof(void) && returnType != typeof(Task) && returnType.GetGenericTypeDefinition() != typeof(Task <>))
            {
                throw new InvalidOperationException("Cannot invoke method without a return type of void, Task, or Task<T>");
            }

            var interfaceName = @interface.Name;
            var methodName    = method.Name;
            var httpMethod    = method.Method;
            var query         = new (string, string)[method.HasOptions ? parameters.Length - 1 : parameters.Length];