public virtual WebInterfaceContract ResolveInterface(Type type)
        {
            if (_contracts.ContainsKey(type))
            {
                return(_contracts[type] as WebInterfaceContract);
            }

            if (!type.IsInterface)
            {
                throw new ArgumentException($"The provided type {type} is not an interface");
            }

            WebInterfaceContract  contract  = new WebInterfaceContract(type);
            WebInterfaceAttribute attribute = type.GetCustomAttribute <WebInterfaceAttribute>();

            if (attribute == null || string.IsNullOrWhiteSpace(attribute.Name))
            {
                contract.Name = type.Name;
            }
            else
            {
                contract.Name = attribute.Name;
            }

            contract.IsService = attribute?.IsService ?? false;

            _contracts[type] = 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];