/// <summary> /// Adds StringContent containing a json string of the supplied body object /// </summary> /// <typeparam name="T">The type of body</typeparam> /// <param name="request">The SolidHttpRequest</param> /// <param name="body">The request body object</param> /// <param name="settings">(Optional) JsonSerializerSettings to use to serialize the body object</param> /// <returns>SolidHttpRequest</returns> public static ISolidHttpRequest WithJsonContent <T>(this ISolidHttpRequest request, T body, JsonSerializerSettings settings = null) { var json = JsonConvert.SerializeObject(body, settings ?? request.GetJsonSerializerSettings()); var content = new StringContent(json, Encoding.UTF8, "application/json"); return(request.WithContent(content)); }
/// <summary> /// Adds form data content to the inner <see cref="HttpRequestMessage" />. /// </summary> /// <param name="request">The <see cref="ISolidHttpRequest" /> that is being extended.</param> /// <param name="name">The form name of the <see cref="HttpContent" />.</param> /// <param name="content">The <see cref="HttpContent" /> to add.</param> /// <returns>The <see cref="ISolidHttpRequest" /> so that additional calls can be chained.</returns> public static ISolidHttpRequest WithFormDataContent(this ISolidHttpRequest request, string name, HttpContent content) { var form = request.GetMultipartFormDataContent(); form.Add(content, name); return(request); }
private static ISolidHttpRequest WithMultipartContent(this ISolidHttpRequest request, Func <MultipartContent> create) { var content = request.BaseRequest.Content; var multipart = content as MultipartContent; var contents = Enumerable.Empty <HttpContent>(); if (multipart != null) { contents = multipart; } else if (content != null) { contents = new[] { content } } ; var m = create(); // TODO: Make sure the headers aren't gonna be a problem foreach (var c in contents) { m.Add(c); } request.BaseRequest.Content = m; return(request); } }
/// <summary> /// Adds form data file to the inner <see cref="HttpRequestMessage" />. /// </summary> /// <param name="request">The <see cref="ISolidHttpRequest" /> that is being extended.</param> /// <param name="name">The form name of the file.</param> /// <param name="content">The file <see cref="ByteArrayContent" />.</param> /// <param name="fileName">The file name.</param> /// <returns>The <see cref="ISolidHttpRequest" /> so that additional calls can be chained.</returns> public static ISolidHttpRequest WithFormDataFile(this ISolidHttpRequest request, string name, ByteArrayContent content, string fileName) { var form = request.GetMultipartFormDataContent(); form.Add(content, name, fileName); return(request); }
/// <summary> /// Deserializes the response content as the specified type using the specified settings /// </summary> /// <typeparam name="T">The type of response body</typeparam> /// <param name="request">The SolidHttpRequest</param> /// <param name="settings">The specified DataContractSerializerSettings</param> /// <returns>Task of type T</returns> public static async Task <T> As <T>(this ISolidHttpRequest request, DataContractSerializerSettings settings) { var factory = new XmlResponseDeserializerFactory(settings); var deserialize = factory.CreateDeserializer <T>(); return(await request.As <T>(deserialize)); }
/// <summary> /// Returns the content as a GzipStream, caller is responsable for disposing the stream /// </summary> /// <param name="request">The extended ISolidHttpRequest</param> /// <param name="mode">The zip archive mode</param> /// <returns>An awaitable task</returns> public static Task <ZipArchive> AsZipArchive(this ISolidHttpRequest request, ZipArchiveMode mode = ZipArchiveMode.Read) { var factory = new ZipArchiveResponseDeserializerFactory(mode); var deserialize = factory.CreateDeserializer <ZipArchive>(); return(request.As <ZipArchive>()); }
/// <summary> /// Performs an async assertion against the http response message /// </summary> /// <param name="request">The Solid.Http request</param> /// <param name="assert">The async assertion action</param> /// <returns>The fluent assertion</returns> public static Assertion Should(this ISolidHttpRequest request, Func <HttpResponseMessage, Task> assert) { var assertion = new Assertion(request); assertion.Request.OnHttpResponse(async(_, response) => await assert(response)); return(assertion); }
/// <summary> /// Deserializes <see cref="HttpContent" /> into <typeparamref name="T" />. /// </summary> /// <typeparam name="T">The type to deserialize as.</typeparam> /// <param name="request">The <see cref="ISolidHttpRequest" /> that is being extended.</param> /// <returns>A <see cref="ValueTask{T}" /> of type <typeparamref name="T" />.</returns> public static ValueTask <T> As <T>(this ISolidHttpRequest request) { var provider = request.Services.GetService <DeserializerProvider>(); return(request .As(content => content.ReadAsAsync <T>(provider)) ); }
/// <summary> /// Deserializes an XML <see cref="HttpContent" /> as <typeparamref name="T" /> using the /// specified serializer settings. /// </summary> /// <typeparam name="T">The type of response body.</typeparam> /// <param name="request">The <see cref="ISolidHttpRequest" /> that is being extended.</param> /// <param name="settings">The specified <see cref="DataContractSerializerSettings" />.</param> /// <returns><see cref="ValueTask{T}" /> of type <typeparamref name="T" /></returns> public static ValueTask <T> As <T>(this ISolidHttpRequest request, DataContractSerializerSettings settings) { return(request.As <T>((services, content) => { var deserializer = services.GetService <DataContractXmlDeserializer>(); return deserializer.DeserializeAsync <T>(content, settings); })); }
/// <summary> /// Adds a query parameter to the url of the <see cref="ISolidHttpRequest"/>. /// </summary> /// <param name="request">The <see cref="ISolidHttpRequest"/> that is being extended.</param> /// <param name="parameters">The query parameters to be added.</param> /// <returns>The <see cref="ISolidHttpRequest"/> so that additional calls can be chained.</returns> public static ISolidHttpRequest WithQueryParameters(this ISolidHttpRequest request, IDictionary <string, string> parameters) { foreach (var parameter in parameters) { request.WithQueryParameter(parameter.Key, parameter.Value, o => o.ConvertToStrings()); } return(request); }
/// <summary> /// Adds headers to the <see cref="ISolidHttpRequest"/>. /// </summary> /// <param name="request">The <see cref="ISolidHttpRequest"/> that is being extended.</param> /// <param name="parameters">The headers to be added.</param> /// <returns>The <see cref="ISolidHttpRequest"/> so that additional calls can be chained.</returns> public static ISolidHttpRequest WithHeaders(this ISolidHttpRequest request, IDictionary <string, string> parameters) { foreach (var parameter in parameters) { request.WithHeader(parameter.Key, parameter.Value); } return(request); }
/// <summary> /// Replaces a templated parameter in the url /// </summary> /// <param name="request">The SolidHttpRequest</param> /// <param name="name">The name of the templated parameter</param> /// <param name="value">The value to inject</param> /// <returns>SolidHttpRequest</returns> public static ISolidHttpRequest WithNamedParameter(this ISolidHttpRequest request, string name, string value) { var url = request.BaseRequest.RequestUri.OriginalString; var regex = new Regex($@"{{\s*{name}\s*}}"); url = regex.Replace(url, value); request.BaseRequest.RequestUri = new Uri(url, UriKind.RelativeOrAbsolute); return(request); }
/// <summary> /// Deserializes a JSON <see cref="HttpContent" /> as <typeparamref name="T" /> using the /// specified serializer settings. /// </summary> /// <typeparam name="T">The type of response body.</typeparam> /// <param name="request">The <see cref="ISolidHttpRequest" /> that is being extended.</param> /// <param name="options">The specified <see cref="JsonSerializerOptions" />.</param> /// <returns><see cref="ValueTask{T}" /> of type <typeparamref name="T" /></returns> public static async ValueTask <T> As <T>(this ISolidHttpRequest request, JsonSerializerOptions options) { return(await request.As <T>(async content => { using (var stream = await content.ReadAsStreamAsync()) { return await JsonSerializer.DeserializeAsync <T>(stream, options); } })); }
/// <summary> /// Map a handler that is run on a specific condition defined by <paramref name="predicate" />. /// </summary> /// <param name="request">The <see cref="ISolidHttpRequest" /> that is being extended.</param> /// <param name="predicate">The predicate</param> /// <param name="handler">The handler to run when <paramref name ="predicate" /> returns true.</param> /// <returns>The <see cref="ISolidHttpRequest" /> so that additional calls can be chained.</returns> public static ISolidHttpRequest On(this ISolidHttpRequest request, Func <HttpResponseMessage, bool> predicate, Func <IServiceProvider, HttpResponseMessage, ValueTask> handler) { request.OnHttpResponse(async(services, response) => { if (predicate(response)) { await handler(services, response); } }); return(request); }
/// <summary> /// Map a handler to a specific http status code /// </summary> /// <param name="request">The ISolidHttpRequest</param> /// <param name="predicate">The predicate</param> /// <param name="handler">The handler</param> /// <returns>SolidHttpRequest</returns> public static ISolidHttpRequest On(this ISolidHttpRequest request, Func <HttpResponseMessage, bool> predicate, Action <IServiceProvider, HttpResponseMessage> handler) { request.OnResponse((services, response) => { if (predicate(response)) { handler(services, response); } }); return(request); }
private static MultipartFormDataContent GetMultipartFormDataContent(this ISolidHttpRequest request) { var multipart = request.BaseRequest.Content as MultipartFormDataContent; if (multipart == null) { multipart = request.WithMultipartContent(() => new MultipartFormDataContent()).BaseRequest.Content as MultipartFormDataContent; } return(multipart); }
/// <summary> /// Adds <see cref="HttpContent" /> to the inner <seealso cref="HttpRequestMessage" />. /// <para>If there is already <see cref="HttpContent" /> on the <seealso cref="HttpRequestMessage" />, it makes the request multipart.</para> /// </summary> /// <param name="request">The <see cref="ISolidHttpRequest" /> that is being extended.</param> /// <param name="content">The <see cref="HttpContent" /> to add to the <seealso cref="HttpRequestMessage" />.await</param> /// <returns>The <see cref="ISolidHttpRequest" /> so that additional calls can be chained.</returns> public static ISolidHttpRequest WithContent(this ISolidHttpRequest request, HttpContent content) { if (request.BaseRequest.Content == null) { request.BaseRequest.Content = content; return(request); } var multipart = request.WithMultipartContent(() => new MultipartContent()).BaseRequest.Content as MultipartContent; multipart.Add(content); return(request); }
/// <summary> /// Adds <see cref="StringContent" /> containing a json string of type <typeparamref name="T" />. /// </summary> /// <typeparam name="T">The type of body</typeparam> /// <param name="request">The <see cref="ISolidHttpRequest" /> that is being extended.</param> /// <param name="body">The request body object of type <typeparamref name="T" />.</param> /// <param name="contentType">(Optional) The content type header value.</param> /// <param name="settings">(Optional) <see cref="JsonSerializerSettings" /> to use to serialize the <paramref name="body" />..</param> /// <returns>The <see cref="ISolidHttpRequest" /> so that additional calls can be chained.</returns> public static ISolidHttpRequest WithNewtonsoftJsonContent <T>(this ISolidHttpRequest request, T body, string contentType = "application/json", JsonSerializerSettings settings = null) { if (settings == null) { settings = request.Services.GetService <IOptions <SolidHttpNewtonsoftJsonOptions> >().Value.SerializerSettings; } var json = JsonConvert.SerializeObject(body, settings); var content = new StringContent(json, Encoding.UTF8, contentType); return(request.WithContent(content)); }
/// <summary> /// Deserializes an ZIP <see cref="HttpContent" /> as <seealso cref="ZipArchive" />. /// </summary> /// <param name="request">The <see cref="ISolidHttpRequest" /> that is being extended.</param> /// <param name="mode">(Optional) The specified <see cref="ZipArchiveMode" />.</param> /// <returns><see cref="ValueTask{T}" /> of type <see cref="ZipArchive" /></returns> public static ValueTask <ZipArchive> AsZipArchive(this ISolidHttpRequest request, ZipArchiveMode?mode = null) { if (!mode.HasValue) { return(request.As <ZipArchive>()); } return(request.As <ZipArchive>((services, content) => { var deserializer = services.GetService <ZipArchiveDeserializer>(); return deserializer.DeserializeAsync(content, mode.Value); })); }
/// <summary> /// Expect a success status code /// <para>If a non-success status code is received, an InvalidOperationException is thrown</para> /// </summary> /// <param name="request">The ISolidHttpRequest</param> /// <returns>SolidHttpRequest</returns> public static ISolidHttpRequest ExpectSuccess(this ISolidHttpRequest request) { request.OnResponse(async(services, response) => { if (!response.IsSuccessStatusCode) { var message = await GenerateNonSuccessMessage(response); // TODO: reevaluate this exception type. maybe a seperate type for server error and client error throw new InvalidOperationException(message); } }); return(request); }
private static void OnRequestCreated(IServiceProvider services, ISolidHttpRequest request) { var baseAddress = request.Client.GetProperty <Uri>("Client::BaseAddress"); if (baseAddress == null) { return; } var url = new Uri(baseAddress, request.BaseRequest.RequestUri); request.BaseRequest.RequestUri = url; }
/// <summary> /// Deserializes a JSON <see cref="HttpContent" /> as <typeparamref name="T" /> using the /// specified serializer settings. /// </summary> /// <typeparam name="T">The type of response body.</typeparam> /// <param name="request">The <see cref="ISolidHttpRequest" /> that is being extended.</param> /// <param name="settings">The specified <see cref="JsonSerializerSettings" />.</param> /// <returns><see cref="ValueTask{T}" /> of type <typeparamref name="T" /></returns> public static async ValueTask <T> As <T>(this ISolidHttpRequest request, JsonSerializerSettings settings) { if (settings == null) { settings = request.Services.GetService <IOptions <SolidHttpNewtonsoftJsonOptions> >().Value.SerializerSettings; } return(await request.As <T>(async content => { var json = await content.ReadAsStringAsync(); return JsonConvert.DeserializeObject <T>(json, settings); })); }
/// <summary> /// Deserializes the response content using a specified deserializer /// </summary> /// <typeparam name="T">The type to deserialize to</typeparam> /// <param name="request">The ISolidHttpRequest</param> /// <param name="deserialize">The deserialization method</param> /// <returns>Task of type T</returns> public static async Task <T> As <T>(this ISolidHttpRequest request, Func <HttpContent, Task <T> > deserialize) { var content = await request.GetContentAsync(); if (content == null) { return(default(T)); // should we maybe throw an exception if there is no content? } if (request.BaseRequest.Properties.ContainsKey(IgnoreSerializationErrorKey)) { return(await SafeDeserializeAsync(() => deserialize(content))); } return(await deserialize(content)); }
/// <summary> /// Adds StringContent containing a json string of the supplied body object /// </summary> /// <typeparam name="T">The type of body</typeparam> /// <param name="request">The SolidHttpRequest</param> /// <param name="body">The request body object</param> /// <param name="settings">(Optional) DataContractSerializerSettings to use to serialize the body object</param> /// <returns>SolidHttpRequest</returns> public static ISolidHttpRequest WithXmlContent <T>(this ISolidHttpRequest request, T body, DataContractSerializerSettings settings = null) { using (var ms = new MemoryStream()) { var ser = new DataContractSerializer(typeof(T), settings ?? request.GetXmlSerializerSettings()); ser.WriteObject(ms, body); ms.Position = 0; using (var reader = new StreamReader(ms)) { var content = new StringContent(reader.ReadToEnd(), Encoding.UTF8, "application/xml"); return(request.WithContent(content)); } } }
/// <summary> /// Adds <see cref="StreamContent" /> containing UTF-8 serialized JSON of type <typeparamref name="T" />. /// </summary> /// <typeparam name="T">The type of body</typeparam> /// <param name="request">The <see cref="ISolidHttpRequest" /> that is being extended.</param> /// <param name="body">The request body object of type <typeparamref name="T" />.</param> /// <param name="contentType">(Optional) The content type header value.</param> /// <param name="options">(Optional) <see cref="JsonSerializerOptions" /> to use to serialize the <paramref name="body" />..</param> /// <returns>The <see cref="ISolidHttpRequest" /> so that additional calls can be chained.</returns> public static ISolidHttpRequest WithJsonContent <T>(this ISolidHttpRequest request, T body, string contentType = "application/json", JsonSerializerOptions options = null) { if (options == null) { options = request.Services.GetService <IOptions <SolidHttpJsonOptions> >().Value.SerializerOptions; } var bytes = JsonSerializer.SerializeToUtf8Bytes <T>(body, options); var stream = new MemoryStream(bytes); var content = new StreamContent(stream); content.Headers.ContentType = new MediaTypeHeaderValue(contentType) { CharSet = "utf-8" }; return(request.WithContent(content)); }
/// <summary> /// Adds a query parameter to the url /// </summary> /// <param name="request">The SolidHttpRequest</param> /// <param name="name">The name of the query parameter</param> /// <param name="values">The value of the query parameter</param> /// <returns></returns> public static ISolidHttpRequest WithQueryParameter(this ISolidHttpRequest request, string name, StringValues values) { var url = request.BaseRequest.RequestUri.OriginalString; foreach (var value in values) { if (url.Contains("?")) { url += $"&{name}={value}"; } else { url += $"?{name}={value}"; } } request.BaseRequest.RequestUri = new Uri(url, UriKind.RelativeOrAbsolute); return(request); }
/// <summary> /// Adds a query parameter to the url. /// </summary> /// <param name="request">The <see cref="ISolidHttpRequest"/> that is being extended.</param> /// <param name="name">The name of the query parameter</param> /// <param name="value">The value of the query parameter.</param> /// <param name="convert">A converter used to convert the <paramref name="value"/> to an <see cref="IEnumerable{T}"/> of <seealso cref="string"/>.</param> /// <returns>The <see cref="ISolidHttpRequest"/> so that additional calls can be chained.</returns> public static ISolidHttpRequest WithQueryParameter(this ISolidHttpRequest request, string name, object value, Func <object, IEnumerable <string> > convert) { var url = request.BaseRequest.RequestUri.OriginalString; var values = convert(value); foreach (var v in values) { if (url.Contains("?")) { url += $"&{name}={v}"; } else { url += $"?{name}={v}"; } } request.BaseRequest.RequestUri = new Uri(url, UriKind.RelativeOrAbsolute); return(request); }
/// <summary> /// Expect a success status code. /// <para>If a status code in the 400 range is received, a <see cref="ClientErrorException" /> is thrown.</para> /// <para>If a status code in the 500 range is received, a <see cref="ServerErrorException" /> is thrown.</para> /// </summary> /// <param name="request">The <see cref="ISolidHttpRequest" /> that is being extended.</param> /// <returns>The <see cref="ISolidHttpRequest" /> so that additional calls can be chained.</returns> public static ISolidHttpRequest ExpectSuccess(this ISolidHttpRequest request) { request.OnHttpResponse(async(services, response) => { if (!response.IsSuccessStatusCode) { var message = await GenerateNonSuccessMessage(response); if ((int)response.StatusCode < 500) { throw new ClientErrorException(message); } else { throw new ServerErrorException(message); } } }); return(request); }
/// <summary> /// Adds <see cref="StreamContent" /> containing UTF-8 serialized XML of type <typeparamref name="T" />. /// </summary> /// <typeparam name="T">The type of body</typeparam> /// <param name="request">The <see cref="ISolidHttpRequest" /> that is being extended.</param> /// <param name="body">The request body object of type <typeparamref name="T" />.</param> /// <param name="contentType">(Optional) The content type header value.</param> /// <param name="settings">(Optional) <see cref="DataContractSerializerSettings" /> to use to serialize the <paramref name="body" />.</param> /// <returns>The <see cref="ISolidHttpRequest" /> so that additional calls can be chained.</returns> public static ISolidHttpRequest WithXmlContent <T>(this ISolidHttpRequest request, T body, string contentType = "application/xml", DataContractSerializerSettings settings = null) { if (settings == null) { settings = request.Services.GetService <IOptions <SolidHttpXmlOptions> >().Value.SerializerSettings; } var stream = new MemoryStream(); var serializer = new DataContractSerializer(typeof(T), settings); serializer.WriteObject(stream, body); stream.Position = 0; var content = new StreamContent(stream); content.Headers.ContentType = new MediaTypeHeaderValue(contentType) { CharSet = "utf-8" }; return(request.WithContent(content)); }
/// <summary> /// Deserializes the response content /// </summary> /// <typeparam name="T">The type to deserialize to</typeparam> /// <param name="request">The ISolidHttpRequest</param> /// <returns>Task of type T</returns> public static async Task <T> As <T>(this ISolidHttpRequest request) { var content = await request.GetContentAsync(); if (content == null) { return(default(T)); // should we maybe throw an exception if there is no content? } var mime = content?.Headers?.ContentType?.MediaType; var deserializer = request.Client.Deserializers.FirstOrDefault(d => d.CanDeserialize(mime)); if (deserializer == null) { throw new InvalidOperationException($"Cannot deserialize {mime} response as {typeof(T).FullName}"); } if (request.BaseRequest.Properties.ContainsKey(IgnoreSerializationErrorKey)) { return(await SafeDeserializeAsync(() => deserializer.DeserializeAsync <T>(content))); } return(await deserializer.DeserializeAsync <T>(content)); }