diff --git a/Flurl.Http.Xml.sln b/Flurl.Http.Xml.sln index b407d1c..5c5fea8 100644 --- a/Flurl.Http.Xml.sln +++ b/Flurl.Http.Xml.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.28803.156 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34407.89 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F2114366-0322-434F-91D3-A25939F0CFA7}" ProjectSection(SolutionItems) = preProject diff --git a/appveyor.yml b/appveyor.yml index 80e2f0a..04bbab3 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,11 +1,11 @@ -version: 2.0.0-{build} +version: 4.0.0-{build} branches: only: - main - development pull_requests: do_not_increment_build_number: true -image: Visual Studio 2019 +image: Visual Studio 2022 build_script: - ps: .\build\build.ps1 $env:APPVEYOR_BUILD_VERSION $env:APPVEYOR_REPO_TAG_NAME #before_test: @@ -16,7 +16,7 @@ deploy: - provider: NuGet api_key: secure: yc/gQNTv1/CbW+NYNpSF0SEOAAVVPr96aLb7kWWE764XGrDlG/ijBXyzQ+g6EnFN - skip_symbols: false + skip_symbols: true artifact: /.*(\.|\.s)nupkg/ on: - appveyor_repo_tag: true # deploy on tag push only + appveyor_repo_tag: true # deploy on tag push only \ No newline at end of file diff --git a/global.json b/global.json index 48934da..d105f4f 100644 --- a/global.json +++ b/global.json @@ -1,7 +1,7 @@ { "projects": [ "src", "test" ], "sdk": { - "version": "3.1.202", + "version": "8.0.100", "rollForward": "latestFeature" } -} +} \ No newline at end of file diff --git a/src/Flurl.Http.Xml/CapturedXmlContent.cs b/src/Flurl.Http.Xml/CapturedXmlContent.cs index dd6e1b0..f72320f 100644 --- a/src/Flurl.Http.Xml/CapturedXmlContent.cs +++ b/src/Flurl.Http.Xml/CapturedXmlContent.cs @@ -1,18 +1,17 @@ using Flurl.Http.Content; -namespace Flurl.Http.Xml +namespace Flurl.Http.Xml; + +/// +/// Provides HTTP content based on a serialized XML object, with the XML string captured to a property +/// so it can be read without affecting the read-once content stream. +/// +public class CapturedXmlContent : CapturedStringContent { /// - /// Provides HTTP content based on a serialized XML object, with the XML string captured to a property - /// so it can be read without affecting the read-once content stream. + /// Initializes a new instance of the class. /// - public class CapturedXmlContent : CapturedStringContent - { - /// - /// Initializes a new instance of the class. - /// - /// The XML. - /// The media-type. - public CapturedXmlContent(string xml, string mediaType) : base(xml, mediaType) { } - } + /// The XML. + /// The media-type. + public CapturedXmlContent(string xml, string mediaType) : base(xml, mediaType) { } } \ No newline at end of file diff --git a/src/Flurl.Http.Xml/Flurl.Http.Xml.csproj b/src/Flurl.Http.Xml/Flurl.Http.Xml.csproj index 75469b3..321fb08 100644 --- a/src/Flurl.Http.Xml/Flurl.Http.Xml.csproj +++ b/src/Flurl.Http.Xml/Flurl.Http.Xml.csproj @@ -1,7 +1,8 @@  - netstandard2.0;netstandard2.1;net461;net472 + netstandard2.0;netstandard2.1;net461;net472;net481;net5;net6;net7;net8 + latest false false Luk Vermeulen @@ -18,7 +19,7 @@ - + diff --git a/src/Flurl.Http.Xml/FlurlHttpSettingsExtensions.cs b/src/Flurl.Http.Xml/FlurlHttpSettingsExtensions.cs deleted file mode 100644 index 0267663..0000000 --- a/src/Flurl.Http.Xml/FlurlHttpSettingsExtensions.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Text; -using System.Xml; -using Flurl.Http.Configuration; - -namespace Flurl.Http.Xml -{ - /// - /// FlurlHttpSettingsExtensions - /// - public static class FlurlHttpSettingsExtensions - { - private static XmlWriterSettings s_xmlWriterSettings = new XmlWriterSettings { Encoding = new UTF8Encoding(false, false), Indent = true, OmitXmlDeclaration = false }; - private static readonly Lazy s_xmlSerializerInstance = new Lazy(() => new MicrosoftXmlSerializer(s_xmlWriterSettings)); - - /// - /// XMLs the serializer. - /// - /// The settings. - public static MicrosoftXmlSerializer XmlSerializer(this FlurlHttpSettings settings) - { - return settings.XmlSerializer(s_xmlWriterSettings); - } - - /// - /// XMLs the serializer. - /// - /// The settings. - /// The XML writer settings. - // ReSharper disable once UnusedParameter.Local - private static MicrosoftXmlSerializer XmlSerializer(this FlurlHttpSettings settings, XmlWriterSettings xmlWriterSettings) - { - s_xmlWriterSettings = xmlWriterSettings; - return s_xmlSerializerInstance.Value; - } - } -} diff --git a/src/Flurl.Http.Xml/FlurlRequestExtensions.cs b/src/Flurl.Http.Xml/FlurlRequestExtensions.cs index 689f51b..c138251 100644 --- a/src/Flurl.Http.Xml/FlurlRequestExtensions.cs +++ b/src/Flurl.Http.Xml/FlurlRequestExtensions.cs @@ -7,144 +7,156 @@ using System.Xml; using System.Xml.Linq; -namespace Flurl.Http.Xml +namespace Flurl.Http.Xml; + +/// +/// FlurlRequestExtensions +/// +public static class FlurlRequestExtensions { /// - /// FlurlRequestExtensions + /// Sends an asynchronous GET request. /// - public static class FlurlRequestExtensions + /// + /// The request. + /// The HttpCompletionOption used in the request. Optional. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. + /// + /// A Task whose result is the XML response body deserialized to an object of type T. + /// + public static Task GetXmlAsync(this IFlurlRequest request, + HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead, + CancellationToken cancellationToken = default) { - /// - /// Sends an asynchronous GET request. - /// - /// - /// The request. - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. - /// The HttpCompletionOption used in the request. Optional. - /// - /// A Task whose result is the XML response body deserialized to an object of type T. - /// - public static Task GetXmlAsync(this IFlurlRequest request, - CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) - { - return request.SendAsync(HttpMethod.Get, null, cancellationToken, completionOption).ReceiveXml(); - } + return request.SendAsync(HttpMethod.Get, null, completionOption, cancellationToken).ReceiveXml(); + } - /// - /// Sends an asynchronous GET request. - /// - /// The request. - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. - /// The HttpCompletionOption used in the request. Optional. - /// - /// A Task whose result is the XML response body parsed into an XDocument. - /// - public static Task GetXDocumentAsync(this IFlurlRequest request, - CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) - { - return request.SendAsync(HttpMethod.Get, null, cancellationToken, completionOption).ReceiveXDocument(); - } + /// + /// Sends an asynchronous GET request. + /// + /// The request. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. + /// The HttpCompletionOption used in the request. Optional. + /// + /// A Task whose result is the XML response body parsed into an XDocument. + /// + public static Task GetXDocumentAsync(this IFlurlRequest request, + HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead, CancellationToken cancellationToken = default) + { + return request.SendAsync(HttpMethod.Get, null, completionOption, cancellationToken).ReceiveXDocument(); + } - /// - /// Sends an asynchronous GET request. - /// - /// The request. - /// The expression. - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. - /// The HttpCompletionOption used in the request. Optional. - /// - /// A Task whose result is the XML response body parsed into a collection of XElements. - /// - public static Task> GetXElementsFromXPath(this IFlurlRequest request, string expression, - CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) - { - return request.SendAsync(HttpMethod.Get, null, cancellationToken, completionOption).ReceiveXElementsFromXPath(expression); - } + /// + /// Sends an asynchronous GET request. + /// + /// The request. + /// The expression. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. + /// The HttpCompletionOption used in the request. Optional. + /// + /// A Task whose result is the XML response body parsed into a collection of XElements. + /// + public static Task> GetXElementsFromXPath(this IFlurlRequest request, string expression, + CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) + { + return request.SendAsync(HttpMethod.Get, null, completionOption, cancellationToken).ReceiveXElementsFromXPath(expression); + } - /// - /// Sends an asynchronous GET request. - /// - /// The request. - /// The expression. - /// The resolver. - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. - /// The HttpCompletionOption used in the request. Optional. - /// - /// A Task whose result is the XML response body parsed into a collection of XElements. - /// - public static Task> GetXElementsFromXPath(this IFlurlRequest request, string expression, IXmlNamespaceResolver resolver, - CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) - { - return request.SendAsync(HttpMethod.Get, null, cancellationToken, completionOption).ReceiveXElementsFromXPath(expression, resolver); - } + /// + /// Sends an asynchronous GET request. + /// + /// The request. + /// The expression. + /// The resolver. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. + /// The HttpCompletionOption used in the request. Optional. + /// + /// A Task whose result is the XML response body parsed into a collection of XElements. + /// + public static Task> GetXElementsFromXPath(this IFlurlRequest request, string expression, IXmlNamespaceResolver resolver, + CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) + { + return request.SendAsync(HttpMethod.Get, null, completionOption, cancellationToken).ReceiveXElementsFromXPath(expression, resolver); + } - private static string GetMediaType(this IHttpSettingsContainer request) + private static string GetMediaType(this IFlurlRequest request) + { + var acceptHeaders = request.Headers + .Where(x => x.Name == "Accept") + .ToList(); + + if (!acceptHeaders.Any() || acceptHeaders.All(x => x.Value == null)) { - var acceptHeaders = request.Headers - .Where(x => x.Name == "Accept") - .ToList(); + // no accepted media type present, return default + return "application/xml"; + } - if (!acceptHeaders.Any() || acceptHeaders.All(x => x.Value == null)) - { - // no accepted media type present, return default - return "application/xml"; - } + // return media type of first accepted media type containing "xml", else of first accepted media type + var mediaTypes = acceptHeaders + .Where(x => x.Value != null) + .SelectMany(x => x.Value.ToString().Split(',')) + .Select(x => x.Trim()) + .ToList(); - // return media type of first accepted media type containing "xml", else of first accepted media type - var mediaTypes = acceptHeaders - .Where(x => x.Value != null) - .SelectMany(x => x.Value.ToString().Split(',')) - .Select(x => x.Trim()) - .ToList(); + return mediaTypes.FirstOrDefault(x => x.IndexOf("xml", StringComparison.OrdinalIgnoreCase) >= 0) + ?? mediaTypes.FirstOrDefault(); + } - return mediaTypes.FirstOrDefault(x => x.IndexOf("xml", StringComparison.OrdinalIgnoreCase) >= 0) - ?? mediaTypes.FirstOrDefault(); - } + /// + /// Sends an asynchronous HTTP request. + /// + /// The request. + /// HTTP method of the request + /// Contents of the request body. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. + /// The HttpCompletionOption used in the request. Optional. + /// + /// A Task whose result is the received IFlurlResponse. + /// + public static Task SendXmlAsync(this IFlurlRequest request, HttpMethod httpMethod, object data, + CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) + { + var content = new CapturedXmlContent(MicrosoftXmlSerializer.Default.Serialize(data), request.GetMediaType()); + return request.SendAsync(httpMethod, content, completionOption, cancellationToken); + } - /// - /// Sends an asynchronous HTTP request. - /// - /// The request. - /// HTTP method of the request - /// Contents of the request body. - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. - /// The HttpCompletionOption used in the request. Optional. - /// - /// A Task whose result is the received IFlurlResponse. - /// - public static Task SendXmlAsync(this IFlurlRequest request, HttpMethod httpMethod, object data, - CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) - { - var content = new CapturedXmlContent(request.Settings.XmlSerializer().Serialize(data), request.GetMediaType()); - return request.SendAsync(httpMethod, content, cancellationToken, completionOption); - } + /// + /// Sends an asynchronous POST request. + /// + /// The request. + /// Contents of the request body. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. + /// The HttpCompletionOption used in the request. Optional. + /// + /// A Task whose result is the received IFlurlResponse. + /// + public static Task PostXmlAsync(this IFlurlRequest request, object data, + CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) => + SendXmlAsync(request, HttpMethod.Post, data, cancellationToken, completionOption); - /// - /// Sends an asynchronous POST request. - /// - /// The request. - /// Contents of the request body. - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. - /// The HttpCompletionOption used in the request. Optional. - /// - /// A Task whose result is the received IFlurlResponse. - /// - public static Task PostXmlAsync(this IFlurlRequest request, object data, - CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) => - SendXmlAsync(request, HttpMethod.Post, data, cancellationToken, completionOption); + /// + /// Sends an asynchronous PUT request. + /// + /// The request. + /// Contents of the request body. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. + /// The HttpCompletionOption used in the request. Optional. + /// + /// A Task whose result is the received IFlurlResponse. + /// + public static Task PutXmlAsync(this IFlurlRequest request, object data, + CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) => + SendXmlAsync(request, HttpMethod.Put, data, cancellationToken, completionOption); - /// - /// Sends an asynchronous PUT request. - /// - /// The request. - /// Contents of the request body. - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. - /// The HttpCompletionOption used in the request. Optional. - /// - /// A Task whose result is the received IFlurlResponse. - /// - public static Task PutXmlAsync(this IFlurlRequest request, object data, - CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) => - SendXmlAsync(request, HttpMethod.Put, data, cancellationToken, completionOption); + /// + /// Sets the verb associated with this request + /// + /// The request. + /// The verb. + /// The request. + public static Task WithVerb(this IFlurlRequest request, HttpMethod verb) + { + request.Verb = verb; + return Task.FromResult(request); } -} +} \ No newline at end of file diff --git a/src/Flurl.Http.Xml/HttpResponseMessageExtensions.cs b/src/Flurl.Http.Xml/HttpResponseMessageExtensions.cs index ba6a7ff..c92e885 100644 --- a/src/Flurl.Http.Xml/HttpResponseMessageExtensions.cs +++ b/src/Flurl.Http.Xml/HttpResponseMessageExtensions.cs @@ -9,120 +9,101 @@ using System.Xml.Linq; using System.Xml.XPath; -namespace Flurl.Http.Xml +namespace Flurl.Http.Xml; + +/// +/// IFlurlResponseExtensions +/// +public static class IFlurlResponseExtensions { - /// - /// IFlurlResponseExtensions - /// - public static class IFlurlResponseExtensions + private static string GetMediaType(HttpRequestMessage request) { - private static FlurlCall GetHttpCall(HttpRequestMessage request) + if (request.Headers.Accept.Any()) { - if (request?.Properties != null && request.Properties.TryGetValue("FlurlHttpCall", out var obj) && obj is FlurlCall call) - { - return call; - } - return null; + // return media type of first accepted media type containing "xml", else of first accepted media type + var acceptHeader = request.Headers.Accept.FirstOrDefault(x => x.MediaType?.IndexOf("xml", StringComparison.OrdinalIgnoreCase) >= 0) + ?? request.Headers.Accept.FirstOrDefault(); + + return acceptHeader?.MediaType; } - private static string GetMediaType(HttpRequestMessage request) - { - if (request.Headers.Accept.Any()) - { - // return media type of first accepted media type containing "xml", else of first accepted media type - var acceptHeader = request.Headers.Accept.FirstOrDefault(x => x.MediaType.IndexOf("xml", StringComparison.OrdinalIgnoreCase) >= 0) - ?? request.Headers.Accept.FirstOrDefault(); + // no accepted media type present, return default + return "application/xml"; + } - return acceptHeader?.MediaType; - } + /// + /// Receives XML-formatted HTTP response body. Intended to chain off an async HTTP. + /// + /// The response. + /// A Task whose result is a response message containing data in the response body. + /// x = await url.PostAsync(data).ReceiveXmlResponseMessage() + public static async Task ReceiveXmlResponseMessage(this Task responseMessage) + { + var response = await responseMessage.ConfigureAwait(false); + response.ResponseMessage.Content.Headers.ContentType = new MediaTypeHeaderValue(GetMediaType(response.ResponseMessage.RequestMessage)); - // no accepted media type present, return default - return "application/xml"; - } + return response; + } - /// - /// Receives XML-formatted HTTP response body. Intended to chain off an async HTTP. - /// - /// The response. - /// A Task whose result is a response message containing data in the response body. - /// x = await url.PostAsync(data).ReceiveXmlResponseMessage() - public static async Task ReceiveXmlResponseMessage(this Task responseMessage) + private static async Task ReceiveFromXmlStream(this Task response, Func streamHandler) + { + var resp = await ReceiveXmlResponseMessage(response).ConfigureAwait(false); + try { - var response = await responseMessage.ConfigureAwait(false); - response.ResponseMessage.Content.Headers.ContentType = new MediaTypeHeaderValue(GetMediaType(response.ResponseMessage.RequestMessage)); - - return response; + // ReSharper disable once UseAwaitUsing + using var stream = await resp.ResponseMessage.Content.ReadAsStreamAsync().ConfigureAwait(false); + return streamHandler(stream); } - - private static async Task ReceiveFromXmlStream(this Task response, Func streamHandler) + catch (Exception ex) { - var resp = await ReceiveXmlResponseMessage(response); - var call = GetHttpCall(resp.ResponseMessage.RequestMessage); - - try - { - using (var stream = await resp.ResponseMessage.Content.ReadAsStreamAsync().ConfigureAwait(false)) - { - return streamHandler(call, stream); - } - } - catch (Exception ex) - { - string s = await resp.ResponseMessage.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new FlurlHttpException(call, s, ex); - } + var s = await resp.ResponseMessage.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new FlurlHttpException(null, s, ex); } + } - /// - /// Deserializes XML-formatted HTTP response body to object of type T. Intended to chain off an async HTTP. - /// - /// A type whose structure matches the expected XML response. - /// The response. - /// A Task whose result is an object containing data in the response body. - /// x = await url.PostAsync(data).ReceiveXml<T>() - public static async Task ReceiveXml(this Task response) - { - return await ReceiveFromXmlStream(response, (call, stm) => - call.Request.Settings.XmlSerializer().Deserialize(stm)); - } + /// + /// Deserializes XML-formatted HTTP response body to object of type T. Intended to chain off an async HTTP. + /// + /// A type whose structure matches the expected XML response. + /// The response. + /// A Task whose result is an object containing data in the response body. + /// x = await url.PostAsync(data).ReceiveXml<T>() + public static async Task ReceiveXml(this Task response) => await ReceiveFromXmlStream(response, stm => MicrosoftXmlSerializer.Default.Deserialize(stm)); - /// - /// Parses XML-formatted HTTP response body into an XDocument. Intended to chain off an async call. - /// - /// The response. - /// A Task whose result is an XDocument containing XML data from the response body. - /// d = await url.PostAsync(data).ReceiveXDocument() - public static async Task ReceiveXDocument(this Task response) + /// + /// Parses XML-formatted HTTP response body into an XDocument. Intended to chain off an async call. + /// + /// The response. + /// A Task whose result is an XDocument containing XML data from the response body. + /// d = await url.PostAsync(data).ReceiveXDocument() + public static async Task ReceiveXDocument(this Task response) + { + return await ReceiveFromXmlStream(response, stm => { - return await ReceiveFromXmlStream(response, (call, stm) => - { - using (var streamReader = new StreamReader(stm)) - { - return XDocument.Parse(streamReader.ReadToEnd()); - } - }); - } + using var streamReader = new StreamReader(stm); + return XDocument.Parse(streamReader.ReadToEnd()); + }).ConfigureAwait(false); + } - /// - /// Parses XML-formatted HTTP response body into a collection of XElements. Intended to chain off an async call. - /// - /// A Task whose result is a collection of XElements from an XDocument containing XML data from the response body. - /// d = await url.PostAsync(data).ReceiveXElementsFromXPath(xpathExpression) - public static async Task> ReceiveXElementsFromXPath(this Task response, string expression) - { - var doc = await response.ReceiveXDocument().ConfigureAwait(false); - return doc.XPathSelectElements(expression); - } + /// + /// Parses XML-formatted HTTP response body into a collection of XElements. Intended to chain off an async call. + /// + /// A Task whose result is a collection of XElements from an XDocument containing XML data from the response body. + /// d = await url.PostAsync(data).ReceiveXElementsFromXPath(xpathExpression) + public static async Task> ReceiveXElementsFromXPath(this Task response, string expression) + { + var doc = await response.ReceiveXDocument().ConfigureAwait(false); + return doc.XPathSelectElements(expression); + } - /// - /// Parses XML-formatted HTTP response body into a collection of XElements. Intended to chain off an async call. - /// - /// A Task whose result is a collection of XElements from an XDocument containing XML data from the response body. - /// d = await url.PostAsync(data).ReceiveXElementsFromXPath(xpathExpression, namespaceResolver) - public static async Task> ReceiveXElementsFromXPath(this Task response, string expression, IXmlNamespaceResolver resolver) - { - var doc = await response.ReceiveXDocument().ConfigureAwait(false); - return doc.XPathSelectElements(expression, resolver); - } + /// + /// Parses XML-formatted HTTP response body into a collection of XElements. Intended to chain off an async call. + /// + /// A Task whose result is a collection of XElements from an XDocument containing XML data from the response body. + /// d = await url.PostAsync(data).ReceiveXElementsFromXPath(xpathExpression, namespaceResolver) + public static async Task> ReceiveXElementsFromXPath(this Task response, string expression, IXmlNamespaceResolver resolver) + { + var doc = await response.ReceiveXDocument().ConfigureAwait(false); + return doc.XPathSelectElements(expression, resolver); } -} +} \ No newline at end of file diff --git a/src/Flurl.Http.Xml/MicrosoftXmlSerializer.cs b/src/Flurl.Http.Xml/MicrosoftXmlSerializer.cs index 18f7605..acaebc0 100644 --- a/src/Flurl.Http.Xml/MicrosoftXmlSerializer.cs +++ b/src/Flurl.Http.Xml/MicrosoftXmlSerializer.cs @@ -1,87 +1,92 @@ using System.IO; +using System.Text; using System.Xml; using System.Xml.Linq; using System.Xml.Serialization; using Flurl.Http.Configuration; -namespace Flurl.Http.Xml +namespace Flurl.Http.Xml; + +/// +/// ISerializer implementation that uses Microsoft XmlSerializer. +/// Default serializer used in calls to GetXmlAsync, PostXmlAsync, etc. +/// +public class MicrosoftXmlSerializer : ISerializer { + private readonly XmlWriterSettings _xmlWriterSettings; + /// - /// ISerializer implementation that uses Microsoft XmlSerializer. - /// Default serializer used in calls to GetXmlAsync, PostXmlAsync, etc. + /// The default XML writer settings. /// - public class MicrosoftXmlSerializer : ISerializer + public static XmlWriterSettings DefaultXmlWriterSettings { get; } = new XmlWriterSettings { - private readonly XmlWriterSettings _xmlWriterSettings; + Encoding = new UTF8Encoding(false, false), + Indent = true, + OmitXmlDeclaration = false + }; - /// - /// Initializes a new instance of the class. - /// - /// The XML writer settings. - public MicrosoftXmlSerializer(XmlWriterSettings xmlWriterSettings) - { - _xmlWriterSettings = xmlWriterSettings; - } + /// + /// Returns a default instance of the serializer. + /// + public static MicrosoftXmlSerializer Default { get; } = new MicrosoftXmlSerializer(DefaultXmlWriterSettings); - /// - /// Serializes an object to a string representation. - /// - /// - public string Serialize(object obj) - { - using (var writer = new Utf8StringWriter()) - using (var xmlWriter = XmlWriter.Create(writer, _xmlWriterSettings)) - { - var serializer = new XmlSerializer(obj.GetType()); - serializer.Serialize(xmlWriter, obj); - return writer.ToString(); - } - } + /// + /// Initializes a new instance of the class. + /// + /// The XML writer settings. + public MicrosoftXmlSerializer(XmlWriterSettings xmlWriterSettings) => _xmlWriterSettings = xmlWriterSettings; - private static string TextReaderToString(TextReader reader) - { - using (reader) - { - return reader.ReadToEnd(); - } - } + /// + /// Serializes an object to a string representation. + /// + /// + public string Serialize(object obj) + { + using var writer = new Utf8StringWriter(); + using var xmlWriter = XmlWriter.Create(writer, _xmlWriterSettings); + var serializer = new XmlSerializer(obj.GetType()); + serializer.Serialize(xmlWriter, obj); + return writer.ToString(); + } - private static XDocument StringToXDocument(string s) + private static string TextReaderToString(TextReader reader) + { + using (reader) { - var doc = XDocument.Parse(s); - if (doc.Declaration == null) - { - doc.Declaration = new XDeclaration("1.0", "utf-8", "yes"); - } - - return doc; + return reader.ReadToEnd(); } + } - private static T DeserializeInternal(TextReader reader) - { - string xml = TextReaderToString(reader); - var doc = StringToXDocument(xml); - string xmlWithDeclaration = doc.ToStringWithDeclaration(); + private static XDocument StringToXDocument(string s) + { + var doc = XDocument.Parse(s); + doc.Declaration ??= new XDeclaration("1.0", "utf-8", "yes"); - using (var textReader = new StringReader(xmlWithDeclaration)) - { - var serializer = new XmlSerializer(typeof(T)); - return (T)serializer.Deserialize(textReader); - } - } + return doc; + } - /// - /// Deserializes an object from a string representation. - /// - /// - /// The string. - public T Deserialize(string s) => string.IsNullOrWhiteSpace(s) ? default : DeserializeInternal(new StringReader(s)); + private static T DeserializeInternal(TextReader reader) + { + var xml = TextReaderToString(reader); + var doc = StringToXDocument(xml); + var xmlWithDeclaration = doc.ToStringWithDeclaration(); - /// - /// Deserializes an object from a stream representation. - /// - /// - /// The stream. - public T Deserialize(Stream stream) => stream == null ? default : DeserializeInternal(new StreamReader(stream)); + using var textReader = new StringReader(xmlWithDeclaration); + var serializer = new XmlSerializer(typeof(T)); + return (T)serializer.Deserialize(textReader); } + + /// + /// Deserializes an object from a string representation. + /// + /// + /// The string. + public T Deserialize(string s) => string.IsNullOrWhiteSpace(s) ? default : DeserializeInternal(new StringReader(s)); + + /// + /// Deserializes an object from a stream representation. + /// + /// + /// The stream. + public T Deserialize(Stream stream) => stream == null ? default : DeserializeInternal(new StreamReader(stream)); } \ No newline at end of file diff --git a/src/Flurl.Http.Xml/StringExtensions.cs b/src/Flurl.Http.Xml/StringExtensions.cs index f130290..41a45a6 100644 --- a/src/Flurl.Http.Xml/StringExtensions.cs +++ b/src/Flurl.Http.Xml/StringExtensions.cs @@ -5,98 +5,97 @@ using System.Xml; using System.Xml.Linq; -namespace Flurl.Http.Xml +namespace Flurl.Http.Xml; + +/// +/// StringExtensions +/// +public static class StringExtensions { /// - /// StringExtensions + /// Sends an asynchronous GET request. /// - public static class StringExtensions - { - /// - /// Sends an asynchronous GET request. - /// - /// - /// The URL. - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. - /// The HttpCompletionOption used in the request. Optional. - /// - /// A Task whose result is the XML response body deserialized to an object of type T. - /// - public static Task GetXmlAsync(this string url, - CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) => - new FlurlRequest(url).GetXmlAsync(cancellationToken, completionOption); + /// + /// The URL. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. + /// The HttpCompletionOption used in the request. Optional. + /// + /// A Task whose result is the XML response body deserialized to an object of type T. + /// + public static Task GetXmlAsync(this string url, + CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) => + new FlurlRequest(url).GetXmlAsync(completionOption, cancellationToken); - /// - /// Sends an asynchronous GET request. - /// - /// The URL. - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. - /// The HttpCompletionOption used in the request. Optional. - /// A Task whose result is the XML response body parsed into an XDocument. - public static Task GetXDocumentAsync(this string url, - CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) => - new FlurlRequest(url).GetXDocumentAsync(cancellationToken, completionOption); + /// + /// Sends an asynchronous GET request. + /// + /// The URL. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. + /// The HttpCompletionOption used in the request. Optional. + /// A Task whose result is the XML response body parsed into an XDocument. + public static Task GetXDocumentAsync(this string url, + CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) => + new FlurlRequest(url).GetXDocumentAsync(completionOption, cancellationToken); - /// - /// Sends an asynchronous GET request. - /// - /// The URL. - /// The expression. - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. - /// The HttpCompletionOption used in the request. Optional. - /// A Task whose result is the XML response body parsed into a collection of XElements. - public static Task> GetXElementsFromXPath(this string url, string expression, - CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) => - new FlurlRequest(url).GetXElementsFromXPath(expression, cancellationToken, completionOption); + /// + /// Sends an asynchronous GET request. + /// + /// The URL. + /// The expression. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. + /// The HttpCompletionOption used in the request. Optional. + /// A Task whose result is the XML response body parsed into a collection of XElements. + public static Task> GetXElementsFromXPath(this string url, string expression, + CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) => + new FlurlRequest(url).GetXElementsFromXPath(expression, cancellationToken, completionOption); - /// - /// Sends an asynchronous GET request. - /// - /// The URL. - /// The expression. - /// The resolver. - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. - /// The HttpCompletionOption used in the request. Optional. - /// A Task whose result is the XML response body parsed into a collection of XElements. - public static Task> GetXElementsFromXPath(this string url, string expression, IXmlNamespaceResolver resolver, - CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) => - new FlurlRequest(url).GetXElementsFromXPath(expression, resolver, cancellationToken, completionOption); + /// + /// Sends an asynchronous GET request. + /// + /// The URL. + /// The expression. + /// The resolver. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. + /// The HttpCompletionOption used in the request. Optional. + /// A Task whose result is the XML response body parsed into a collection of XElements. + public static Task> GetXElementsFromXPath(this string url, string expression, IXmlNamespaceResolver resolver, + CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) => + new FlurlRequest(url).GetXElementsFromXPath(expression, resolver, cancellationToken, completionOption); - /// - /// Creates a FlurlClient from the URL and sends an asynchronous HTTP request. - /// - /// The URL. - /// HTTP method of the request - /// Contents of the request body. - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. - /// The HttpCompletionOption used in the request. Optional. - /// A Task whose result is the received IFlurlResponse. - public static Task SendXmlAsync(this string url, HttpMethod method, object data, - CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) => - new FlurlRequest(url).SendXmlAsync(method, data, cancellationToken, completionOption); + /// + /// Creates a FlurlClient from the URL and sends an asynchronous HTTP request. + /// + /// The URL. + /// HTTP method of the request + /// Contents of the request body. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. + /// The HttpCompletionOption used in the request. Optional. + /// A Task whose result is the received IFlurlResponse. + public static Task SendXmlAsync(this string url, HttpMethod method, object data, + CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) => + new FlurlRequest(url).SendXmlAsync(method, data, cancellationToken, completionOption); - /// - /// Creates a FlurlClient from the URL and sends an asynchronous POST request. - /// - /// The URL. - /// Contents of the request body. - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. - /// The HttpCompletionOption used in the request. Optional. - /// A Task whose result is the received IFlurlResponse. - public static Task PostXmlAsync(this string url, object data, - CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) => - new FlurlRequest(url).PostXmlAsync(data, cancellationToken, completionOption); + /// + /// Creates a FlurlClient from the URL and sends an asynchronous POST request. + /// + /// The URL. + /// Contents of the request body. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. + /// The HttpCompletionOption used in the request. Optional. + /// A Task whose result is the received IFlurlResponse. + public static Task PostXmlAsync(this string url, object data, + CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) => + new FlurlRequest(url).PostXmlAsync(data, cancellationToken, completionOption); - /// - /// Creates a FlurlClient from the URL and sends an asynchronous PUT request. - /// - /// The URL. - /// Contents of the request body. - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. - /// The HttpCompletionOption used in the request. Optional. - /// A Task whose result is the received IFlurlResponse. - public static Task PutXmlAsync(this string url, object data, - CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) => - new FlurlRequest(url).PutXmlAsync(data, cancellationToken, completionOption); - } + /// + /// Creates a FlurlClient from the URL and sends an asynchronous PUT request. + /// + /// The URL. + /// Contents of the request body. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. + /// The HttpCompletionOption used in the request. Optional. + /// A Task whose result is the received IFlurlResponse. + public static Task PutXmlAsync(this string url, object data, + CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) => + new FlurlRequest(url).PutXmlAsync(data, cancellationToken, completionOption); } \ No newline at end of file diff --git a/src/Flurl.Http.Xml/UrlExtensions.cs b/src/Flurl.Http.Xml/UrlExtensions.cs index d15f157..dc58483 100644 --- a/src/Flurl.Http.Xml/UrlExtensions.cs +++ b/src/Flurl.Http.Xml/UrlExtensions.cs @@ -5,98 +5,97 @@ using System.Xml; using System.Xml.Linq; -namespace Flurl.Http.Xml +namespace Flurl.Http.Xml; + +/// +/// UrlExtensions +/// +public static class UrlExtensions { /// - /// UrlExtensions + /// Sends an asynchronous GET request. /// - public static class UrlExtensions - { - /// - /// Sends an asynchronous GET request. - /// - /// - /// The URL. - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. - /// The HttpCompletionOption used in the request. Optional. - /// - /// A Task whose result is the XML response body deserialized to an object of type T. - /// - public static Task GetXmlAsync(this Url url, - CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) => - new FlurlRequest(url).GetXmlAsync(cancellationToken, completionOption); + /// + /// The URL. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. + /// The HttpCompletionOption used in the request. Optional. + /// + /// A Task whose result is the XML response body deserialized to an object of type T. + /// + public static Task GetXmlAsync(this Url url, + CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) => + new FlurlRequest(url).GetXmlAsync(completionOption, cancellationToken); - /// - /// Sends an asynchronous GET request. - /// - /// The URL. - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. - /// The HttpCompletionOption used in the request. Optional. - /// A Task whose result is the XML response body parsed into an XDocument. - public static Task GetXDocumentAsync(this Url url, - CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) => - new FlurlRequest(url).GetXDocumentAsync(cancellationToken, completionOption); + /// + /// Sends an asynchronous GET request. + /// + /// The URL. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. + /// The HttpCompletionOption used in the request. Optional. + /// A Task whose result is the XML response body parsed into an XDocument. + public static Task GetXDocumentAsync(this Url url, + CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) => + new FlurlRequest(url).GetXDocumentAsync(completionOption, cancellationToken); - /// - /// Sends an asynchronous GET request. - /// - /// The URL. - /// The expression. - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. - /// The HttpCompletionOption used in the request. Optional. - /// A Task whose result is the XML response body parsed into a collection of XElements. - public static Task> GetXElementsFromXPath(this Url url, string expression, - CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) => - new FlurlRequest(url).GetXElementsFromXPath(expression, cancellationToken, completionOption); + /// + /// Sends an asynchronous GET request. + /// + /// The URL. + /// The expression. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. + /// The HttpCompletionOption used in the request. Optional. + /// A Task whose result is the XML response body parsed into a collection of XElements. + public static Task> GetXElementsFromXPath(this Url url, string expression, + CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) => + new FlurlRequest(url).GetXElementsFromXPath(expression, cancellationToken, completionOption); - /// - /// Sends an asynchronous GET request. - /// - /// The URL. - /// The expression. - /// The resolver. - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. - /// The HttpCompletionOption used in the request. Optional. - /// A Task whose result is the XML response body parsed into a collection of XElements. - public static Task> GetXElementsFromXPath(this Url url, string expression, IXmlNamespaceResolver resolver, - CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) => - new FlurlRequest(url).GetXElementsFromXPath(expression, resolver, cancellationToken, completionOption); + /// + /// Sends an asynchronous GET request. + /// + /// The URL. + /// The expression. + /// The resolver. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. + /// The HttpCompletionOption used in the request. Optional. + /// A Task whose result is the XML response body parsed into a collection of XElements. + public static Task> GetXElementsFromXPath(this Url url, string expression, IXmlNamespaceResolver resolver, + CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) => + new FlurlRequest(url).GetXElementsFromXPath(expression, resolver, cancellationToken, completionOption); - /// - /// Creates a FlurlClient from the URL and sends an asynchronous HTTP request. - /// - /// The URL. - /// HTTP method of the request - /// Contents of the request body. - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. - /// The HttpCompletionOption used in the request. Optional. - /// A Task whose result is the received IFlurlResponse. - public static Task SendXmlAsync(this Url url, HttpMethod method, object data, - CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) => - new FlurlRequest(url).SendXmlAsync(method, data, cancellationToken, completionOption); + /// + /// Creates a FlurlClient from the URL and sends an asynchronous HTTP request. + /// + /// The URL. + /// HTTP method of the request + /// Contents of the request body. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. + /// The HttpCompletionOption used in the request. Optional. + /// A Task whose result is the received IFlurlResponse. + public static Task SendXmlAsync(this Url url, HttpMethod method, object data, + CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) => + new FlurlRequest(url).SendXmlAsync(method, data, cancellationToken, completionOption); - /// - /// Creates a FlurlClient from the URL and sends an asynchronous POST request. - /// - /// The URL. - /// Contents of the request body. - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. - /// The HttpCompletionOption used in the request. Optional. - /// A Task whose result is the received IFlurlResponse. - public static Task PostXmlAsync(this Url url, object data, - CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) => - new FlurlRequest(url).PostXmlAsync(data, cancellationToken, completionOption); + /// + /// Creates a FlurlClient from the URL and sends an asynchronous POST request. + /// + /// The URL. + /// Contents of the request body. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. + /// The HttpCompletionOption used in the request. Optional. + /// A Task whose result is the received IFlurlResponse. + public static Task PostXmlAsync(this Url url, object data, + CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) => + new FlurlRequest(url).PostXmlAsync(data, cancellationToken, completionOption); - /// - /// Creates a FlurlClient from the URL and sends an asynchronous PUT request. - /// - /// The URL. - /// Contents of the request body. - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. - /// The HttpCompletionOption used in the request. Optional. - /// A Task whose result is the received IFlurlResponse. - public static Task PutXmlAsync(this Url url, object data, - CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) => - new FlurlRequest(url).PutXmlAsync(data, cancellationToken, completionOption); - } + /// + /// Creates a FlurlClient from the URL and sends an asynchronous PUT request. + /// + /// The URL. + /// Contents of the request body. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional. + /// The HttpCompletionOption used in the request. Optional. + /// A Task whose result is the received IFlurlResponse. + public static Task PutXmlAsync(this Url url, object data, + CancellationToken cancellationToken = default, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) => + new FlurlRequest(url).PutXmlAsync(data, cancellationToken, completionOption); } \ No newline at end of file diff --git a/src/Flurl.Http.Xml/Utf8StringWriter.cs b/src/Flurl.Http.Xml/Utf8StringWriter.cs index 4ec134b..f04a65c 100644 --- a/src/Flurl.Http.Xml/Utf8StringWriter.cs +++ b/src/Flurl.Http.Xml/Utf8StringWriter.cs @@ -1,34 +1,33 @@ using System.IO; using System.Text; -namespace Flurl.Http.Xml +namespace Flurl.Http.Xml; + +/// +/// Utf8StringWriter +/// +/// +internal class Utf8StringWriter : StringWriter { /// - /// Utf8StringWriter + /// Initializes a new instance of the class. /// - /// - internal class Utf8StringWriter : StringWriter - { - /// - /// Initializes a new instance of the class. - /// - public Utf8StringWriter() - { } + public Utf8StringWriter() + { } - /// - /// Initializes a new instance of the class. - /// - /// The builder. - public Utf8StringWriter(StringBuilder builder) - : base(builder) - { } + /// + /// Initializes a new instance of the class. + /// + /// The builder. + public Utf8StringWriter(StringBuilder builder) + : base(builder) + { } - /// - /// Gets the encoding. - /// - /// - /// The encoding. - /// - public override Encoding Encoding => Encoding.UTF8; - } + /// + /// Gets the encoding. + /// + /// + /// The encoding. + /// + public override Encoding Encoding => Encoding.UTF8; } \ No newline at end of file diff --git a/src/Flurl.Http.Xml/XDocumentExtensions.cs b/src/Flurl.Http.Xml/XDocumentExtensions.cs index bd0870f..d4407bb 100644 --- a/src/Flurl.Http.Xml/XDocumentExtensions.cs +++ b/src/Flurl.Http.Xml/XDocumentExtensions.cs @@ -1,25 +1,25 @@ using System.Text; using System.Xml.Linq; -namespace Flurl.Http.Xml +namespace Flurl.Http.Xml; + +/// +/// XDocumentExtensions +/// +public static class XDocumentExtensions { /// - /// XDocumentExtensions + /// To the string with declaration. /// - public static class XDocumentExtensions + /// The document. + public static string ToStringWithDeclaration(this XDocument doc) { - /// - /// To the string with declaration. - /// - /// The document. - public static string ToStringWithDeclaration(this XDocument doc) + var sb = new StringBuilder(); + using (var writer = new Utf8StringWriter(sb)) { - var sb = new StringBuilder(); - using (var writer = new Utf8StringWriter(sb)) - { - doc.Save(writer); - } - return sb.ToString(); + doc.Save(writer); } + + return sb.ToString(); } } \ No newline at end of file diff --git a/test/Flurl.Http.Xml.Tests/AssemblyInfo.cs b/test/Flurl.Http.Xml.Tests/AssemblyInfo.cs index 39f1749..87e5ee1 100644 --- a/test/Flurl.Http.Xml.Tests/AssemblyInfo.cs +++ b/test/Flurl.Http.Xml.Tests/AssemblyInfo.cs @@ -1,4 +1,5 @@ using Xunit; + [assembly: CollectionBehavior(DisableTestParallelization = true)] [assembly: TestCaseOrderer("Xunit.Extensions.Ordering.TestCaseOrderer", "Xunit.Extensions.Ordering")] [assembly: TestCollectionOrderer("Xunit.Extensions.Ordering.CollectionOrderer", "Xunit.Extensions.Ordering")] diff --git a/test/Flurl.Http.Xml.Tests/Factories/BaseTestModelClientFactory.cs b/test/Flurl.Http.Xml.Tests/Factories/BaseTestModelClientFactory.cs deleted file mode 100644 index de2885f..0000000 --- a/test/Flurl.Http.Xml.Tests/Factories/BaseTestModelClientFactory.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Net.Http; -using Flurl.Http.Configuration; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.TestHost; - -namespace Flurl.Http.Xml.Tests.Factories -{ - public abstract class BaseTestModelClientFactory : DefaultHttpClientFactory - { - private readonly string _responseBody; - - protected BaseTestModelClientFactory(string responseBody) - { - _responseBody = responseBody; - } - - private HttpClient GetClient() - { - var builder = new WebHostBuilder().Configure(app => - { - app.Use(async (context, next) => - { - await context.Response.WriteAsync(_responseBody); - }); - }); - - var server = new TestServer(builder) { AllowSynchronousIO = true }; - return server.CreateClient(); - } - - public override HttpClient CreateHttpClient(HttpMessageHandler handler) => GetClient(); - } -} diff --git a/test/Flurl.Http.Xml.Tests/Factories/EchoHttpClientFactory.cs b/test/Flurl.Http.Xml.Tests/Factories/EchoHttpClientFactory.cs deleted file mode 100644 index 97fea24..0000000 --- a/test/Flurl.Http.Xml.Tests/Factories/EchoHttpClientFactory.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System.IO; -using System.Net.Http; -using System.Text; -using Flurl.Http.Configuration; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.TestHost; - -namespace Flurl.Http.Xml.Tests.Factories -{ - public class EchoHttpClientFactory : DefaultHttpClientFactory - { - private string HttpRequestBodyToString(HttpRequest httpRequest) - { - string result; - - httpRequest.EnableBuffering(); - - using (var reader = new StreamReader(httpRequest.Body, Encoding.UTF8, true, 1024, true)) - { - result = reader.ReadToEnd(); - } - - httpRequest.Body.Position = 0; - - return result; - } - - private HttpClient GetClient() - { - var builder = new WebHostBuilder().Configure(app => - { - app.Use(async (context, next) => - { - string requestBody = HttpRequestBodyToString(context.Request); - await context.Response.WriteAsync(requestBody); - }); - }); - - var server = new TestServer(builder) { AllowSynchronousIO = true }; - return server.CreateClient(); - } - - public override HttpClient CreateHttpClient(HttpMessageHandler handler) => GetClient(); - } -} \ No newline at end of file diff --git a/test/Flurl.Http.Xml.Tests/Factories/JsonTestModelHttpClientFactory.cs b/test/Flurl.Http.Xml.Tests/Factories/JsonTestModelHttpClientFactory.cs deleted file mode 100644 index 73c2d7e..0000000 --- a/test/Flurl.Http.Xml.Tests/Factories/JsonTestModelHttpClientFactory.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Flurl.Http.Xml.Tests.Factories -{ - public class JsonTestModelHttpClientFactory : BaseTestModelClientFactory - { - private const string REQUEST_BODY_JSON = @"{ - ""number"": 3, - ""text"": ""Test"" -}"; - - public JsonTestModelHttpClientFactory() - : base(REQUEST_BODY_JSON) - { } - } -} \ No newline at end of file diff --git a/test/Flurl.Http.Xml.Tests/Factories/XmlTestModelHttpClientFactory.cs b/test/Flurl.Http.Xml.Tests/Factories/XmlTestModelHttpClientFactory.cs deleted file mode 100644 index f4569c4..0000000 --- a/test/Flurl.Http.Xml.Tests/Factories/XmlTestModelHttpClientFactory.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Flurl.Http.Xml.Tests.Factories -{ - public class XmlTestModelHttpClientFactory : BaseTestModelClientFactory - { - private const string REQUEST_BODY_XML = @" - - 3 - Test -"; - - public XmlTestModelHttpClientFactory() - : base(REQUEST_BODY_XML) - { } - } -} \ No newline at end of file diff --git a/test/Flurl.Http.Xml.Tests/Flurl.Http.Xml.Tests.csproj b/test/Flurl.Http.Xml.Tests/Flurl.Http.Xml.Tests.csproj index 6e11ae0..bed8b0a 100644 --- a/test/Flurl.Http.Xml.Tests/Flurl.Http.Xml.Tests.csproj +++ b/test/Flurl.Http.Xml.Tests/Flurl.Http.Xml.Tests.csproj @@ -1,7 +1,8 @@  - netcoreapp3.1 + net8 + latest Flurl.Http.Xml.Tests Flurl.Http.Xml.Tests true @@ -12,15 +13,14 @@ - + - - - - - + + + + - + all runtime; build; native; contentfiles; analyzers diff --git a/test/Flurl.Http.Xml.Tests/JsonTestModelHttpMiddleware.cs b/test/Flurl.Http.Xml.Tests/JsonTestModelHttpMiddleware.cs new file mode 100644 index 0000000..6f4cb66 --- /dev/null +++ b/test/Flurl.Http.Xml.Tests/JsonTestModelHttpMiddleware.cs @@ -0,0 +1,26 @@ +using System; +using System.Net.Http; +using System.Threading.Tasks; +using System.Threading; + +namespace Flurl.Http.Xml.Tests; + +public class JsonTestModelHttpMiddleware : DelegatingHandler +{ + protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + if (request == null) + { + throw new ArgumentNullException(nameof(request)); + } + + + return Task.FromResult(new HttpResponseMessage + { + Content = new StringContent(@"{ + ""number"": 3, + ""text"": ""Test"" +}") + }); + } +} diff --git a/test/Flurl.Http.Xml.Tests/MicrosoftXmlSerializerShould.cs b/test/Flurl.Http.Xml.Tests/MicrosoftXmlSerializerShould.cs index ef94d95..b613f0b 100644 --- a/test/Flurl.Http.Xml.Tests/MicrosoftXmlSerializerShould.cs +++ b/test/Flurl.Http.Xml.Tests/MicrosoftXmlSerializerShould.cs @@ -3,52 +3,51 @@ using Flurl.Http.Xml.Tests.Models; using Xunit; -namespace Flurl.Http.Xml.Tests +namespace Flurl.Http.Xml.Tests; + +public class MicrosoftXmlSerializerShould { - public class MicrosoftXmlSerializerShould - { - const string XML_WITHOUT_DECLARATION = - @" + private const string XML_WITHOUT_DECLARATION = + @" 3 Test "; - const string XML_WITH_DECLARATION = @"" + "\r\n" + XML_WITHOUT_DECLARATION; + private const string XML_WITH_DECLARATION = @"" + "\r\n" + XML_WITHOUT_DECLARATION; - private readonly MicrosoftXmlSerializer _serializer; + private readonly MicrosoftXmlSerializer _serializer; - public MicrosoftXmlSerializerShould() - { - var settings = new XmlWriterSettings { Encoding = new UTF8Encoding(false, false), Indent = true, OmitXmlDeclaration = false }; - _serializer = new MicrosoftXmlSerializer(settings); - } + public MicrosoftXmlSerializerShould() + { + var settings = new XmlWriterSettings { Encoding = new UTF8Encoding(false, false), Indent = true, OmitXmlDeclaration = false }; + _serializer = new MicrosoftXmlSerializer(settings); + } - [Fact] - public void Serialize() - { - var model = new TestModel { Number = 3, Text = "Test" }; - model = _serializer.Deserialize(_serializer.Serialize(model)); + [Fact] + public void DeserializeModel() + { + var model = new TestModel { Number = 3, Text = "Test" }; + model = _serializer.Deserialize(_serializer.Serialize(model)); - Assert.Equal(3, model.Number); - Assert.Equal("Test", model.Text); - } + Assert.Equal(3, model.Number); + Assert.Equal("Test", model.Text); + } - [Fact] - public void DeserializeWithDeclaration() - { - var model = _serializer.Deserialize(XML_WITH_DECLARATION); + [Fact] + public void DeserializeWithDeclaration() + { + var model = _serializer.Deserialize(XML_WITH_DECLARATION); - Assert.Equal(3, model.Number); - Assert.Equal("Test", model.Text); - } + Assert.Equal(3, model.Number); + Assert.Equal("Test", model.Text); + } - [Fact] - public void DeserializeWithoutDeclaration() - { - var model = _serializer.Deserialize(XML_WITHOUT_DECLARATION); + [Fact] + public void DeserializeWithoutDeclaration() + { + var model = _serializer.Deserialize(XML_WITHOUT_DECLARATION); - Assert.Equal(3, model.Number); - Assert.Equal("Test", model.Text); - } + Assert.Equal(3, model.Number); + Assert.Equal("Test", model.Text); } -} +} \ No newline at end of file diff --git a/test/Flurl.Http.Xml.Tests/Models/TestModel.cs b/test/Flurl.Http.Xml.Tests/Models/TestModel.cs index f5fc63f..32b8c47 100644 --- a/test/Flurl.Http.Xml.Tests/Models/TestModel.cs +++ b/test/Flurl.Http.Xml.Tests/Models/TestModel.cs @@ -1,8 +1,7 @@ -namespace Flurl.Http.Xml.Tests.Models +namespace Flurl.Http.Xml.Tests.Models; + +public class TestModel { - public class TestModel - { - public int Number { get; set; } - public string Text { get; set; } - } -} + public int Number { get; set; } + public string Text { get; set; } +} \ No newline at end of file diff --git a/test/Flurl.Http.Xml.Tests/RequestExtensionsShould.cs b/test/Flurl.Http.Xml.Tests/RequestExtensionsShould.cs index 0fcfe17..0024592 100644 --- a/test/Flurl.Http.Xml.Tests/RequestExtensionsShould.cs +++ b/test/Flurl.Http.Xml.Tests/RequestExtensionsShould.cs @@ -1,212 +1,219 @@ using System.Linq; +using System.Net.Http; using System.Threading.Tasks; using System.Xml; using System.Xml.Linq; -using Flurl.Http.Xml.Tests.Factories; using Flurl.Http.Xml.Tests.Models; using Xunit; using Xunit.Extensions.Ordering; -namespace Flurl.Http.Xml.Tests +namespace Flurl.Http.Xml.Tests; + +public class RequestExtensionsShould : TestBase { - public class RequestExtensionsShould : TestBase + private void AssertTestModel(TestModel testModel, int expectedNumber, string expectedText) + { + Assert.NotNull(testModel); + Assert.Equal(expectedNumber, testModel.Number); + Assert.Equal(expectedText, testModel.Text); + } + + private void AssertXDocument(XDocument document, int expectedNumber, string expectedText) + { + Assert.Equal(expectedNumber.ToString(), document?.Element("TestModel")?.Element("Number")?.Value); + Assert.Equal(expectedText, document?.Element("TestModel")?.Element("Text")?.Value); + } + + [Fact, Order(1)] + public async Task GetXmlAsync() + { + using var flurlClient = XmlFlurlClientBuilder.Build(); + + var request = await new FlurlRequest(new Url("https://some.url")) + .WithVerb(HttpMethod.Get); + var result = await flurlClient + .SendAsync(request) + .ReceiveXml(); + + AssertTestModel(result, 3, "Test"); + } + + [Fact, Order(1)] + public async Task GetXDocumentAsync() { - private void AssertTestModel(TestModel testModel, int expectedNumber, string expectedText) - { - Assert.Equal(expectedNumber, testModel.Number); - Assert.Equal(expectedText, testModel.Text); - } - - private void AssertXDocument(XDocument document, int expectedNumber, string expectedText) - { - Assert.Equal(expectedNumber.ToString(), document?.Element("TestModel")?.Element("Number")?.Value); - Assert.Equal(expectedText, document?.Element("TestModel")?.Element("Text")?.Value); - } - - [Fact, Order(1)] - public async Task GetXmlAsync() - { - FlurlHttp.Configure(c => c.HttpClientFactory = new XmlTestModelHttpClientFactory()); - - var result = await new Url("https://some.url") - .AllowAnyHttpStatus() - .GetXmlAsync(); - - AssertTestModel(result, 3, "Test"); - } - - [Fact, Order(1)] - public async Task GetXDocumentAsync() - { - FlurlHttp.Configure(c => c.HttpClientFactory = new XmlTestModelHttpClientFactory()); - - var result = await new Url("https://some.url") - .AllowAnyHttpStatus() - .GetXDocumentAsync(); - - AssertXDocument(result, 3, "Test"); - } - - [Fact, Order(1)] - public async Task GetXElementsFromXPathAsync() - { - FlurlHttp.Configure(c => c.HttpClientFactory = new XmlTestModelHttpClientFactory()); - - var result = await new Url("https://some.url") - .AllowAnyHttpStatus() - .GetXElementsFromXPath("/TestModel"); - - AssertXDocument(result.FirstOrDefault()?.Document, 3, "Test"); - } - - [Fact, Order(1)] - public async Task GetXElementsFromXPathNamespaceResolverAsync() - { - FlurlHttp.Configure(c => c.HttpClientFactory = new XmlTestModelHttpClientFactory()); - - var result = await new Url("https://some.url") - .AllowAnyHttpStatus() - .GetXElementsFromXPath("/TestModel", new XmlNamespaceManager(new NameTable())); - - AssertXDocument(result.FirstOrDefault()?.Document, 3, "Test"); - } - - [Theory] - [InlineData(HttpMethodTypes.Post)] - [InlineData(HttpMethodTypes.Put)] - public async Task SendXmlToModelAsync(HttpMethodTypes methodType) - { - FlurlHttp.Configure(c => c.HttpClientFactory = new EchoHttpClientFactory()); - - var method = HttpMethodByType[methodType]; - var result = await new Url("https://some.url") - .AllowAnyHttpStatus() - .SendXmlAsync(method, new TestModel { Number = 3, Text = "Test" }) - .ReceiveXml(); - - AssertTestModel(result, 3, "Test"); - } - - [Theory] - [InlineData(HttpMethodTypes.Post)] - [InlineData(HttpMethodTypes.Put)] - public async Task SendXmlToXDocumentAsync(HttpMethodTypes methodType) - { - FlurlHttp.Configure(c => c.HttpClientFactory = new EchoHttpClientFactory()); - - var method = HttpMethodByType[methodType]; - var result = await new Url("https://some.url") - .AllowAnyHttpStatus() - .SendXmlAsync(method, new TestModel { Number = 3, Text = "Test" }) - .ReceiveXDocument(); - - AssertXDocument(result, 3, "Test"); - } - - [Fact] - public async Task PostXmlToModelAsync() - { - FlurlHttp.Configure(c => c.HttpClientFactory = new EchoHttpClientFactory()); - - var result = await new Url("https://some.url") - .AllowAnyHttpStatus() - .PostXmlAsync(new TestModel { Number = 3, Text = "Test" }) - .ReceiveXml(); - - AssertTestModel(result, 3, "Test"); - } - - [Fact] - public async Task PostXmlToXDocumentAsync() - { - FlurlHttp.Configure(c => c.HttpClientFactory = new EchoHttpClientFactory()); - - var result = await new Url("https://some.url") - .AllowAnyHttpStatus() - .PostXmlAsync(new TestModel { Number = 3, Text = "Test" }) - .ReceiveXDocument(); - - AssertXDocument(result, 3, "Test"); - } - - [Fact] - public async Task PutXmlToModelAsync() - { - FlurlHttp.Configure(c => c.HttpClientFactory = new EchoHttpClientFactory()); - - var result = await new Url("https://some.url") - .AllowAnyHttpStatus() - .PutXmlAsync(new TestModel { Number = 3, Text = "Test" }) - .ReceiveXml(); - - AssertTestModel(result, 3, "Test"); - } - - [Fact] - public async Task PutXmlToXDocumentAsync() - { - FlurlHttp.Configure(c => c.HttpClientFactory = new EchoHttpClientFactory()); - - var result = await new Url("https://some.url") - .AllowAnyHttpStatus() - .PutXmlAsync(new TestModel { Number = 3, Text = "Test" }) - .ReceiveXDocument(); - - AssertXDocument(result, 3, "Test"); - } - - [Theory] - [InlineData("", null, "application/xml")] - [InlineData("Accept", "application/json", "application/json")] - [InlineData("Accept", "text/something+xml", "text/something+xml")] - [InlineData("Accept", "text/xml, application/xml", "text/xml")] - [InlineData("Accept", null, "application/xml")] - public async Task ReceiveCorrectMediaType(string headerName, string acceptMediaType, string expectedContentType) - { - FlurlHttp.Configure(c => c.HttpClientFactory = new EchoHttpClientFactory()); - - var result = await new Url("https://some.url") - .WithHeader(headerName, acceptMediaType) - .PostXmlAsync(new TestModel { Number = 3, Text = "Test" }) - .ReceiveXmlResponseMessage(); - - Assert.Equal(expectedContentType, result?.ResponseMessage.Content?.Headers?.ContentType?.MediaType); - } - - [Theory] - [InlineData("", null)] - [InlineData("Accept", "application/json")] - [InlineData("Accept", "text/something+xml")] - [InlineData("Accept", "text/xml, application/xml")] - [InlineData("Accept", null)] - public async Task ReceiveCorrectMediaTypeWithXmlResponse(string headerName, string acceptMediaType) - { - FlurlHttp.Configure(c => c.HttpClientFactory = new XmlTestModelHttpClientFactory()); - - var result = await new Url("https://some.url") - .WithHeader(headerName, acceptMediaType) - .PostXmlAsync(new TestModel { Number = 3, Text = "Test" }) - .ReceiveXml(); - - AssertTestModel(result, 3, "Test"); - } - - [Theory, Order(4)] - [InlineData("", null)] - [InlineData("Accept", "application/json")] - [InlineData("Accept", "text/something+xml")] - [InlineData("Accept", "text/xml, application/xml")] - [InlineData("Accept", null)] - public async Task ReceiveCorrectMediaTypeWithJsonResponse(string headerName, string acceptMediaType) - { - FlurlHttp.Configure(c => c.HttpClientFactory = new JsonTestModelHttpClientFactory()); - - var result = await new Url("https://some.url") - .WithHeader(headerName, acceptMediaType) - .PostXmlAsync(new TestModel { Number = 3, Text = "Test" }) - .ReceiveJson(); - - AssertTestModel(result, 3, "Test"); - } + using var flurlClient = XmlFlurlClientBuilder.Build(); + + var result = await flurlClient + .Request(new Url("https://some.url")) + .GetXDocumentAsync(); + + AssertXDocument(result, 3, "Test"); + } + + [Fact, Order(1)] + public async Task GetXElementsFromXPathAsync() + { + using var flurlClient = XmlFlurlClientBuilder.Build(); + + var result = await flurlClient + .Request(new Url("https://some.url")) + .GetXElementsFromXPath("/TestModel"); + + AssertXDocument(result.FirstOrDefault()?.Document, 3, "Test"); + } + + [Fact, Order(1)] + public async Task GetXElementsFromXPathNamespaceResolverAsync() + { + using var flurlClient = XmlFlurlClientBuilder.Build(); + + var result = await flurlClient + .Request(new Url("https://some.url")) + .GetXElementsFromXPath("/TestModel", new XmlNamespaceManager(new NameTable())); + + AssertXDocument(result.FirstOrDefault()?.Document, 3, "Test"); + } + + [Theory] + [InlineData(HttpMethodTypes.Post)] + [InlineData(HttpMethodTypes.Put)] + public async Task SendXmlToModelAsync(HttpMethodTypes methodType) + { + using var flurlClient = XmlFlurlClientBuilder.Build(); + + var method = HttpMethodByType[methodType]; + var result = await flurlClient + .Request(new Url("https://some.url")) + .AllowAnyHttpStatus() + .SendXmlAsync(method, new TestModel { Number = 3, Text = "Test" }) + .ReceiveXml(); + + AssertTestModel(result, 3, "Test"); + } + + [Theory] + [InlineData(HttpMethodTypes.Post)] + [InlineData(HttpMethodTypes.Put)] + public async Task SendXmlToXDocumentAsync(HttpMethodTypes methodType) + { + using var flurlClient = XmlFlurlClientBuilder.Build(); + + var method = HttpMethodByType[methodType]; + var result = await flurlClient + .Request(new Url("https://some.url")) + .AllowAnyHttpStatus() + .SendXmlAsync(method, new TestModel { Number = 3, Text = "Test" }) + .ReceiveXDocument(); + + AssertXDocument(result, 3, "Test"); + } + + [Fact] + public async Task PostXmlToModelAsync() + { + using var flurlClient = XmlFlurlClientBuilder.Build(); + + var result = await flurlClient + .Request(new Url("https://some.url")) + .PostXmlAsync(new TestModel { Number = 3, Text = "Test" }) + .ReceiveXml(); + + AssertTestModel(result, 3, "Test"); + } + + [Fact] + public async Task PostXmlToXDocumentAsync() + { + using var flurlClient = XmlFlurlClientBuilder.Build(); + + var result = await flurlClient + .Request(new Url("https://some.url")) + .PostXmlAsync(new TestModel { Number = 3, Text = "Test" }) + .ReceiveXDocument(); + + AssertXDocument(result, 3, "Test"); + } + + [Fact] + public async Task PutXmlToModelAsync() + { + using var flurlClient = XmlFlurlClientBuilder.Build(); + + var result = await flurlClient + .Request(new Url("https://some.url")) + .PutXmlAsync(new TestModel { Number = 3, Text = "Test" }) + .ReceiveXml(); + + AssertTestModel(result, 3, "Test"); + } + + [Fact] + public async Task PutXmlToXDocumentAsync() + { + using var flurlClient = XmlFlurlClientBuilder.Build(); + + var result = await flurlClient + .Request(new Url("https://some.url")) + .PutXmlAsync(new TestModel { Number = 3, Text = "Test" }) + .ReceiveXDocument(); + + AssertXDocument(result, 3, "Test"); + } + + [Theory] + [InlineData("", null, "application/xml")] + [InlineData("Accept", "application/json", "application/json")] + [InlineData("Accept", "text/something+xml", "text/something+xml")] + [InlineData("Accept", "text/xml, application/xml", "text/xml")] + [InlineData("Accept", null, "application/xml")] + public async Task ReceiveCorrectMediaType(string headerName, string acceptMediaType, string expectedContentType) + { + using var flurlClient = XmlFlurlClientBuilder.Build(); + + var result = await flurlClient + .Request(new Url("https://some.url")) + .WithHeader(headerName, acceptMediaType) + .PostXmlAsync(new TestModel { Number = 3, Text = "Test" }) + .ReceiveXmlResponseMessage(); + + Assert.Equal(expectedContentType, result?.ResponseMessage.Content.Headers.ContentType?.MediaType); + } + + [Theory] + [InlineData("", null)] + [InlineData("Accept", "application/json")] + [InlineData("Accept", "text/something+xml")] + [InlineData("Accept", "text/xml, application/xml")] + [InlineData("Accept", null)] + public async Task ReceiveCorrectMediaTypeWithXmlResponse(string headerName, string acceptMediaType) + { + using var flurlClient = XmlFlurlClientBuilder.Build(); + + var result = await flurlClient + .Request(new Url("https://some.url")) + .WithHeader(headerName, acceptMediaType) + .PostXmlAsync(new TestModel { Number = 3, Text = "Test" }) + .ReceiveXml(); + + AssertTestModel(result, 3, "Test"); + } + + [Theory, Order(4)] + [InlineData("", null)] + [InlineData("Accept", "application/json")] + [InlineData("Accept", "text/something+xml")] + [InlineData("Accept", "text/xml, application/xml")] + [InlineData("Accept", null)] + public async Task ReceiveCorrectMediaTypeWithJsonResponse(string headerName, string acceptMediaType) + { + using var flurlClient = JsonFlurlClientBuilder.Build(); + + var result = await flurlClient + .Request(new Url("https://some.url")) + .WithHeader(headerName, acceptMediaType) + .PostXmlAsync(new TestModel { Number = 3, Text = "Test" }) + .ReceiveJson(); + + AssertTestModel(result, 3, "Test"); } } diff --git a/test/Flurl.Http.Xml.Tests/StringExtensionsShould.cs b/test/Flurl.Http.Xml.Tests/StringExtensionsShould.cs index 54738f9..19dfed7 100644 --- a/test/Flurl.Http.Xml.Tests/StringExtensionsShould.cs +++ b/test/Flurl.Http.Xml.Tests/StringExtensionsShould.cs @@ -2,147 +2,155 @@ using System.Threading.Tasks; using System.Xml; using System.Xml.Linq; -using Flurl.Http.Xml.Tests.Factories; using Flurl.Http.Xml.Tests.Models; using Xunit; using Xunit.Extensions.Ordering; -namespace Flurl.Http.Xml.Tests +namespace Flurl.Http.Xml.Tests; + +public class StringExtensionsShould : TestBase { - public class StringExtensionsShould : TestBase + private void AssertTestModel(TestModel testModel, int expectedNumber, string expectedText) + { + Assert.Equal(expectedNumber, testModel.Number); + Assert.Equal(expectedText, testModel.Text); + } + + private void AssertXDocument(XDocument document, int expectedNumber, string expectedText) + { + Assert.Equal(expectedNumber.ToString(), document?.Element("TestModel")?.Element("Number")?.Value); + Assert.Equal(expectedText, document?.Element("TestModel")?.Element("Text")?.Value); + } + + [Fact, Order(2)] + public async Task GetXmlAsync() + { + using var flurlClient = XmlFlurlClientBuilder.Build(); + + var result = await flurlClient + .Request(new Url("https://some.url")) + .GetXmlAsync(); + + AssertTestModel(result, 3, "Test"); + } + + [Fact, Order(2)] + public async Task GetXDocumentAsync() + { + using var flurlClient = XmlFlurlClientBuilder.Build(); + + var result = await flurlClient + .Request(new Url("https://some.url")) + .GetXDocumentAsync(); + + AssertXDocument(result, 3, "Test"); + } + + [Fact, Order(2)] + public async Task GetXElementsFromXPathAsync() + { + using var flurlClient = XmlFlurlClientBuilder.Build(); + + var result = await flurlClient + .Request(new Url("https://some.url")) + .GetXElementsFromXPath("/TestModel"); + + AssertXDocument(result.FirstOrDefault()?.Document, 3, "Test"); + } + + [Fact, Order(2)] + public async Task GetXElementsFromXPathNamespaceResolverAsync() + { + using var flurlClient = XmlFlurlClientBuilder.Build(); + + var result = await flurlClient + .Request(new Url("https://some.url")) + .GetXElementsFromXPath("/TestModel", new XmlNamespaceManager(new NameTable())); + + AssertXDocument(result.FirstOrDefault()?.Document, 3, "Test"); + } + + [Theory] + [InlineData(HttpMethodTypes.Post)] + [InlineData(HttpMethodTypes.Put)] + public async Task SendXmlToModelAsync(HttpMethodTypes methodType) + { + using var flurlClient = XmlFlurlClientBuilder.Build(); + + var method = HttpMethodByType[methodType]; + var result = await flurlClient + .Request(new Url("https://some.url")) + .SendXmlAsync(method, new TestModel { Number = 3, Text = "Test" }) + .ReceiveXml(); + + AssertTestModel(result, 3, "Test"); + } + + [Theory] + [InlineData(HttpMethodTypes.Post)] + [InlineData(HttpMethodTypes.Put)] + public async Task SendXmlToXDocumentAsync(HttpMethodTypes methodType) { - private void AssertTestModel(TestModel testModel, int expectedNumber, string expectedText) - { - Assert.Equal(expectedNumber, testModel.Number); - Assert.Equal(expectedText, testModel.Text); - } - - private void AssertXDocument(XDocument document, int expectedNumber, string expectedText) - { - Assert.Equal(expectedNumber.ToString(), document?.Element("TestModel")?.Element("Number")?.Value); - Assert.Equal(expectedText, document?.Element("TestModel")?.Element("Text")?.Value); - } - - [Fact, Order(2)] - public async Task GetXmlAsync() - { - FlurlHttp.Configure(c => c.HttpClientFactory = new XmlTestModelHttpClientFactory()); - - var result = await "https://some.url" - .GetXmlAsync(); - - AssertTestModel(result, 3, "Test"); - } - - [Fact, Order(2)] - public async Task GetXDocumentAsync() - { - FlurlHttp.Configure(c => c.HttpClientFactory = new XmlTestModelHttpClientFactory()); - - var result = await "https://some.url" - .GetXDocumentAsync(); - - AssertXDocument(result, 3, "Test"); - } - - [Fact, Order(2)] - public async Task GetXElementsFromXPathAsync() - { - FlurlHttp.Configure(c => c.HttpClientFactory = new XmlTestModelHttpClientFactory()); - - var result = await "https://some.url" - .GetXElementsFromXPath("/TestModel"); - - AssertXDocument(result.FirstOrDefault()?.Document, 3, "Test"); - } - - [Fact, Order(2)] - public async Task GetXElementsFromXPathNamespaceResolverAsync() - { - FlurlHttp.Configure(c => c.HttpClientFactory = new XmlTestModelHttpClientFactory()); - - var result = await "https://some.url" - .GetXElementsFromXPath("/TestModel", new XmlNamespaceManager(new NameTable())); - - AssertXDocument(result.FirstOrDefault()?.Document, 3, "Test"); - } - - [Theory] - [InlineData(HttpMethodTypes.Post)] - [InlineData(HttpMethodTypes.Put)] - public async Task SendXmlToModelAsync(HttpMethodTypes methodType) - { - FlurlHttp.Configure(c => c.HttpClientFactory = new EchoHttpClientFactory()); - - var method = HttpMethodByType[methodType]; - var result = await "http://some.url" - .SendXmlAsync(method, new TestModel { Number = 3, Text = "Test" }) - .ReceiveXml(); - - AssertTestModel(result, 3, "Test"); - } - - [Theory] - [InlineData(HttpMethodTypes.Post)] - [InlineData(HttpMethodTypes.Put)] - public async Task SendXmlToXDocumentAsync(HttpMethodTypes methodType) - { - FlurlHttp.Configure(c => c.HttpClientFactory = new EchoHttpClientFactory()); - - var method = HttpMethodByType[methodType]; - var result = await "http://some.url" - .SendXmlAsync(method, new TestModel { Number = 3, Text = "Test" }) - .ReceiveXDocument(); - - AssertXDocument(result, 3, "Test"); - } - - [Fact] - public async Task PostXmlToModelAsync() - { - FlurlHttp.Configure(c => c.HttpClientFactory = new EchoHttpClientFactory()); - - var result = await "http://some.url" - .PostXmlAsync(new TestModel { Number = 3, Text = "Test" }) - .ReceiveXml(); - - AssertTestModel(result, 3, "Test"); - } - - [Fact] - public async Task PostXmlToXDocumentAsync() - { - FlurlHttp.Configure(c => c.HttpClientFactory = new EchoHttpClientFactory()); - - var result = await "http://some.url" - .PostXmlAsync(new TestModel { Number = 3, Text = "Test" }) - .ReceiveXDocument(); - - AssertXDocument(result, 3, "Test"); - } - - [Fact] - public async Task PutXmlToModelAsync() - { - FlurlHttp.Configure(c => c.HttpClientFactory = new EchoHttpClientFactory()); + using var flurlClient = XmlFlurlClientBuilder.Build(); - var result = await "http://some.url" - .PutXmlAsync(new TestModel { Number = 3, Text = "Test" }) - .ReceiveXml(); + var method = HttpMethodByType[methodType]; + var result = await flurlClient + .Request(new Url("https://some.url")) + .SendXmlAsync(method, new TestModel { Number = 3, Text = "Test" }) + .ReceiveXDocument(); - AssertTestModel(result, 3, "Test"); - } - - [Fact] - public async Task PutXmlToXDocumentAsync() - { - FlurlHttp.Configure(c => c.HttpClientFactory = new EchoHttpClientFactory()); + AssertXDocument(result, 3, "Test"); + } + + [Fact] + public async Task PostXmlToModelAsync() + { + using var flurlClient = XmlFlurlClientBuilder.Build(); + + var result = await flurlClient + .Request(new Url("https://some.url")) + .PostXmlAsync(new TestModel { Number = 3, Text = "Test" }) + .ReceiveXml(); + + AssertTestModel(result, 3, "Test"); + } + + [Fact] + public async Task PostXmlToXDocumentAsync() + { + using var flurlClient = XmlFlurlClientBuilder.Build(); + + var result = await flurlClient + .Request(new Url("https://some.url")) + .PostXmlAsync(new TestModel { Number = 3, Text = "Test" }) + .ReceiveXDocument(); + + AssertXDocument(result, 3, "Test"); + } + + [Fact] + public async Task PutXmlToModelAsync() + { + using var flurlClient = XmlFlurlClientBuilder.Build(); + + var result = await flurlClient + .Request(new Url("https://some.url")) + .PutXmlAsync(new TestModel { Number = 3, Text = "Test" }) + .ReceiveXml(); + + AssertTestModel(result, 3, "Test"); + } + + [Fact] + public async Task PutXmlToXDocumentAsync() + { + using var flurlClient = XmlFlurlClientBuilder.Build(); - var result = await "http://some.url" - .PutXmlAsync(new TestModel { Number = 3, Text = "Test" }) - .ReceiveXDocument(); + var result = await flurlClient + .Request(new Url("https://some.url")) + .PutXmlAsync(new TestModel { Number = 3, Text = "Test" }) + .ReceiveXDocument(); - AssertXDocument(result, 3, "Test"); - } + AssertXDocument(result, 3, "Test"); } -} +} \ No newline at end of file diff --git a/test/Flurl.Http.Xml.Tests/TestBase.cs b/test/Flurl.Http.Xml.Tests/TestBase.cs index 1a5e683..3801610 100644 --- a/test/Flurl.Http.Xml.Tests/TestBase.cs +++ b/test/Flurl.Http.Xml.Tests/TestBase.cs @@ -1,20 +1,31 @@ using System.Collections.Generic; using System.Net.Http; +using Flurl.Http.Configuration; -namespace Flurl.Http.Xml.Tests +namespace Flurl.Http.Xml.Tests; + +public abstract class TestBase { - public abstract class TestBase + public FlurlClientBuilder XmlFlurlClientBuilder { get; } + public FlurlClientBuilder JsonFlurlClientBuilder { get; } + + protected TestBase() { - public enum HttpMethodTypes - { - Post, - Put - } + XmlFlurlClientBuilder = new FlurlClientBuilder() + .AddMiddleware(() => new XmlTestModelHttpMiddleware()) as FlurlClientBuilder; + JsonFlurlClientBuilder = new FlurlClientBuilder() + .AddMiddleware(() => new JsonTestModelHttpMiddleware()) as FlurlClientBuilder; + } - protected readonly Dictionary HttpMethodByType = new Dictionary - { - [HttpMethodTypes.Post] = HttpMethod.Post, - [HttpMethodTypes.Put] = HttpMethod.Put - }; + public enum HttpMethodTypes + { + Post, + Put } -} + + protected readonly Dictionary HttpMethodByType = new Dictionary + { + [HttpMethodTypes.Post] = HttpMethod.Post, + [HttpMethodTypes.Put] = HttpMethod.Put + }; +} \ No newline at end of file diff --git a/test/Flurl.Http.Xml.Tests/UrlExtensionsShould.cs b/test/Flurl.Http.Xml.Tests/UrlExtensionsShould.cs index 0d22c1e..8476b43 100644 --- a/test/Flurl.Http.Xml.Tests/UrlExtensionsShould.cs +++ b/test/Flurl.Http.Xml.Tests/UrlExtensionsShould.cs @@ -2,157 +2,155 @@ using System.Threading.Tasks; using System.Xml; using System.Xml.Linq; -using Flurl.Http.Xml.Tests.Factories; using Flurl.Http.Xml.Tests.Models; using Xunit; using Xunit.Extensions.Ordering; -namespace Flurl.Http.Xml.Tests +namespace Flurl.Http.Xml.Tests; + +public class UrlExtensionsShould : TestBase { - public class UrlExtensionsShould : TestBase + private void AssertTestModel(TestModel testModel, int expectedNumber, string expectedText) + { + Assert.Equal(expectedNumber, testModel.Number); + Assert.Equal(expectedText, testModel.Text); + } + + private void AssertXDocument(XDocument document, int expectedNumber, string expectedText) + { + Assert.Equal(expectedNumber.ToString(), document?.Element("TestModel")?.Element("Number")?.Value); + Assert.Equal(expectedText, document?.Element("TestModel")?.Element("Text")?.Value); + } + + [Fact, Order(3)] + public async Task GetXmlAsync() + { + using var flurlClient = XmlFlurlClientBuilder.Build(); + + var result = await flurlClient + .Request(new Url("https://some.url")) + .GetXmlAsync(); + + AssertTestModel(result, 3, "Test"); + } + + [Fact, Order(3)] + public async Task GetXDocumentAsync() + { + using var flurlClient = XmlFlurlClientBuilder.Build(); + + var result = await flurlClient + .Request(new Url("https://some.url")) + .GetXDocumentAsync(); + + AssertXDocument(result, 3, "Test"); + } + + [Fact, Order(3)] + public async Task GetXElementsFromXPathAsync() + { + using var flurlClient = XmlFlurlClientBuilder.Build(); + + var result = await flurlClient + .Request(new Url("https://some.url")) + .GetXElementsFromXPath("/TestModel"); + + AssertXDocument(result.FirstOrDefault()?.Document, 3, "Test"); + } + + [Fact, Order(3)] + public async Task GetXElementsFromXPathNamespaceResolverAsync() + { + using var flurlClient = XmlFlurlClientBuilder.Build(); + + var result = await flurlClient + .Request(new Url("https://some.url")) + .GetXElementsFromXPath("/TestModel", new XmlNamespaceManager(new NameTable())); + + AssertXDocument(result.FirstOrDefault()?.Document, 3, "Test"); + } + + [Theory] + [InlineData(HttpMethodTypes.Post)] + [InlineData(HttpMethodTypes.Put)] + public async Task SendXmlToModelAsync(HttpMethodTypes methodType) { - private void AssertTestModel(TestModel testModel, int expectedNumber, string expectedText) - { - Assert.Equal(expectedNumber, testModel.Number); - Assert.Equal(expectedText, testModel.Text); - } - - private void AssertXDocument(XDocument document, int expectedNumber, string expectedText) - { - Assert.Equal(expectedNumber.ToString(), document?.Element("TestModel")?.Element("Number")?.Value); - Assert.Equal(expectedText, document?.Element("TestModel")?.Element("Text")?.Value); - } - - [Fact, Order(3)] - public async Task GetXmlAsync() - { - FlurlHttp.Configure(c => c.HttpClientFactory = new XmlTestModelHttpClientFactory()); - - var result = await new Url("https://some.url") - .GetXmlAsync() - .ConfigureAwait(false); - - AssertTestModel(result, 3, "Test"); - } - - [Fact, Order(3)] - public async Task GetXDocumentAsync() - { - FlurlHttp.Configure(c => c.HttpClientFactory = new XmlTestModelHttpClientFactory()); - - var result = await new Url("https://some.url") - .GetXDocumentAsync() - .ConfigureAwait(false); - - AssertXDocument(result, 3, "Test"); - } - - [Fact, Order(3)] - public async Task GetXElementsFromXPathAsync() - { - FlurlHttp.Configure(c => c.HttpClientFactory = new XmlTestModelHttpClientFactory()); - - var result = await new Url("https://some.url") - .GetXElementsFromXPath("/TestModel") - .ConfigureAwait(false); - - AssertXDocument(result.FirstOrDefault()?.Document, 3, "Test"); - } - - [Fact, Order(3)] - public async Task GetXElementsFromXPathNamespaceResolverAsync() - { - FlurlHttp.Configure(c => c.HttpClientFactory = new XmlTestModelHttpClientFactory()); - - var result = await new Url("https://some.url") - .GetXElementsFromXPath("/TestModel", new XmlNamespaceManager(new NameTable())) - .ConfigureAwait(false); - - AssertXDocument(result.FirstOrDefault()?.Document, 3, "Test"); - } - - [Theory] - [InlineData(HttpMethodTypes.Post)] - [InlineData(HttpMethodTypes.Put)] - public async Task SendXmlToModelAsync(HttpMethodTypes methodType) - { - FlurlHttp.Configure(c => c.HttpClientFactory = new EchoHttpClientFactory()); - - var method = HttpMethodByType[methodType]; - var result = await new Url("https://some.url") - .SendXmlAsync(method, new TestModel { Number = 3, Text = "Test" }) - .ReceiveXml() - .ConfigureAwait(false); - - AssertTestModel(result, 3, "Test"); - } - - [Theory] - [InlineData(HttpMethodTypes.Post)] - [InlineData(HttpMethodTypes.Put)] - public async Task SendXmlToXDocumentAsync(HttpMethodTypes methodType) - { - FlurlHttp.Configure(c => c.HttpClientFactory = new EchoHttpClientFactory()); - - var method = HttpMethodByType[methodType]; - var result = await new Url("https://some.url") - .SendXmlAsync(method, new TestModel { Number = 3, Text = "Test" }) - .ReceiveXDocument() - .ConfigureAwait(false); - - AssertXDocument(result, 3, "Test"); - } - - [Fact] - public async Task PostXmlToModelAsync() - { - FlurlHttp.Configure(c => c.HttpClientFactory = new EchoHttpClientFactory()); - - var result = await new Url("https://some.url") - .PostXmlAsync(new TestModel { Number = 3, Text = "Test" }) - .ReceiveXml() - .ConfigureAwait(false); - - AssertTestModel(result, 3, "Test"); - } - - [Fact] - public async Task PostXmlToXDocumentAsync() - { - FlurlHttp.Configure(c => c.HttpClientFactory = new EchoHttpClientFactory()); - - var result = await new Url("https://some.url") - .PostXmlAsync(new TestModel { Number = 3, Text = "Test" }) - .ReceiveXDocument() - .ConfigureAwait(false); - - AssertXDocument(result, 3, "Test"); - } - - [Fact] - public async Task PutXmlToModelAsync() - { - FlurlHttp.Configure(c => c.HttpClientFactory = new EchoHttpClientFactory()); - - var result = await new Url("https://some.url") - .PutXmlAsync(new TestModel { Number = 3, Text = "Test" }) - .ReceiveXml() - .ConfigureAwait(false); - - AssertTestModel(result, 3, "Test"); - } - - [Fact] - public async Task PutXmlToXDocumentAsync() - { - FlurlHttp.Configure(c => c.HttpClientFactory = new EchoHttpClientFactory()); - - var result = await new Url("https://some.url") - .PutXmlAsync(new TestModel { Number = 3, Text = "Test" }) - .ReceiveXDocument() - .ConfigureAwait(false); - - AssertXDocument(result, 3, "Test"); - } + using var flurlClient = XmlFlurlClientBuilder.Build(); + + var method = HttpMethodByType[methodType]; + var result = await flurlClient + .Request(new Url("https://some.url")) + .SendXmlAsync(method, new TestModel { Number = 3, Text = "Test" }) + .ReceiveXml(); + + AssertTestModel(result, 3, "Test"); + } + + [Theory] + [InlineData(HttpMethodTypes.Post)] + [InlineData(HttpMethodTypes.Put)] + public async Task SendXmlToXDocumentAsync(HttpMethodTypes methodType) + { + using var flurlClient = XmlFlurlClientBuilder.Build(); + + var method = HttpMethodByType[methodType]; + var result = await flurlClient + .Request(new Url("https://some.url")) + .SendXmlAsync(method, new TestModel { Number = 3, Text = "Test" }) + .ReceiveXDocument(); + + AssertXDocument(result, 3, "Test"); + } + + [Fact] + public async Task PostXmlToModelAsync() + { + using var flurlClient = XmlFlurlClientBuilder.Build(); + + var result = await flurlClient + .Request(new Url("https://some.url")) + .PostXmlAsync(new TestModel { Number = 3, Text = "Test" }) + .ReceiveXml(); + + AssertTestModel(result, 3, "Test"); + } + + [Fact] + public async Task PostXmlToXDocumentAsync() + { + using var flurlClient = XmlFlurlClientBuilder.Build(); + + var result = await flurlClient + .Request(new Url("https://some.url")) + .PostXmlAsync(new TestModel { Number = 3, Text = "Test" }) + .ReceiveXDocument(); + + AssertXDocument(result, 3, "Test"); + } + + [Fact] + public async Task PutXmlToModelAsync() + { + using var flurlClient = XmlFlurlClientBuilder.Build(); + + var result = await flurlClient + .Request(new Url("https://some.url")) + .PutXmlAsync(new TestModel { Number = 3, Text = "Test" }) + .ReceiveXml(); + + AssertTestModel(result, 3, "Test"); + } + + [Fact] + public async Task PutXmlToXDocumentAsync() + { + using var flurlClient = XmlFlurlClientBuilder.Build(); + + var result = await flurlClient + .Request(new Url("https://some.url")) + .PutXmlAsync(new TestModel { Number = 3, Text = "Test" }) + .ReceiveXDocument(); + + AssertXDocument(result, 3, "Test"); } -} +} \ No newline at end of file diff --git a/test/Flurl.Http.Xml.Tests/XmlTestModelHttpMiddleware.cs b/test/Flurl.Http.Xml.Tests/XmlTestModelHttpMiddleware.cs new file mode 100644 index 0000000..beb917b --- /dev/null +++ b/test/Flurl.Http.Xml.Tests/XmlTestModelHttpMiddleware.cs @@ -0,0 +1,27 @@ +using System; +using System.Net.Http; +using System.Threading.Tasks; +using System.Threading; + +namespace Flurl.Http.Xml.Tests; + +public class XmlTestModelHttpMiddleware : DelegatingHandler +{ + protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + if (request == null) + { + throw new ArgumentNullException(nameof(request)); + } + + + return Task.FromResult(new HttpResponseMessage + { + Content = new StringContent(@" + + 3 + Test +") + }); + } +} \ No newline at end of file