private static async Task <MultipartFormDataContent> CreateContent <T>(IContentSerializer contentSerializer, string projectAlias, object data, IDictionary <string, MultipartItem> files) { var content = new MultipartFormDataContent { Headers = { { Constants.Headers.ProjectAlias, projectAlias } }, }; var postData = await contentSerializer.SerializeAsync(data).ConfigureAwait(false); content.Add(postData, "content"); foreach (var file in files) { content.Add(file.Value.ToContent(), file.Key, file.Value.FileName); } return(content); }
public static string ToQueryString(this object model) { var serialized = serializer.SerializeAsync <object>(model).Result; var deserialized = serializer.DeserializeAsync <Dictionary <string, string> >(serialized).Result; var result = String.Empty; var first = true; foreach (var pair in deserialized) { if (first) { first = false; result += "?"; } else { result += "&"; } result += pair.Key + "=" + pair.Value; } return(result); }
Func <object[], Task <HttpRequestMessage> > BuildRequestFactoryForMethod(RestMethodInfo restMethod, string basePath, bool paramsContainsCancellationToken) { return(async paramList => { // make sure we strip out any cancelation tokens if (paramsContainsCancellationToken) { paramList = paramList.Where(o => o == null || o.GetType() != typeof(CancellationToken)).ToArray(); } var ret = new HttpRequestMessage { Method = restMethod.HttpMethod }; // set up multipart content MultipartFormDataContent multiPartContent = null; if (restMethod.IsMultipart) { multiPartContent = new MultipartFormDataContent("----MyGreatBoundary"); ret.Content = multiPartContent; } var urlTarget = (basePath == "/" ? string.Empty : basePath) + restMethod.RelativePath; var queryParamsToAdd = new List <KeyValuePair <string, string> >(); var headersToAdd = new Dictionary <string, string>(restMethod.Headers); for (var i = 0; i < paramList.Length; i++) { // if part of REST resource URL, substitute it in if (restMethod.ParameterMap.ContainsKey(i)) { urlTarget = Regex.Replace( urlTarget, "{" + restMethod.ParameterMap[i] + "}", Uri.EscapeDataString(settings.UrlParameterFormatter .Format(paramList[i], restMethod.ParameterInfoMap[i]) ?? string.Empty), RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); continue; } // if marked as body, add to content if (restMethod.BodyParameterInfo != null && restMethod.BodyParameterInfo.Item3 == i) { if (paramList[i] is HttpContent httpContentParam) { ret.Content = httpContentParam; } else if (paramList[i] is Stream streamParam) { ret.Content = new StreamContent(streamParam); } // Default sends raw strings else if (restMethod.BodyParameterInfo.Item1 == BodySerializationMethod.Default && paramList[i] is string stringParam) { ret.Content = new StringContent(stringParam); } else { switch (restMethod.BodyParameterInfo.Item1) { case BodySerializationMethod.UrlEncoded: ret.Content = paramList[i] is string str ? (HttpContent) new StringContent(Uri.EscapeDataString(str), Encoding.UTF8, "application/x-www-form-urlencoded") : new FormUrlEncodedContent(new FormValueMultimap(paramList[i], settings)); break; case BodySerializationMethod.Default: #pragma warning disable CS0618 // Type or member is obsolete case BodySerializationMethod.Json: #pragma warning restore CS0618 // Type or member is obsolete case BodySerializationMethod.Serialized: var content = await serializer.SerializeAsync(paramList[i]).ConfigureAwait(false); switch (restMethod.BodyParameterInfo.Item2) { case false: ret.Content = new PushStreamContent( async(stream, _, __) => { using (stream) { await content.CopyToAsync(stream).ConfigureAwait(false); } }, content.Headers.ContentType); break; case true: ret.Content = content; break; } break; } } continue; } // if header, add to request headers if (restMethod.HeaderParameterMap.ContainsKey(i)) { headersToAdd[restMethod.HeaderParameterMap[i]] = paramList[i]?.ToString(); continue; } // ignore nulls if (paramList[i] == null) { continue; } // for anything that fell through to here, if this is not // a multipart method, add the parameter to the query string if (!restMethod.IsMultipart) { var attr = restMethod.ParameterInfoMap[i].GetCustomAttribute <QueryAttribute>() ?? new QueryAttribute(); if (DoNotConvertToQueryMap(paramList[i])) { if (paramList[i] is IEnumerable paramValues) { switch (attr.CollectionFormat) { case CollectionFormat.Multi: foreach (var paramValue in paramValues) { queryParamsToAdd.Add(new KeyValuePair <string, string>( restMethod.QueryParameterMap[i], settings.UrlParameterFormatter.Format(paramValue, restMethod.ParameterInfoMap[i]))); } continue; case CollectionFormat.Csv: case CollectionFormat.Ssv: case CollectionFormat.Tsv: case CollectionFormat.Pipes: var delimiter = attr.CollectionFormat == CollectionFormat.Csv ? "," : attr.CollectionFormat == CollectionFormat.Ssv ? " " : attr.CollectionFormat == CollectionFormat.Tsv ? "\t" : "|"; var formattedValues = paramValues .Cast <object>() .Select(v => settings.UrlParameterFormatter.Format(v, restMethod.ParameterInfoMap[i])); queryParamsToAdd.Add(new KeyValuePair <string, string>( restMethod.QueryParameterMap[i], string.Join(delimiter, formattedValues))); continue; } } queryParamsToAdd.Add(new KeyValuePair <string, string>(restMethod.QueryParameterMap[i], settings.UrlParameterFormatter.Format(paramList[i], restMethod.ParameterInfoMap[i]))); } else { foreach (var kvp in BuildQueryMap(paramList[i], attr.Delimiter)) { var path = !string.IsNullOrWhiteSpace(attr.Prefix) ? $"{attr.Prefix}{attr.Delimiter}{kvp.Key}" : kvp.Key; queryParamsToAdd.Add(new KeyValuePair <string, string>(path, settings.UrlParameterFormatter.Format(kvp.Value, restMethod.ParameterInfoMap[i]))); } } continue; } // we are in a multipart method, add the part to the content // the parameter name should be either the attachment name or the parameter name (as fallback) string itemName; string parameterName; if (!restMethod.AttachmentNameMap.TryGetValue(i, out var attachment)) { itemName = restMethod.QueryParameterMap[i]; parameterName = itemName; } else { itemName = attachment.Item1; parameterName = attachment.Item2; } // Check to see if it's an IEnumerable var itemValue = paramList[i]; var enumerable = itemValue as IEnumerable <object>; var typeIsCollection = enumerable != null; if (typeIsCollection) { foreach (var item in enumerable) { await AddMultipartItemAsync(multiPartContent, itemName, parameterName, item).ConfigureAwait(false); } } else { await AddMultipartItemAsync(multiPartContent, itemName, parameterName, itemValue).ConfigureAwait(false); } } // NB: We defer setting headers until the body has been // added so any custom content headers don't get left out. if (headersToAdd.Count > 0) { // We could have content headers, so we need to make // sure we have an HttpContent object to add them to, // provided the HttpClient will allow it for the method if (ret.Content == null && !bodylessMethods.Contains(ret.Method)) { ret.Content = new ByteArrayContent(new byte[0]); } foreach (var header in headersToAdd) { SetHeader(ret, header.Key, header.Value); } } // NB: The URI methods in .NET are dumb. Also, we do this // UriBuilder business so that we preserve any hardcoded query // parameters as well as add the parameterized ones. var uri = new UriBuilder(new Uri(new Uri("http://api"), urlTarget)); var query = HttpUtility.ParseQueryString(uri.Query ?? ""); foreach (var key in query.AllKeys) { queryParamsToAdd.Insert(0, new KeyValuePair <string, string>(key, query[key])); } if (queryParamsToAdd.Any()) { var pairs = queryParamsToAdd.Where(x => x.Key != null && x.Value != null) .Select(x => Uri.EscapeDataString(x.Key) + "=" + Uri.EscapeDataString(x.Value)); uri.Query = string.Join("&", pairs); } else { uri.Query = null; } ret.RequestUri = new Uri(uri.Uri.GetComponents(UriComponents.PathAndQuery, UriFormat.UriEscaped), UriKind.Relative); return ret; }); }