/// <summary> /// Checks a parameter for any <see cref="SendAsHeaderAttribute"/> attributes. /// </summary> /// <param name="requestBuilder">A request builder instance.</param> /// <param name="attrs">The parameters attributes.</param> /// <param name="argument">The parameters actual value.</param> /// <returns>The request builder instance.</returns> internal static HttpRequestBuilder CheckParameterForSendAsHeader( this HttpRequestBuilder requestBuilder, IEnumerable <Attribute> attrs, object argument) { void AddHeader(string name, string format, object arg) { if (string.IsNullOrEmpty(format) == false) { requestBuilder.AddHeader( name, string.Format(format, arg.ToString())); } else { requestBuilder.AddHeader( name, arg.ToString()); } } foreach (var attr in attrs.OfType <SendAsHeaderAttribute>()) { if (typeof(IEnumerable <string>).IsAssignableFrom(argument.GetType()) == true) { foreach (var item in (IEnumerable <string>)argument) { AddHeader(attr.Name, attr.Format, item); } } else { AddHeader(attr.Name, attr.Format, argument); } } return(requestBuilder); }
/// <summary> /// Adds the method headers to a <see cref="HttpRequestBuilder"/>. /// </summary> /// <param name="requestBuilder">A <see cref="HttpRequestBuilder"/> instance.</param> /// <param name="method">The <see cref="MethodInfo"/>.</param> /// <param name="names">A list of keys.</param> /// <param name="values">A list of values.</param> /// <returns>The <see cref="HttpRequestBuilder"/> instance.</returns> public static HttpRequestBuilder AddMethodHeaders( this HttpRequestBuilder requestBuilder, MethodInfo method, IEnumerable <string> names, IEnumerable <object> values) { var headerAttrs = method .GetCustomAttributes <AddHeaderAttribute>() .Union( method.DeclaringType.GetCustomAttributes <AddHeaderAttribute>()); if (headerAttrs.Any() == true) { foreach (var attr in headerAttrs) { requestBuilder.AddHeader( attr.Header, attr.Value.ExpandString(names, values)); } } return(requestBuilder); }
/// <summary> /// Checks a parameter for attributes. /// </summary> /// <param name="requestBuilder">The request builder.</param> /// <param name="parm">The parameter.</param> /// <param name="argument">The parameters value.</param> /// <param name="uri">A variable to receive a Uri.</param> /// <param name="formUrlContent">A variable to receive the a value indicating whether or not there is form url content.</param> /// <param name="contentDisposition">A variable to receive the a value indicating whether or not there is content disposition.</param> internal void CheckParameterAttributes( HttpRequestBuilder requestBuilder, ParameterInfo parm, object argument, out string uri, out bool formUrlContent, out bool contentDisposition) { uri = null; formUrlContent = false; contentDisposition = false; var attrs = parm.GetCustomAttributes(); if (attrs == null || attrs.Any() == false || argument == null) { return; } /* * if (requestBuilder.IsContentSet == true) * { * return; * } */ var urlAttr = attrs.OfType <UriAttribute>().FirstOrDefault(); if (urlAttr != null) { uri = argument.ToString(); } var sendAsAttr = attrs.OfType <SendAsContentAttribute>().FirstOrDefault(); if (sendAsAttr != null) { if (typeof(HttpContent).IsAssignableFrom(parm.ParameterType) == true) { requestBuilder.SetContent((HttpContent)argument); } else if (typeof(Stream).IsAssignableFrom(parm.ParameterType) == true) { requestBuilder.SetContent(new StreamContent((Stream)argument)); } else { string contType = sendAsAttr.ContentType ?? this.contentType; var serializer = this.options.GetObjectSerializer(contType); if (serializer == null) { throw new NotSupportedException($"Serializer for {contType} not found"); } requestBuilder.SetContent(new StringContent( serializer.SerializeObject(argument), sendAsAttr.Encoding ?? Encoding.UTF8, serializer.ContentType)); } return; } var formUrlAttr = attrs.OfType <SendAsFormUrlAttribute>().FirstOrDefault(); if (formUrlAttr != null) { formUrlContent = true; var argType = argument.GetType(); if (argument is Dictionary <string, string> strStrDictionayArgument) { requestBuilder.SetContent( new FormUrlEncodedContent( (Dictionary <string, string>)argument)); } else if (argument is Dictionary <string, object> strObjDictionaryArgument) { requestBuilder.SetContent( new FormUrlEncodedContent( ((Dictionary <string, object>)argument) .Select( kvp => { return(new KeyValuePair <string, string>( kvp.Key, kvp.Value?.ToString())); }))); } else if (parm.ParameterType.IsModelObject() == true) { var list = new Dictionary <string, string>(); var properties = argument.GetType().GetProperties(); foreach (var property in properties) { list.Add( property.Name, property.GetValue(argument)?.ToString()); } requestBuilder.SetContent(new FormUrlEncodedContent(list)); } else { requestBuilder.AddFormUrlProperty( formUrlAttr.Name ?? parm.Name, argument.ToString()); } return; } var contentDispAttr = attrs.OfType <SendAsContentDispositionAttribute>().FirstOrDefault(); if (contentDispAttr != null) { contentDisposition = true; requestBuilder.SetMultipartContent(true); if (contentDispAttr.IsName == true) { requestBuilder.SetContentDispositionHeader(c => c.Name = (string)argument); } else if (contentDispAttr.IsFileName == true) { requestBuilder.SetContentDispositionHeader(c => c.FileName = (string)argument); } else if (contentDispAttr.IsFileNameStar) { requestBuilder.SetContentDispositionHeader(c => c.FileNameStar = (string)argument); } return; } requestBuilder .CheckParameterForSendAsQuery(attrs, parm, argument) .CheckParameterForSendAsHeader(attrs, argument); }
/// <summary> /// Checks the arguments for specific ones. /// </summary> /// <param name="requestBuilder">A request builder.</param> /// <param name="uri">A variable to receive a Uri.</param> /// <returns>An array of argument names.</returns> private string[] CheckArgsAndBuildRequest( HttpRequestBuilder requestBuilder, out string uri) { uri = null; var responseAttr = this.MethodInfo.GetMethodOrTypeAttribute <HttpResponseProcessorAttribute>(); if (responseAttr != null) { this.responseProcessorType = responseAttr.ResponseProcesorType; } var formUrlAttrs = this.MethodInfo.GetCustomAttributes <AddFormUrlEncodedPropertyAttribute>(); if (formUrlAttrs.Any() == true) { foreach (var attr in formUrlAttrs) { requestBuilder.AddFormUrlProperty(attr.Key, attr.Value); } } Type returnType = this.MethodInfo.ReturnType; if (returnType.IsAsync(out Type taskType) == true) { returnType = taskType; } bool formUrlContent = false; bool contentDisposition = false; ParameterInfo[] parms = this.MethodInfo.GetParameters(); if (parms == null) { return(new string[0]); } string[] names = new string[parms.Length]; for (int i = 0; i < parms.Length; i++) { names[i] = parms[i].Name; Type parmType = parms[i].ParameterType; if (parms[i].IsOut == true) { var fromHeader = parms[i].GetCustomAttribute <FromHeaderAttribute>(); if (fromHeader != null) { this.fromHeaders = this.fromHeaders ?? new Dictionary <int, string>(); this.fromHeaders.Add(i, fromHeader.Name); } else { var fromResponse = parms[i].GetCustomAttribute <FromResponseAttribute>(); if (fromResponse != null) { this.fromResponses = this.fromResponses ?? new Dictionary <int, Tuple <FromResponseAttribute, Type> >(); this.fromResponses.Add(i, Tuple.Create(fromResponse, parmType.GetElementType())); } else { var elemParmType = parms[i].ParameterType.GetElementType(); if (elemParmType == typeof(HttpResponseMessage)) { this.responseArg = i; } else { this.dataArg = i; this.dataArgType = parmType; } } } continue; } if (returnType != typeof(void) && parmType == typeof(Func <,>).MakeGenericType(typeof(HttpResponseMessage), returnType)) { this.responseFuncArg = i; } else if (parmType == typeof(Action <HttpRequestMessage>)) { this.requestAction = (Action <HttpRequestMessage>) this.Arguments[i]; } else if (parmType == typeof(Action <HttpResponseMessage>)) { this.responseAction = (Action <HttpResponseMessage>) this.Arguments[i]; } else if (parmType == typeof(CancellationTokenSource)) { this.cancellationTokenSource = (CancellationTokenSource)this.Arguments[i]; } else if (parmType == typeof(CancellationToken)) { this.cancellationToken = (CancellationToken)this.Arguments[i]; } else if (parmType == typeof(IUriBuilder)) { uri = ((IUriBuilder)this.Arguments[i]).BuildUri().ToString(); } else { this.CheckParameterAttributes( requestBuilder, parms[i], this.Arguments[i], out string parmUri, out formUrlContent, out contentDisposition); if (parmUri != null) { uri = parmUri; } if (formUrlContent == false && requestBuilder.IsContentSet == false && parms[i].ParameterType.IsModelObject() == true) { var serializer = this.options.GetObjectSerializer(this.contentType); if (serializer == null) { throw new NotSupportedException($"Serializer for {this.contentType} not found"); } requestBuilder.SetContent(new StringContent( serializer.SerializeObject(this.Arguments[i]), Encoding.UTF8, this.contentType)); } } } return(names); }
/// <summary> /// Builds a request, sends it, and proecesses the response. /// </summary> /// <param name="httpMethod">The http method.</param> /// <param name="baseUri">The base Uri.</param> /// <param name="uriPath">The Uri path.</param> /// <param name="contentType">The content type.</param> /// <param name="timeout">A value representing the request timeout.</param> /// <returns>The result of the request.</returns> public async Task <object> BuildAndSendRequestAsync( HttpMethod httpMethod, string baseUri, string uriPath, string contentType, TimeSpan?timeout) { var requestBuilder = new HttpRequestBuilder() .SetMethod(httpMethod) .SetHttpVersion(this.options.HttpVersion); var names = this.CheckArgsAndBuildRequest(requestBuilder, out string uri); if (string.IsNullOrWhiteSpace(uri) == false) { baseUri = uri; } requestBuilder .AddMethodHeaders(this.MethodInfo, names, this.Arguments) .SetUri(Utility.CombineUri(baseUri, uriPath.ExpandString(names, this.Arguments))); Type returnType = this.MethodInfo.ReturnType; await requestBuilder.AddAuthorizationHeaderAsync( this.MethodInfo, names, this.Arguments, this.options.Services); HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead; if (returnType == typeof(HttpResponseMessage) || returnType == typeof(Task <HttpResponseMessage>) || returnType == typeof(Task <Stream>)) { completionOption = HttpCompletionOption.ResponseHeadersRead; } if (timeout.HasValue == true) { this.SetTimeout(timeout.Value); } var httpRequestSenderFactory = this.options.Services?.GetService <IHttpRequestSenderFactory>(); var httpClient = this.options.GetHttpClient(); var requestSender = httpRequestSenderFactory?.CreateRequestSender(httpClient, this) ?? new HttpRequestSender(httpClient, this); if (returnType.IsAsync(out Type taskType) == true && taskType != typeof(void)) { Type asyncType = typeof(AsyncCall <>).MakeGenericType(taskType); object obj = Activator.CreateInstance(asyncType, requestSender, this); var mi = asyncType.GetMethod("SendAsync", new Type[] { typeof(HttpRequestBuilder), typeof(HttpCompletionOption) }); return(mi.Invoke(obj, new object[] { requestBuilder, completionOption })); } var response = await requestSender .SendAsync( requestBuilder, completionOption) .ConfigureAwait(false); return(await this.ProcessResultAsync( response, returnType)); }
/// <summary> /// Checks a parameter for any <see cref="SendAsQueryAttribute"/> attributes. /// </summary> /// <param name="requestBuilder">A request builder instance.</param> /// <param name="attrs">The parameters attributes.</param> /// <param name="parm">The parameter.</param> /// <param name="argument">The parameters actual value.</param> /// <returns>The request builder instance.</returns> internal static HttpRequestBuilder CheckParameterForSendAsQuery( this HttpRequestBuilder requestBuilder, IEnumerable <Attribute> attrs, ParameterInfo parm, object argument) { foreach (var query in attrs.OfType <SendAsQueryAttribute>()) { var name = query.Name.IsNullOrEmpty() == false ? query.Name : parm.Name; if (parm.ParameterType.IsGenericType == true) { if (parm.ParameterType.GetGenericTypeDefinition() == typeof(IDictionary <,>)) { IDictionary <string, string> queryMap = null; if (typeof(IDictionary <string, string>).IsAssignableFrom(parm.ParameterType) == true) { queryMap = (IDictionary <string, string>)argument; } else if (typeof(IDictionary <object, object>).IsAssignableFrom(parm.ParameterType) == true) { queryMap = ((IDictionary <object, object>)argument) .ToDictionary(key => key.Key.ToString(), value => value.Value.ToString()); } else if (typeof(IDictionary <string, object>).IsAssignableFrom(parm.ParameterType) == true) { queryMap = ((IDictionary <string, object>)argument) .ToDictionary(key => key.Key, value => value.Value.ToString()); } else if (typeof(IDictionary <object, string>).IsAssignableFrom(parm.ParameterType) == true) { queryMap = ((IDictionary <object, string>)argument) .ToDictionary(key => key.Key.ToString(), value => value.Value); } if (query != null) { foreach (var item in queryMap) { var value = parm.ConvertParameterValue(item.Value, query.Format, query.Base64, query.Encoding); requestBuilder.AddQueryString(item.Key, value); } } } else if (typeof(IEnumerable <string>).IsAssignableFrom(parm.ParameterType) == true) { foreach (var item in (IEnumerable <string>)argument) { var value = parm.ConvertParameterValue(item, query.Format, query.Base64, query.Encoding); requestBuilder.AddQueryString(name, value); } } } else { var value = parm.ConvertParameterValue(argument, query.Format, query.Base64, query.Encoding); requestBuilder.AddQueryString(name, value); } } return(requestBuilder); }