From c475daac1598907a5577cc0faa15cdb99b3337c2 Mon Sep 17 00:00:00 2001 From: Alexey Zimarev Date: Tue, 14 Dec 2021 11:10:40 +0100 Subject: [PATCH 01/10] Improving test run --- test/RestSharp.IntegrationTests/AsyncTests.cs | 10 +- .../Authentication/AuthenticationTests.cs | 8 +- .../CompressionTests.cs | 4 + .../Fixtures/RequestBodyFixture.cs | 2 +- .../Fixtures/TestServer.cs | 1 + .../HttpHeadersTests.cs | 4 + .../ResourceStringParametersTests.cs | 4 +- .../RestSharp.IntegrationTests.csproj | 3 + .../xunit.runner.json | 4 + .../Extensions/StreamExtensions.cs | 4 +- .../Fixtures/Handlers.cs | 117 +++++----- .../Fixtures/HttpServerFixture.cs | 36 ++- .../Fixtures/RequestBodyCapturer.cs | 33 ++- .../Fixtures/SimpleServer.cs | 24 +- .../Fixtures/TestHttpServer.cs | 221 ++++++++---------- .../Fixtures/TestHttpServerExtensions.cs | 36 ++- .../Fixtures/TestRequestHandler.cs | 98 ++++---- .../Fixtures/WebServer.cs | 99 +++----- 18 files changed, 324 insertions(+), 384 deletions(-) create mode 100644 test/RestSharp.IntegrationTests/xunit.runner.json diff --git a/test/RestSharp.IntegrationTests/AsyncTests.cs b/test/RestSharp.IntegrationTests/AsyncTests.cs index ae70b03dc..fb5c8c839 100644 --- a/test/RestSharp.IntegrationTests/AsyncTests.cs +++ b/test/RestSharp.IntegrationTests/AsyncTests.cs @@ -6,11 +6,13 @@ namespace RestSharp.IntegrationTests; public class AsyncTests : IAsyncLifetime { - readonly HttpServer _server; + readonly ITestOutputHelper _output; + readonly HttpServer _server; - public AsyncTests(ITestOutputHelper output) => _server = new HttpServer(output); - - static void UrlToStatusCodeHandler(HttpListenerContext obj) => obj.Response.StatusCode = int.Parse(obj.Request.Url.Segments.Last()); + public AsyncTests(ITestOutputHelper output) { + _output = output; + _server = new HttpServer(output); + } class ResponseHandler { void error(HttpListenerContext context) { diff --git a/test/RestSharp.IntegrationTests/Authentication/AuthenticationTests.cs b/test/RestSharp.IntegrationTests/Authentication/AuthenticationTests.cs index aec34f255..40ccfeeed 100644 --- a/test/RestSharp.IntegrationTests/Authentication/AuthenticationTests.cs +++ b/test/RestSharp.IntegrationTests/Authentication/AuthenticationTests.cs @@ -7,10 +7,14 @@ namespace RestSharp.IntegrationTests.Authentication; public class AuthenticationTests { + readonly ITestOutputHelper _output; + + public AuthenticationTests(ITestOutputHelper output) => _output = output; + static void UsernamePasswordEchoHandler(HttpListenerContext context) { - var header = context.Request.Headers["Authorization"]; + var header = context.Request.Headers["Authorization"]!; - var parts = Encoding.ASCII.GetString(Convert.FromBase64String(header.Substring("Basic ".Length))) + var parts = Encoding.ASCII.GetString(Convert.FromBase64String(header["Basic ".Length..])) .Split(':'); context.Response.OutputStream.WriteStringUtf8(string.Join("|", parts)); diff --git a/test/RestSharp.IntegrationTests/CompressionTests.cs b/test/RestSharp.IntegrationTests/CompressionTests.cs index 9bf01af03..8ef9cf1eb 100644 --- a/test/RestSharp.IntegrationTests/CompressionTests.cs +++ b/test/RestSharp.IntegrationTests/CompressionTests.cs @@ -6,6 +6,8 @@ namespace RestSharp.IntegrationTests; public class CompressionTests { + readonly ITestOutputHelper _output; + static Action GzipEchoValue(string value) => context => { context.Response.Headers.Add("Content-encoding", "gzip"); @@ -23,6 +25,8 @@ static Action DeflateEchoValue(string value) gzip.WriteStringUtf8(value); }; + + public CompressionTests(ITestOutputHelper output) => _output = output; [Fact] public async Task Can_Handle_Deflate_Compressed_Content() { diff --git a/test/RestSharp.IntegrationTests/Fixtures/RequestBodyFixture.cs b/test/RestSharp.IntegrationTests/Fixtures/RequestBodyFixture.cs index 60c683e25..82a5d874f 100644 --- a/test/RestSharp.IntegrationTests/Fixtures/RequestBodyFixture.cs +++ b/test/RestSharp.IntegrationTests/Fixtures/RequestBodyFixture.cs @@ -2,7 +2,7 @@ namespace RestSharp.IntegrationTests.Fixtures; -public class RequestBodyFixture : IDisposable { +public sealed class RequestBodyFixture : IDisposable { public SimpleServer Server { get; } public RequestBodyFixture() => Server = SimpleServer.Create(Handlers.Generic()); diff --git a/test/RestSharp.IntegrationTests/Fixtures/TestServer.cs b/test/RestSharp.IntegrationTests/Fixtures/TestServer.cs index 49b834c9a..d3b0a9742 100644 --- a/test/RestSharp.IntegrationTests/Fixtures/TestServer.cs +++ b/test/RestSharp.IntegrationTests/Fixtures/TestServer.cs @@ -21,6 +21,7 @@ public HttpServer(ITestOutputHelper? output = null) { _app.MapGet("success", () => new TestResponse { Message = "Works!" }); _app.MapGet("echo", (string msg) => msg); _app.MapGet("timeout", async () => await Task.Delay(2000)); + // ReSharper disable once ConvertClosureToMethodGroup _app.MapGet("status", (int code) => Results.StatusCode(code)); } diff --git a/test/RestSharp.IntegrationTests/HttpHeadersTests.cs b/test/RestSharp.IntegrationTests/HttpHeadersTests.cs index aa925d9cc..4311ad2e3 100644 --- a/test/RestSharp.IntegrationTests/HttpHeadersTests.cs +++ b/test/RestSharp.IntegrationTests/HttpHeadersTests.cs @@ -4,6 +4,10 @@ namespace RestSharp.IntegrationTests; public class HttpHeadersTests : CaptureFixture { + readonly ITestOutputHelper _output; + + public HttpHeadersTests(ITestOutputHelper output) => _output = output; + [Fact] public async Task Ensure_headers_correctly_set_in_the_hook() { const string headerName = "HeaderName"; diff --git a/test/RestSharp.IntegrationTests/ResourceStringParametersTests.cs b/test/RestSharp.IntegrationTests/ResourceStringParametersTests.cs index 6208e4fca..b75894b45 100644 --- a/test/RestSharp.IntegrationTests/ResourceStringParametersTests.cs +++ b/test/RestSharp.IntegrationTests/ResourceStringParametersTests.cs @@ -3,10 +3,10 @@ namespace RestSharp.IntegrationTests; -public class ResourcestringParametersTests : IDisposable { +public sealed class ResourceStringParametersTests : IDisposable { readonly SimpleServer _server; - public ResourcestringParametersTests() => _server = SimpleServer.Create(RequestHandler.Handle); + public ResourceStringParametersTests() => _server = SimpleServer.Create(RequestHandler.Handle); public void Dispose() => _server.Dispose(); diff --git a/test/RestSharp.IntegrationTests/RestSharp.IntegrationTests.csproj b/test/RestSharp.IntegrationTests/RestSharp.IntegrationTests.csproj index 6193cbc89..ff1cc94b9 100644 --- a/test/RestSharp.IntegrationTests/RestSharp.IntegrationTests.csproj +++ b/test/RestSharp.IntegrationTests/RestSharp.IntegrationTests.csproj @@ -11,4 +11,7 @@ + + + \ No newline at end of file diff --git a/test/RestSharp.IntegrationTests/xunit.runner.json b/test/RestSharp.IntegrationTests/xunit.runner.json new file mode 100644 index 000000000..3ad9c00e1 --- /dev/null +++ b/test/RestSharp.IntegrationTests/xunit.runner.json @@ -0,0 +1,4 @@ +{ + "parallelizeAssembly": false, + "parallelizeTestCollections": false +} \ No newline at end of file diff --git a/test/RestSharp.Tests.Shared/Extensions/StreamExtensions.cs b/test/RestSharp.Tests.Shared/Extensions/StreamExtensions.cs index 33183088b..8adce5aee 100644 --- a/test/RestSharp.Tests.Shared/Extensions/StreamExtensions.cs +++ b/test/RestSharp.Tests.Shared/Extensions/StreamExtensions.cs @@ -1,6 +1,6 @@ using System.Text; -namespace RestSharp.Tests.Shared.Extensions; +namespace RestSharp.Tests.Shared.Extensions; public static class StreamExtensions { public static void WriteStringUtf8(this Stream target, string value) { @@ -14,6 +14,4 @@ public static string StreamToString(this Stream stream) { return streamReader.ReadToEnd(); } - - public static byte[] StreamToBytes(this Stream stream) => Encoding.UTF8.GetBytes(stream.StreamToString()); } \ No newline at end of file diff --git a/test/RestSharp.Tests.Shared/Fixtures/Handlers.cs b/test/RestSharp.Tests.Shared/Fixtures/Handlers.cs index 4a3a10c28..5d6351541 100644 --- a/test/RestSharp.Tests.Shared/Fixtures/Handlers.cs +++ b/test/RestSharp.Tests.Shared/Fixtures/Handlers.cs @@ -1,73 +1,66 @@ -using System; -using System.IO; -using System.Linq; -using System.Net; +using System.Net; using System.Reflection; using RestSharp.Tests.Shared.Extensions; -namespace RestSharp.Tests.Shared.Fixtures -{ - public static class Handlers - { - /// - /// Echoes the request input back to the output. - /// - public static void Echo(HttpListenerContext context) => context.Request.InputStream.CopyTo(context.Response.OutputStream); +namespace RestSharp.Tests.Shared.Fixtures; - /// - /// Echoes the given value back to the output. - /// - public static Action EchoValue(string value) => ctx => ctx.Response.OutputStream.WriteStringUtf8(value); +public static class Handlers { + /// + /// Echoes the request input back to the output. + /// + public static void Echo(HttpListenerContext context) => context.Request.InputStream.CopyTo(context.Response.OutputStream); - /// - /// Response to a request like this: http://localhost:8888/assets/koala.jpg - /// by streaming the file located at "assets\koala.jpg" back to the client. - /// - public static void FileHandler(HttpListenerContext context, string path) - { - var pathToFile = Path.Combine( - path, - Path.Combine( - context.Request.Url.Segments.Select(s => s.Replace("/", "")).ToArray() - ) - ); + /// + /// Echoes the given value back to the output. + /// + public static Action EchoValue(string value) => ctx => ctx.Response.OutputStream.WriteStringUtf8(value); - using var reader = new StreamReader(pathToFile); + /// + /// Response to a request like this: http://localhost:8888/assets/koala.jpg + /// by streaming the file located at "assets\koala.jpg" back to the client. + /// + public static void FileHandler(HttpListenerContext context, string path) { + var pathToFile = Path.Combine( + path, + Path.Combine( + context.Request.Url.Segments.Select(s => s.Replace("/", "")).ToArray() + ) + ); - reader.BaseStream.CopyTo(context.Response.OutputStream); - } + using var reader = new StreamReader(pathToFile); - /// - /// T should be a class that implements methods whose names match the urls being called, and take one parameter, an - /// HttpListenerContext. - /// e.g. - /// urls exercised: "http://localhost:8888/error" and "http://localhost:8888/get_list" - /// class MyHandler - /// { - /// void error(HttpListenerContext ctx) - /// { - /// // do something interesting here - /// } - /// void get_list(HttpListenerContext ctx) - /// { - /// // do something interesting here - /// } - /// } - /// - public static Action Generic() where T : new() - => ctx => - { - var methodName = ctx.Request.Url.Segments.Last(); + reader.BaseStream.CopyTo(context.Response.OutputStream); + } - var method = typeof(T).GetMethod( - methodName, - BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static - ); + /// + /// T should be a class that implements methods whose names match the urls being called, and take one parameter, an + /// HttpListenerContext. + /// e.g. + /// urls exercised: "http://localhost:8888/error" and "http://localhost:8888/get_list" + /// class MyHandler + /// { + /// void error(HttpListenerContext ctx) + /// { + /// // do something interesting here + /// } + /// void get_list(HttpListenerContext ctx) + /// { + /// // do something interesting here + /// } + /// } + /// + public static Action Generic() where T : new() + => ctx => { + var methodName = ctx.Request.Url.Segments.Last(); - if (method.IsStatic) - method.Invoke(null, new object[] {ctx}); - else - method.Invoke(new T(), new object[] {ctx}); - }; - } + var method = typeof(T).GetMethod( + methodName, + BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static + ); + + if (method.IsStatic) + method.Invoke(null, new object[] { ctx }); + else + method.Invoke(new T(), new object[] { ctx }); + }; } \ No newline at end of file diff --git a/test/RestSharp.Tests.Shared/Fixtures/HttpServerFixture.cs b/test/RestSharp.Tests.Shared/Fixtures/HttpServerFixture.cs index 56996400f..d94595845 100644 --- a/test/RestSharp.Tests.Shared/Fixtures/HttpServerFixture.cs +++ b/test/RestSharp.Tests.Shared/Fixtures/HttpServerFixture.cs @@ -1,27 +1,23 @@ -using System; using System.Net; -namespace RestSharp.Tests.Shared.Fixtures -{ - public class HttpServerFixture : IDisposable - { - public static HttpServerFixture StartServer(string url, Action handle) - { - var server = new TestHttpServer(0, url, (request, response, _) => handle(request, response)); - return new HttpServerFixture(server); - } +namespace RestSharp.Tests.Shared.Fixtures; - public static HttpServerFixture StartServer(Action handle) => StartServer("", handle); - - HttpServerFixture(TestHttpServer server) - { - Url = $"http://localhost:{server.Port}"; - _server = server; - } +public sealed class HttpServerFixture : IDisposable { + public static HttpServerFixture StartServer(string url, Action handle) { + var server = new TestHttpServer(0, url, (request, response, _) => handle(request, response)); + return new HttpServerFixture(server); + } - public string Url { get; } + public static HttpServerFixture StartServer(Action handle) => StartServer("", handle); - readonly TestHttpServer _server; - public void Dispose() => _server.Dispose(); + HttpServerFixture(TestHttpServer server) { + Url = $"http://localhost:{server.Port}"; + _server = server; } + + public string Url { get; } + + readonly TestHttpServer _server; + + public void Dispose() => _server.Dispose(); } \ No newline at end of file diff --git a/test/RestSharp.Tests.Shared/Fixtures/RequestBodyCapturer.cs b/test/RestSharp.Tests.Shared/Fixtures/RequestBodyCapturer.cs index 6c47480ac..5a88e799f 100644 --- a/test/RestSharp.Tests.Shared/Fixtures/RequestBodyCapturer.cs +++ b/test/RestSharp.Tests.Shared/Fixtures/RequestBodyCapturer.cs @@ -1,30 +1,25 @@ -using System; -using System.IO; using System.Net; using RestSharp.Tests.Shared.Extensions; -namespace RestSharp.Tests.Shared.Fixtures -{ - public class RequestBodyCapturer - { - public const string Resource = "Capture"; +namespace RestSharp.Tests.Shared.Fixtures; - public static string CapturedContentType { get; set; } +public class RequestBodyCapturer { + public const string Resource = "Capture"; - public static bool CapturedHasEntityBody { get; set; } + public static string? CapturedContentType { get; set; } - public static string CapturedEntityBody { get; set; } + public static bool CapturedHasEntityBody { get; set; } - public static Uri CapturedUrl { get; set; } + public static string? CapturedEntityBody { get; set; } - public static void Capture(HttpListenerContext context) - { - var request = context.Request; + public static Uri? CapturedUrl { get; set; } - CapturedContentType = request.ContentType; - CapturedHasEntityBody = request.HasEntityBody; - CapturedEntityBody = request.InputStream.StreamToString(); - CapturedUrl = request.Url; - } + public static void Capture(HttpListenerContext context) { + var request = context.Request; + + CapturedContentType = request.ContentType; + CapturedHasEntityBody = request.HasEntityBody; + CapturedEntityBody = request.InputStream.StreamToString(); + CapturedUrl = request.Url; } } \ No newline at end of file diff --git a/test/RestSharp.Tests.Shared/Fixtures/SimpleServer.cs b/test/RestSharp.Tests.Shared/Fixtures/SimpleServer.cs index 216533e81..96baf2bfc 100644 --- a/test/RestSharp.Tests.Shared/Fixtures/SimpleServer.cs +++ b/test/RestSharp.Tests.Shared/Fixtures/SimpleServer.cs @@ -1,13 +1,14 @@ using System.Net; -namespace RestSharp.Tests.Shared.Fixtures; +namespace RestSharp.Tests.Shared.Fixtures; -public class SimpleServer : IDisposable { +public sealed class SimpleServer : IDisposable { static readonly Random Random = new(DateTimeOffset.Now.Millisecond); - readonly WebServer _server; + readonly WebServer _server; + readonly CancellationTokenSource _cts = new(); - public string Url { get; } + public string Url { get; } public string ServerUrl { get; } SimpleServer( @@ -15,18 +16,21 @@ public class SimpleServer : IDisposable { Action? handler = null, AuthenticationSchemes authenticationSchemes = AuthenticationSchemes.Anonymous ) { - Url = $"http://localhost:{port}/"; - ; + Url = $"http://localhost:{port}/"; ServerUrl = $"http://{Environment.MachineName}:{port}/"; _server = new WebServer(Url, handler, authenticationSchemes); - _server.Run(); + Task.Run(() => _server.Run(_cts.Token)); } - public void Dispose() => _server.Stop(); + public void Dispose() { + _cts.Cancel(); + _server.Stop(); + _cts.Dispose(); + } public static SimpleServer Create( - Action handler = null, - AuthenticationSchemes authenticationSchemes = AuthenticationSchemes.Anonymous + Action? handler = null, + AuthenticationSchemes authenticationSchemes = AuthenticationSchemes.Anonymous ) { var port = Random.Next(1000, 9999); return new SimpleServer(port, handler, authenticationSchemes); diff --git a/test/RestSharp.Tests.Shared/Fixtures/TestHttpServer.cs b/test/RestSharp.Tests.Shared/Fixtures/TestHttpServer.cs index 5a5cd637c..faf8f9ab2 100644 --- a/test/RestSharp.Tests.Shared/Fixtures/TestHttpServer.cs +++ b/test/RestSharp.Tests.Shared/Fixtures/TestHttpServer.cs @@ -1,142 +1,117 @@ -using System; -using System.Collections.Generic; -using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; -using System.Threading.Tasks; - -namespace RestSharp.Tests.Shared.Fixtures -{ - public class TestHttpServer : IDisposable - { - readonly HttpListener _listener; - readonly List _requestHandlers; - readonly object _requestHandlersLock = new object(); - - public int Port { get; } - - public TestHttpServer( - int port, - string url, - Action> handlerAction, - string hostName = "localhost" - ) - : this(port, new List {new TestRequestHandler(url, handlerAction)}, hostName) { } - - public TestHttpServer( - int port, - List handlers, - string hostName = "localhost" - ) - { - _requestHandlers = handlers; - - Port = port > 0 ? port : GetRandomUnusedPort(); - - //create and start listener - _listener = new HttpListener(); - _listener.Prefixes.Add($"http://{hostName}:{Port}/"); - _listener.Start(); - -// Cannot await Async Call in a Constructor -#pragma warning disable 4014 - HandleRequests(); -#pragma warning restore 4014 - } - static int GetRandomUnusedPort() - { - var listener = new TcpListener(IPAddress.Any, 0); - listener.Start(); - var port = ((IPEndPoint) listener.LocalEndpoint).Port; - listener.Stop(); - return port; - } +namespace RestSharp.Tests.Shared.Fixtures; - async Task HandleRequests() - { - try - { - //listen for all requests - while (_listener.IsListening) - { - //get the request - var context = await _listener.GetContextAsync(); - - try - { - Dictionary parameters = null; - TestRequestHandler handler; - - lock (_requestHandlersLock) - { - handler = _requestHandlers.FirstOrDefault( - h => h.TryMatchUrl(context.Request.RawUrl, context.Request.HttpMethod, out parameters) - ); - } +public class TestHttpServer : IDisposable { + readonly HttpListener _listener; + readonly List _requestHandlers; + readonly object _requestHandlersLock = new(); + readonly CancellationTokenSource _cts = new(); - string responseString = null; - - if (handler != null) - { - //add the query string parameters to the pre-defined url parameters that were set from MatchesUrl() - foreach (var qsParamName in context.Request.QueryString.AllKeys) - parameters[qsParamName] = context.Request.QueryString[qsParamName]; - - try - { - handler.HandlerAction(context.Request, context.Response, parameters); - } - catch (Exception ex) - { - responseString = $"Exception in handler: {ex.Message}"; - context.Response.StatusCode = (int) HttpStatusCode.InternalServerError; - } - } - else - { - context.Response.ContentType("text/plain").StatusCode(404); - responseString = "No handler provided for URL: " + context.Request.RawUrl; - } + public int Port { get; } + + public TestHttpServer( + int port, + string url, + Action> handlerAction, + string hostName = "localhost" + ) + : this(port, new List { new(url, handlerAction) }, hostName) { } + + public TestHttpServer( + int port, + List handlers, + string hostName = "localhost" + ) { + _requestHandlers = handlers; - context.Request.ClearContent(); + Port = port > 0 ? port : GetRandomUnusedPort(); + + //create and start listener + _listener = new HttpListener(); + _listener.Prefixes.Add($"http://{hostName}:{Port}/"); + _listener.Start(); + + Task.Run(() => HandleRequests(_cts.Token)); + } + + static int GetRandomUnusedPort() { + var listener = new TcpListener(IPAddress.Any, 0); + listener.Start(); + var port = ((IPEndPoint)listener.LocalEndpoint).Port; + listener.Stop(); + return port; + } + + async Task HandleRequests(CancellationToken cancellationToken) { + try { + //listen for all requests + while (_listener.IsListening && !cancellationToken.IsCancellationRequested) { + //get the request + var context = await _listener.GetContextAsync(); + + try { + Dictionary? parameters = null; + TestRequestHandler handler; + + lock (_requestHandlersLock) { + handler = _requestHandlers.FirstOrDefault( + h => h.TryMatchUrl(context.Request.RawUrl, context.Request.HttpMethod, out parameters) + ); + } - //send the response, if there is not (if responseString is null, then the handler method should have manually set the output stream) - if (responseString != null) - { - var buffer = Encoding.UTF8.GetBytes(responseString); - context.Response.ContentLength64 += buffer.Length; - context.Response.OutputStream.Write(buffer, 0, buffer.Length); + string? responseString = null; + + if (handler != null) { + //add the query string parameters to the pre-defined url parameters that were set from MatchesUrl() + foreach (var qsParamName in context.Request.QueryString.AllKeys) + parameters[qsParamName] = context.Request.QueryString[qsParamName]; + + try { + handler.HandlerAction(context.Request, context.Response, parameters); + } + catch (Exception ex) { + responseString = $"Exception in handler: {ex.Message}"; + context.Response.StatusCode = (int)HttpStatusCode.InternalServerError; } } - finally - { - context.Response.OutputStream.Close(); - context.Response.Close(); + else { + context.Response.ContentType("text/plain").StatusCode(404); + responseString = "No handler provided for URL: " + context.Request.RawUrl; + } + + context.Request.ClearContent(); + + //send the response, if there is not (if responseString is null, then the handler method should have manually set the output stream) + if (responseString != null) { + var buffer = Encoding.UTF8.GetBytes(responseString); + context.Response.ContentLength64 += buffer.Length; + context.Response.OutputStream.Write(buffer, 0, buffer.Length); } } - } - catch (HttpListenerException ex) - { - //when the listener is stopped, it will throw an exception for being cancelled, so just ignore it - if (ex.Message != "The I/O operation has been aborted because of either a thread exit or an application request") - throw; + finally { + context.Response.OutputStream.Close(); + context.Response.Close(); + } } } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); + catch (HttpListenerException ex) { + //when the listener is stopped, it will throw an exception for being cancelled, so just ignore it + if (ex.Message != "The I/O operation has been aborted because of either a thread exit or an application request") + throw; } + } - protected virtual void Dispose(bool disposing) - { - if (disposing && (_listener?.IsListening ?? false)) - { - _listener.Stop(); - } + public void Dispose() { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) { + if (disposing && _listener.IsListening) { + _listener.Stop(); } } } \ No newline at end of file diff --git a/test/RestSharp.Tests.Shared/Fixtures/TestHttpServerExtensions.cs b/test/RestSharp.Tests.Shared/Fixtures/TestHttpServerExtensions.cs index 65058ccf8..53d05abf1 100644 --- a/test/RestSharp.Tests.Shared/Fixtures/TestHttpServerExtensions.cs +++ b/test/RestSharp.Tests.Shared/Fixtures/TestHttpServerExtensions.cs @@ -1,28 +1,22 @@ -using System.Collections.Generic; using System.Net; -namespace RestSharp.Tests.Shared.Fixtures -{ - public static class TestHttpServerExtensions - { - static readonly Dictionary RequestContent = new Dictionary(); +namespace RestSharp.Tests.Shared.Fixtures; - internal static void ClearContent(this HttpListenerRequest request) - { - if (RequestContent.ContainsKey(request)) - RequestContent.Remove(request); - } +public static class TestHttpServerExtensions { + static readonly Dictionary RequestContent = new(); - public static HttpListenerResponse ContentType(this HttpListenerResponse response, string contentType) - { - response.ContentType = contentType; - return response; - } + internal static void ClearContent(this HttpListenerRequest request) { + if (RequestContent.ContainsKey(request)) + RequestContent.Remove(request); + } + + public static HttpListenerResponse ContentType(this HttpListenerResponse response, string contentType) { + response.ContentType = contentType; + return response; + } - public static HttpListenerResponse StatusCode(this HttpListenerResponse response, int statusCode) - { - response.StatusCode = statusCode; - return response; - } + public static HttpListenerResponse StatusCode(this HttpListenerResponse response, int statusCode) { + response.StatusCode = statusCode; + return response; } } \ No newline at end of file diff --git a/test/RestSharp.Tests.Shared/Fixtures/TestRequestHandler.cs b/test/RestSharp.Tests.Shared/Fixtures/TestRequestHandler.cs index e1640b20f..850a33867 100644 --- a/test/RestSharp.Tests.Shared/Fixtures/TestRequestHandler.cs +++ b/test/RestSharp.Tests.Shared/Fixtures/TestRequestHandler.cs @@ -1,74 +1,64 @@ -using System; -using System.Collections.Generic; -using System.Linq; using System.Net; using System.Text.RegularExpressions; -namespace RestSharp.Tests.Shared.Fixtures -{ - public class TestRequestHandler - { - readonly Regex _comparisonRegex; - - readonly List _urlParameterNames = new List(); - - public TestRequestHandler( - string url, - string httpMethod, - Action> handlerAction - ) - { - Url = url; - HttpMethod = httpMethod; - HandlerAction = handlerAction; - - _comparisonRegex = CreateComparisonRegex(url); - } +namespace RestSharp.Tests.Shared.Fixtures; + +public class TestRequestHandler { + readonly Regex _comparisonRegex; - public TestRequestHandler(string url, Action> handlerAction) - : this(url, null, handlerAction) { } + readonly List _urlParameterNames = new(); - string Url { get; } - string HttpMethod { get; } - internal Action> HandlerAction { get; } + public TestRequestHandler( + string url, + string httpMethod, + Action> handlerAction + ) { + Url = url; + HttpMethod = httpMethod; + HandlerAction = handlerAction; + + _comparisonRegex = CreateComparisonRegex(url); + } - Regex CreateComparisonRegex(string url) - { - var regexString = Regex.Escape(url).Replace(@"\{", "{"); + public TestRequestHandler(string url, Action> handlerAction) + : this(url, null, handlerAction) { } - regexString += regexString.EndsWith("/") ? "?" : "/?"; - regexString = (regexString.StartsWith("/") ? "^" : "^/") + regexString; + string Url { get; } + string? HttpMethod { get; } + internal Action> HandlerAction { get; } - var regex = new Regex(@"{(.*?)}"); + Regex CreateComparisonRegex(string url) { + var regexString = Regex.Escape(url).Replace(@"\{", "{"); - foreach (Match match in regex.Matches(regexString)) - { - regexString = regexString.Replace(match.Value, @"(.*?)"); - _urlParameterNames.Add(match.Groups[1].Value); - } + regexString += regexString.EndsWith("/") ? "?" : "/?"; + regexString = (regexString.StartsWith("/") ? "^" : "^/") + regexString; - regexString += !regexString.Contains(@"\?") ? @"(\?.*)?$" : "$"; + var regex = new Regex(@"{(.*?)}"); - return new Regex(regexString); + foreach (Match match in regex.Matches(regexString)) { + regexString = regexString.Replace(match.Value, @"(.*?)"); + _urlParameterNames.Add(match.Groups[1].Value); } - public bool TryMatchUrl(string rawUrl, string httpMethod, out Dictionary parameters) - { - var match = _comparisonRegex.Match(rawUrl); + regexString += !regexString.Contains(@"\?") ? @"(\?.*)?$" : "$"; - var isMethodMatched = HttpMethod == null || HttpMethod.Split(',').Contains(httpMethod); + return new Regex(regexString); + } - if (!match.Success || !isMethodMatched) - { - parameters = null; - return false; - } + public bool TryMatchUrl(string rawUrl, string httpMethod, out Dictionary? parameters) { + var match = _comparisonRegex.Match(rawUrl); - parameters = new Dictionary(); + var isMethodMatched = HttpMethod == null || HttpMethod.Split(',').Contains(httpMethod); - for (var i = 0; i < _urlParameterNames.Count; i++) - parameters[_urlParameterNames[i]] = match.Groups[i + 1].Value; - return true; + if (!match.Success || !isMethodMatched) { + parameters = null; + return false; } + + parameters = new Dictionary(); + + for (var i = 0; i < _urlParameterNames.Count; i++) + parameters[_urlParameterNames[i]] = match.Groups[i + 1].Value; + return true; } } \ No newline at end of file diff --git a/test/RestSharp.Tests.Shared/Fixtures/WebServer.cs b/test/RestSharp.Tests.Shared/Fixtures/WebServer.cs index 7dc773d34..277466a03 100644 --- a/test/RestSharp.Tests.Shared/Fixtures/WebServer.cs +++ b/test/RestSharp.Tests.Shared/Fixtures/WebServer.cs @@ -1,74 +1,47 @@ -using System; -using System.Net; -using System.Threading; +using System.Net; -namespace RestSharp.Tests.Shared.Fixtures -{ - public class WebServer - { - readonly HttpListener _listener = new HttpListener(); - CancellationTokenSource _cts; - Action _responderMethod; +namespace RestSharp.Tests.Shared.Fixtures; - public WebServer(string prefix, Action method, AuthenticationSchemes authenticationSchemes) - { - if (string.IsNullOrEmpty(prefix)) - throw new ArgumentException("URI prefix is required"); +public class WebServer { + readonly HttpListener _listener = new(); + Action? _responderMethod; - _listener.Prefixes.Add(prefix); - _listener.AuthenticationSchemes = authenticationSchemes; + public WebServer(string prefix, Action? method, AuthenticationSchemes authenticationSchemes) { + if (string.IsNullOrEmpty(prefix)) + throw new ArgumentException("URI prefix is required"); - _responderMethod = method; - _listener.Start(); - } - - public void Run() - { - _cts = new CancellationTokenSource(); + _listener.Prefixes.Add(prefix); + _listener.AuthenticationSchemes = authenticationSchemes; - ThreadPool.QueueUserWorkItem( - o => - { - var token = (CancellationToken) o; - - try - { - while (!token.IsCancellationRequested && _listener.IsListening) - { - ThreadPool.QueueUserWorkItem( - c => - { - try - { - if (!(c is HttpListenerContext ctx)) return; + _responderMethod = method; + } - _responderMethod?.Invoke(ctx); - ctx.Response.OutputStream?.Close(); - } - catch (Exception e) - { - Console.WriteLine(e); - } - }, _listener.IsListening ? _listener.GetContext() : null - ); - } - } - catch (Exception e) - { - Console.WriteLine(e); - } - }, _cts.Token - ); + public async Task Run(CancellationToken token) { + _listener.Start(); + try { + while (!token.IsCancellationRequested && _listener.IsListening) { + try { + var ctx = await _listener.GetContextAsync(); + // ReSharper disable once ConditionIsAlwaysTrueOrFalse + if (ctx == null) continue; + + _responderMethod?.Invoke(ctx); + ctx.Response.OutputStream.Close(); + } + catch (Exception e) { + Console.WriteLine(e.ToString()); + } + } } - - public void Stop() - { - _cts.Cancel(); - _listener.Stop(); - _listener.Close(); - _cts.Dispose(); + catch (Exception e) { + Console.WriteLine(e.ToString()); } + } - public void ChangeHandler(Action handler) => _responderMethod = handler; + public void Stop() { + _listener.Stop(); + _listener.Close(); } + + public void ChangeHandler(Action handler) => _responderMethod = handler; } \ No newline at end of file From 0b33d75b196d00ef10e9e66ff15ce822b2e449eb Mon Sep 17 00:00:00 2001 From: Alexey Zimarev Date: Tue, 14 Dec 2021 11:29:03 +0100 Subject: [PATCH 02/10] Use custom TaskFactory --- .../NonProtocolExceptionHandlingTests.cs | 2 +- test/RestSharp.Tests.Shared/Fixtures/WebServer.cs | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/test/RestSharp.IntegrationTests/NonProtocolExceptionHandlingTests.cs b/test/RestSharp.IntegrationTests/NonProtocolExceptionHandlingTests.cs index 05adb8e58..5c37dd06c 100644 --- a/test/RestSharp.IntegrationTests/NonProtocolExceptionHandlingTests.cs +++ b/test/RestSharp.IntegrationTests/NonProtocolExceptionHandlingTests.cs @@ -80,7 +80,7 @@ public async Task Task_Handles_Non_Existent_Domain() { var response = await client.ExecuteAsync(request); response.ErrorException.Should().BeOfType(); - response.ErrorException!.Message.Should().Contain("nodename nor servname provided, or not known"); + response.ErrorException!.Message.Should().Contain("known"); response.ResponseStatus.Should().Be(ResponseStatus.Error); } } \ No newline at end of file diff --git a/test/RestSharp.Tests.Shared/Fixtures/WebServer.cs b/test/RestSharp.Tests.Shared/Fixtures/WebServer.cs index 277466a03..5578db88c 100644 --- a/test/RestSharp.Tests.Shared/Fixtures/WebServer.cs +++ b/test/RestSharp.Tests.Shared/Fixtures/WebServer.cs @@ -17,17 +17,21 @@ public WebServer(string prefix, Action? method, Authenticat } public async Task Run(CancellationToken token) { + var taskFactory = new TaskFactory(token); _listener.Start(); try { while (!token.IsCancellationRequested && _listener.IsListening) { try { - var ctx = await _listener.GetContextAsync(); + var ctx = await GetContextAsync(); // ReSharper disable once ConditionIsAlwaysTrueOrFalse if (ctx == null) continue; _responderMethod?.Invoke(ctx); ctx.Response.OutputStream.Close(); } + // catch (HttpListenerException) { + // // it's ok + // } catch (Exception e) { Console.WriteLine(e.ToString()); } @@ -36,6 +40,11 @@ public async Task Run(CancellationToken token) { catch (Exception e) { Console.WriteLine(e.ToString()); } + + Task GetContextAsync() => taskFactory.FromAsync( + (callback, state) => ((HttpListener)state!).BeginGetContext(callback, state), + iar => ((HttpListener)iar.AsyncState!).EndGetContext(iar), + _listener); } public void Stop() { From 1fc68217016fb2f6abd081aa558494b7b6a645c0 Mon Sep 17 00:00:00 2001 From: Alexey Zimarev Date: Tue, 14 Dec 2021 12:26:02 +0100 Subject: [PATCH 03/10] Fixing warnings --- ...estSharp.Serializers.NewtonsoftJson.csproj | 2 +- .../OAuth/OAuth1Authenticator.cs | 103 +++++------------- .../Authenticators/OAuth/OAuthWorkflow.cs | 92 +++++++--------- src/RestSharp/Authenticators/OAuth/WebPair.cs | 8 +- .../Extensions/ReflectionExtensions.cs | 4 +- .../Extensions/StringEncodingExtensions.cs | 30 ----- src/RestSharp/Extensions/StringExtensions.cs | 9 +- src/RestSharp/Parameters/Parameter.cs | 2 +- .../Request/HttpContentExtensions.cs | 6 +- .../Request/HttpRequestMessageExtensions.cs | 4 +- src/RestSharp/Request/RequestContent.cs | 24 ++-- .../Request/RestRequestExtensions.cs | 2 +- src/RestSharp/Response/RestResponseBase.cs | 10 +- src/RestSharp/RestClient.cs | 14 +-- src/RestSharp/RestClientOptions.cs | 2 +- .../Serializers/DeserializeAsAttribute.cs | 2 +- .../Json/SystemTextJsonSerializer.cs | 2 +- .../Serializers/Xml/DotNetXmlDeserializer.cs | 10 +- .../Serializers/Xml/DotNetXmlSerializer.cs | 4 +- .../Serializers/Xml/IXmlDeserializer.cs | 4 +- .../Serializers/Xml/IXmlSerializer.cs | 4 +- .../Xml/XmlAttributeDeserializer.cs | 4 +- .../Serializers/Xml/XmlDeserializer.cs | 67 ++++++------ .../Serializers/Xml/XmlExtensions.cs | 6 +- .../Serializers/Xml/XmlRestSerializer.cs | 49 +++++---- .../Serializers/Xml/XmlSerializer.cs | 20 ++-- test/Directory.Build.props | 1 + .../Fixtures/RequestBodyCapturer.cs | 13 +-- .../Fixtures/SimpleServer.cs | 10 +- .../Fixtures/TestHttpServer.cs | 6 +- .../Fixtures/TestRequestHandler.cs | 6 +- .../Fixtures/WebServer.cs | 22 ++-- .../OAuth1AuthenticatorTests.cs | 23 ++-- test/RestSharp.Tests/OAuthTests.cs | 2 +- test/RestSharp.Tests/StringExtensionsTests.cs | 24 +--- 35 files changed, 243 insertions(+), 348 deletions(-) delete mode 100644 src/RestSharp/Extensions/StringEncodingExtensions.cs diff --git a/src/RestSharp.Serializers.NewtonsoftJson/RestSharp.Serializers.NewtonsoftJson.csproj b/src/RestSharp.Serializers.NewtonsoftJson/RestSharp.Serializers.NewtonsoftJson.csproj index 2e19faf9d..c0714836d 100644 --- a/src/RestSharp.Serializers.NewtonsoftJson/RestSharp.Serializers.NewtonsoftJson.csproj +++ b/src/RestSharp.Serializers.NewtonsoftJson/RestSharp.Serializers.NewtonsoftJson.csproj @@ -1,6 +1,6 @@ - + diff --git a/src/RestSharp/Authenticators/OAuth/OAuth1Authenticator.cs b/src/RestSharp/Authenticators/OAuth/OAuth1Authenticator.cs index 921111c2a..09eb301bb 100644 --- a/src/RestSharp/Authenticators/OAuth/OAuth1Authenticator.cs +++ b/src/RestSharp/Authenticators/OAuth/OAuth1Authenticator.cs @@ -4,46 +4,31 @@ // ReSharper disable CheckNamespace -namespace RestSharp.Authenticators; +namespace RestSharp.Authenticators; /// RFC: The OAuth 1.0 Protocol -[PublicAPI] public class OAuth1Authenticator : IAuthenticator { - public virtual string Realm { get; set; } - - public virtual OAuthParameterHandling ParameterHandling { get; set; } - - public virtual OAuthSignatureMethod SignatureMethod { get; set; } - + public virtual string? Realm { get; set; } + public virtual OAuthParameterHandling ParameterHandling { get; set; } + public virtual OAuthSignatureMethod SignatureMethod { get; set; } public virtual OAuthSignatureTreatment SignatureTreatment { get; set; } - - internal virtual OAuthType Type { get; set; } - - internal virtual string ConsumerKey { get; set; } - - internal virtual string? ConsumerSecret { get; set; } - - internal virtual string Token { get; set; } - - internal virtual string TokenSecret { get; set; } - - internal virtual string Verifier { get; set; } - - internal virtual string Version { get; set; } - - internal virtual string CallbackUrl { get; set; } - - internal virtual string SessionHandle { get; set; } - - internal virtual string ClientUsername { get; set; } - - internal virtual string ClientPassword { get; set; } + public virtual OAuthType Type { get; set; } + public virtual string? ConsumerKey { get; set; } + public virtual string? ConsumerSecret { get; set; } + public virtual string? Token { get; set; } + public virtual string? TokenSecret { get; set; } + public virtual string? Verifier { get; set; } + public virtual string? Version { get; set; } + public virtual string? CallbackUrl { get; set; } + public virtual string? SessionHandle { get; set; } + public virtual string? ClientUsername { get; set; } + public virtual string? ClientPassword { get; set; } public ValueTask Authenticate(RestClient client, RestRequest request) { var workflow = new OAuthWorkflow { - ConsumerKey = ConsumerKey, - ConsumerSecret = ConsumerSecret, - ParameterHandling = ParameterHandling, + ConsumerKey = ConsumerKey, + ConsumerSecret = ConsumerSecret, + // ParameterHandling = ParameterHandling, SignatureMethod = SignatureMethod, SignatureTreatment = SignatureTreatment, Verifier = Verifier, @@ -60,6 +45,7 @@ public ValueTask Authenticate(RestClient client, RestRequest request) { return default; } + [PublicAPI] public static OAuth1Authenticator ForRequestToken( string consumerKey, string? consumerSecret, @@ -77,6 +63,7 @@ public static OAuth1Authenticator ForRequestToken( return authenticator; } + [PublicAPI] public static OAuth1Authenticator ForRequestToken(string consumerKey, string? consumerSecret, string callbackUrl) { var authenticator = ForRequestToken(consumerKey, consumerSecret); @@ -85,6 +72,7 @@ public static OAuth1Authenticator ForRequestToken(string consumerKey, string? co return authenticator; } + [PublicAPI] public static OAuth1Authenticator ForAccessToken( string consumerKey, string? consumerSecret, @@ -103,6 +91,7 @@ public static OAuth1Authenticator ForAccessToken( Type = OAuthType.AccessToken }; + [PublicAPI] public static OAuth1Authenticator ForAccessToken( string consumerKey, string? consumerSecret, @@ -117,15 +106,7 @@ string verifier return authenticator; } - /// - /// - /// - /// - /// - /// - /// - /// - /// + [PublicAPI] public static OAuth1Authenticator ForAccessTokenRefresh( string consumerKey, string? consumerSecret, @@ -140,16 +121,7 @@ string sessionHandle return authenticator; } - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// + [PublicAPI] public static OAuth1Authenticator ForAccessTokenRefresh( string consumerKey, string? consumerSecret, @@ -166,15 +138,7 @@ string sessionHandle return authenticator; } - /// - /// - /// - /// - /// - /// - /// - /// - /// + [PublicAPI] public static OAuth1Authenticator ForClientAuthentication( string consumerKey, string? consumerSecret, @@ -193,15 +157,7 @@ public static OAuth1Authenticator ForClientAuthentication( Type = OAuthType.ClientAuthentication }; - /// - /// - /// - /// - /// - /// - /// - /// - /// + [PublicAPI] public static OAuth1Authenticator ForProtectedResource( string consumerKey, string? consumerSecret, @@ -247,7 +203,7 @@ void AddOAuthData(RestClient client, RestRequest request, OAuthWorkflow workflow var query = request.AlwaysMultipartFormData || request.Files.Count > 0 - ? x => BaseQuery(x) && x.Name.StartsWith("oauth_") + ? x => BaseQuery(x) && x.Name != null && x.Name.StartsWith("oauth_") : (Func)BaseQuery; parameters.AddRange(client.DefaultParameters.Where(query).ToWebParameters()); @@ -291,7 +247,7 @@ string GetAuthorizationHeader() { .ToList(); if (!Realm.IsEmpty()) - oathParameters.Insert(0, $"realm=\"{OAuthTools.UrlEncodeRelaxed(Realm)}\""); + oathParameters.Insert(0, $"realm=\"{OAuthTools.UrlEncodeRelaxed(Realm!)}\""); return "OAuth " + string.Join(",", oathParameters); } @@ -299,5 +255,6 @@ string GetAuthorizationHeader() { } static class ParametersExtensions { - internal static IEnumerable ToWebParameters(this IEnumerable p) => p.Select(x => new WebPair(x.Name, x.Value.ToString())); + internal static IEnumerable ToWebParameters(this IEnumerable p) + => p.Select(x => new WebPair(Ensure.NotNull(x.Name, "Parameter name"), Ensure.NotNull(x.Value, "Parameter value").ToString()!)); } \ No newline at end of file diff --git a/src/RestSharp/Authenticators/OAuth/OAuthWorkflow.cs b/src/RestSharp/Authenticators/OAuth/OAuthWorkflow.cs index e4d60f857..420709c4d 100644 --- a/src/RestSharp/Authenticators/OAuth/OAuthWorkflow.cs +++ b/src/RestSharp/Authenticators/OAuth/OAuthWorkflow.cs @@ -2,41 +2,27 @@ using RestSharp.Authenticators.OAuth.Extensions; using RestSharp.Extensions; -namespace RestSharp.Authenticators.OAuth; +namespace RestSharp.Authenticators.OAuth; /// /// A class to encapsulate OAuth authentication flow. /// sealed class OAuthWorkflow { - public string Version { get; set; } - - public string ConsumerKey { get; set; } - - public string? ConsumerSecret { get; set; } - - public string Token { get; set; } - - public string TokenSecret { get; set; } - - public string CallbackUrl { get; set; } - - public string Verifier { get; set; } - - public string SessionHandle { get; set; } - - public OAuthSignatureMethod SignatureMethod { get; set; } - + public string? Version { get; set; } + public string? ConsumerKey { get; set; } + public string? ConsumerSecret { get; set; } + public string? Token { get; set; } + public string? TokenSecret { get; set; } + public string? CallbackUrl { get; set; } + public string? Verifier { get; set; } + public string? SessionHandle { get; set; } + public OAuthSignatureMethod SignatureMethod { get; set; } public OAuthSignatureTreatment SignatureTreatment { get; set; } - - public OAuthParameterHandling ParameterHandling { get; set; } - - public string ClientUsername { get; set; } - - public string ClientPassword { get; set; } - - public string RequestTokenUrl { get; set; } - - public string AccessTokenUrl { get; set; } + // public OAuthParameterHandling ParameterHandling { get; set; } + public string? ClientUsername { get; set; } + public string? ClientPassword { get; set; } + public string? RequestTokenUrl { get; set; } + public string? AccessTokenUrl { get; set; } /// /// Generates an OAuth signature to pass to an @@ -58,7 +44,7 @@ public OAuthParameters BuildRequestTokenInfo(string method, WebPairCollection pa var authParameters = GenerateAuthParameters(timestamp, nonce); allParameters.AddRange(authParameters); - var signatureBase = OAuthTools.ConcatenateRequestElements(method, RequestTokenUrl, allParameters); + var signatureBase = OAuthTools.ConcatenateRequestElements(method, Ensure.NotNull(RequestTokenUrl, nameof(RequestTokenUrl)), allParameters); return new OAuthParameters { Signature = OAuthTools.GetSignature(SignatureMethod, SignatureTreatment, signatureBase, ConsumerSecret), @@ -79,7 +65,7 @@ public OAuthParameters BuildAccessTokenSignature(string method, WebPairCollectio var allParameters = new WebPairCollection(); allParameters.AddRange(parameters); - var uri = new Uri(AccessTokenUrl); + var uri = new Uri(Ensure.NotEmptyString(AccessTokenUrl, nameof(AccessTokenUrl))); var timestamp = OAuthTools.GetTimestamp(); var nonce = OAuthTools.GetNonce(); @@ -107,7 +93,7 @@ public OAuthParameters BuildClientAuthAccessTokenSignature(string method, WebPai var allParameters = new WebPairCollection(); allParameters.AddRange(parameters); - var uri = new Uri(AccessTokenUrl); + var uri = new Uri(Ensure.NotNull(AccessTokenUrl, nameof(AccessTokenUrl))); var timestamp = OAuthTools.GetTimestamp(); var nonce = OAuthTools.GetNonce(); @@ -132,7 +118,7 @@ public OAuthParameters BuildProtectedResourceSignature(string method, WebPairCol var uri = new Uri(url); var urlParameters = HttpUtility.ParseQueryString(uri.Query); - allParameters.AddRange(urlParameters.AllKeys.Select(x => new WebPair(x, urlParameters[x]))); + allParameters.AddRange(urlParameters.AllKeys.Select(x => new WebPair(x!, urlParameters[x]!))); var timestamp = OAuthTools.GetTimestamp(); var nonce = OAuthTools.GetNonce(); @@ -171,38 +157,38 @@ void ValidateProtectedResourceState() { WebPairCollection GenerateAuthParameters(string timestamp, string nonce) { var authParameters = new WebPairCollection { - new WebPair("oauth_consumer_key", ConsumerKey), - new WebPair("oauth_nonce", nonce), - new WebPair("oauth_signature_method", SignatureMethod.ToRequestValue()), - new WebPair("oauth_timestamp", timestamp), - new WebPair("oauth_version", Version ?? "1.0") + new("oauth_consumer_key", Ensure.NotNull(ConsumerKey, nameof(ConsumerKey))), + new("oauth_nonce", nonce), + new("oauth_signature_method", SignatureMethod.ToRequestValue()), + new("oauth_timestamp", timestamp), + new("oauth_version", Version ?? "1.0") }; - if (!Token.IsEmpty()) authParameters.Add(new WebPair("oauth_token", Token, true)); + if (!Token.IsEmpty()) authParameters.Add(new WebPair("oauth_token", Token!, true)); - if (!CallbackUrl.IsEmpty()) authParameters.Add(new WebPair("oauth_callback", CallbackUrl, true)); + if (!CallbackUrl.IsEmpty()) authParameters.Add(new WebPair("oauth_callback", CallbackUrl!, true)); - if (!Verifier.IsEmpty()) authParameters.Add(new WebPair("oauth_verifier", Verifier)); + if (!Verifier.IsEmpty()) authParameters.Add(new WebPair("oauth_verifier", Verifier!)); - if (!SessionHandle.IsEmpty()) authParameters.Add(new WebPair("oauth_session_handle", SessionHandle)); + if (!SessionHandle.IsEmpty()) authParameters.Add(new WebPair("oauth_session_handle", SessionHandle!)); return authParameters; } WebPairCollection GenerateXAuthParameters(string timestamp, string nonce) - => new WebPairCollection { - new WebPair("x_auth_username", ClientUsername), - new WebPair("x_auth_password", ClientPassword), - new WebPair("x_auth_mode", "client_auth"), - new WebPair("oauth_consumer_key", ConsumerKey), - new WebPair("oauth_signature_method", SignatureMethod.ToRequestValue()), - new WebPair("oauth_timestamp", timestamp), - new WebPair("oauth_nonce", nonce), - new WebPair("oauth_version", Version ?? "1.0") + => new() { + new("x_auth_username", Ensure.NotNull(ClientUsername, nameof(ClientUsername))), + new("x_auth_password", Ensure.NotNull(ClientPassword, nameof(ClientPassword))), + new("x_auth_mode", "client_auth"), + new("oauth_consumer_key", Ensure.NotNull(ConsumerKey, nameof(ConsumerKey))), + new("oauth_signature_method", SignatureMethod.ToRequestValue()), + new("oauth_timestamp", timestamp), + new("oauth_nonce", nonce), + new("oauth_version", Version ?? "1.0") }; internal class OAuthParameters { - public WebPairCollection Parameters { get; set; } - public string Signature { get; set; } + public WebPairCollection Parameters { get; init; } = null!; + public string Signature { get; init; } = null!; } } \ No newline at end of file diff --git a/src/RestSharp/Authenticators/OAuth/WebPair.cs b/src/RestSharp/Authenticators/OAuth/WebPair.cs index ffa856b8d..a71155860 100644 --- a/src/RestSharp/Authenticators/OAuth/WebPair.cs +++ b/src/RestSharp/Authenticators/OAuth/WebPair.cs @@ -14,7 +14,7 @@ using System.Collections.Generic; -namespace RestSharp.Authenticators.OAuth; +namespace RestSharp.Authenticators.OAuth; class WebPair { public WebPair(string name, string value, bool encode = false) { @@ -32,10 +32,10 @@ public WebPair(string name, string value, bool encode = false) { internal static WebPairComparer Comparer { get; } = new(); internal class WebPairComparer : IComparer { - public int Compare(WebPair x, WebPair y) { - var compareName = string.CompareOrdinal(x.Name, y.Name); + public int Compare(WebPair? x, WebPair? y) { + var compareName = string.CompareOrdinal(x?.Name, y?.Name); - return compareName != 0 ? compareName : string.CompareOrdinal(x.Value, y.Value); + return compareName != 0 ? compareName : string.CompareOrdinal(x?.Value, y?.Value); } } } \ No newline at end of file diff --git a/src/RestSharp/Extensions/ReflectionExtensions.cs b/src/RestSharp/Extensions/ReflectionExtensions.cs index 671b17cba..6d71f898c 100644 --- a/src/RestSharp/Extensions/ReflectionExtensions.cs +++ b/src/RestSharp/Extensions/ReflectionExtensions.cs @@ -29,7 +29,7 @@ public static class ReflectionExtensions { /// /// /// - public static bool IsSubclassOfRawGeneric(this Type toCheck, Type generic) { + public static bool IsSubclassOfRawGeneric(this Type? toCheck, Type generic) { while (toCheck != null && toCheck != typeof(object)) { var cur = toCheck.GetTypeInfo().IsGenericType ? toCheck.GetGenericTypeDefinition() @@ -70,7 +70,7 @@ public static bool IsSubclassOfRawGeneric(this Type toCheck, Type generic) { var enumValueAsUnderlyingType = Convert.ChangeType(value, Enum.GetUnderlyingType(type), culture); - if (enumValueAsUnderlyingType != null && Enum.IsDefined(type, enumValueAsUnderlyingType)) + if (Enum.IsDefined(type, enumValueAsUnderlyingType)) ret = (Enum)Enum.ToObject(type, enumValueAsUnderlyingType); return ret ?? Activator.CreateInstance(type); diff --git a/src/RestSharp/Extensions/StringEncodingExtensions.cs b/src/RestSharp/Extensions/StringEncodingExtensions.cs deleted file mode 100644 index 1630cd284..000000000 --- a/src/RestSharp/Extensions/StringEncodingExtensions.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Text; - -namespace RestSharp.Extensions; - -public static class StringEncodingExtensions { - /// - /// Converts a byte array to a string, using its byte order mark to convert it to the right encoding. - /// http://www.shrinkrays.net/code-snippets/csharp/an-extension-method-for-converting-a-byte-array-to-a-string.aspx - /// - /// An array of bytes to convert - /// Content encoding. Will fallback to UTF8 if not a valid encoding. - /// The byte as a string. - [Obsolete("This method will be removed soon. If you use it, please copy the code to your project.")] - public static string AsString(this byte[] buffer, string? encoding) { - var enc = encoding.IsEmpty() ? Encoding.UTF8 : TryParseEncoding(); - - return AsString(buffer, enc); - - Encoding TryParseEncoding() { - try { - return encoding != null ? Encoding.GetEncoding(encoding) : Encoding.UTF8; - } - catch (ArgumentException) { - return Encoding.UTF8; - } - } - } - - static string AsString(byte[]? buffer, Encoding encoding) => buffer == null ? "" : encoding.GetString(buffer, 0, buffer.Length); -} \ No newline at end of file diff --git a/src/RestSharp/Extensions/StringExtensions.cs b/src/RestSharp/Extensions/StringExtensions.cs index ce35cdff1..8eec2a512 100644 --- a/src/RestSharp/Extensions/StringExtensions.cs +++ b/src/RestSharp/Extensions/StringExtensions.cs @@ -5,7 +5,7 @@ namespace RestSharp.Extensions; -public static class StringExtensions { +static class StringExtensions { static readonly Regex IsUpperCaseRegex = new(@"^[A-Z]+$"); static readonly Regex AddUnderscoresRegex1 = new(@"[-\s]"); @@ -58,13 +58,6 @@ public static string UrlEncode(this string input) { return encoded?.Replace("+", "%20"); } - /// - /// Check that a string is not null or empty - /// - /// String to check - /// bool - public static bool HasValue(this string input) => !string.IsNullOrEmpty(input); - /// /// Remove underscores from a string /// diff --git a/src/RestSharp/Parameters/Parameter.cs b/src/RestSharp/Parameters/Parameter.cs index 9d5241c22..d11403830 100644 --- a/src/RestSharp/Parameters/Parameter.cs +++ b/src/RestSharp/Parameters/Parameter.cs @@ -26,7 +26,7 @@ public Parameter(string? name, object? value, ParameterType type, bool encode = } Name = name; - Value = type != ParameterType.UrlSegment ? value : value?.ToString().Replace("%2F", "/").Replace("%2f", "/"); + Value = type != ParameterType.UrlSegment ? value : value?.ToString()?.Replace("%2F", "/").Replace("%2f", "/"); Type = type == ParameterType.QueryStringWithoutEncode ? ParameterType.QueryString : type; Encode = type != ParameterType.QueryStringWithoutEncode && encode; } diff --git a/src/RestSharp/Request/HttpContentExtensions.cs b/src/RestSharp/Request/HttpContentExtensions.cs index f833d25ed..a12edf8c6 100644 --- a/src/RestSharp/Request/HttpContentExtensions.cs +++ b/src/RestSharp/Request/HttpContentExtensions.cs @@ -17,9 +17,9 @@ namespace RestSharp; public static class HttpContentExtensions { public static string GetFormBoundary(this HttpContent content) { - var contentType = content.Headers.ContentType.ToString(); - var index = contentType.IndexOf("boundary=", StringComparison.Ordinal); - return index > 0 ? GetFormBoundary(contentType, index) : ""; + var contentType = content.Headers.ContentType?.ToString(); + var index = contentType?.IndexOf("boundary=", StringComparison.Ordinal) ?? 0; + return index > 0 ? GetFormBoundary(contentType!, index) : ""; } static string GetFormBoundary(string headerValue, int index) { diff --git a/src/RestSharp/Request/HttpRequestMessageExtensions.cs b/src/RestSharp/Request/HttpRequestMessageExtensions.cs index 1d452b59f..a2cce28f4 100644 --- a/src/RestSharp/Request/HttpRequestMessageExtensions.cs +++ b/src/RestSharp/Request/HttpRequestMessageExtensions.cs @@ -26,8 +26,8 @@ public static void AddHeaders(this HttpRequestMessage message, IEnumerable x.Type == ParameterType.GetOrPost) - .Select(x => new KeyValuePair(x.Name!, x.Value!.ToString())) + .Select(x => new KeyValuePair(x.Name!, x.Value!.ToString()!))! ); Content = formContent; } @@ -139,11 +144,12 @@ void AddHeader(Parameter parameter) { var parameterStringValue = parameter.Value!.ToString(); var value = parameter.Name switch { - ContentType => GetContentTypeHeader(parameterStringValue), + ContentType => GetContentTypeHeader(Ensure.NotNull(parameterStringValue, nameof(parameter))), _ => parameterStringValue }; - Content!.Headers.Remove(parameter.Name); - Content!.Headers.TryAddWithoutValidation(parameter.Name, value); + var pName = Ensure.NotNull(parameter.Name, nameof(parameter.Name)); + Content!.Headers.Remove(pName); + Content!.Headers.TryAddWithoutValidation(pName, value); } } diff --git a/src/RestSharp/Request/RestRequestExtensions.cs b/src/RestSharp/Request/RestRequestExtensions.cs index 711c28ed4..d056626c7 100644 --- a/src/RestSharp/Request/RestRequestExtensions.cs +++ b/src/RestSharp/Request/RestRequestExtensions.cs @@ -132,7 +132,7 @@ public static RestRequest AddBody(this RestRequest request, object obj) => request.RequestFormat switch { DataFormat.Json => request.AddJsonBody(obj), DataFormat.Xml => request.AddXmlBody(obj), - _ => request.AddParameter("", obj.ToString()) + _ => request.AddParameter("", obj.ToString()!) }; public static RestRequest AddJsonBody(this RestRequest request, object obj) { diff --git a/src/RestSharp/Response/RestResponseBase.cs b/src/RestSharp/Response/RestResponseBase.cs index e165c1386..8526334fa 100644 --- a/src/RestSharp/Response/RestResponseBase.cs +++ b/src/RestSharp/Response/RestResponseBase.cs @@ -49,7 +49,7 @@ public abstract class RestResponseBase { /// /// Encoding of the response content /// - public ICollection ContentEncoding { get; init; } + public ICollection ContentEncoding { get; init; } = new List(); /// /// String representation of response content @@ -84,17 +84,17 @@ public abstract class RestResponseBase { /// /// HttpWebResponse.Server /// - public string Server { get; init; } + public string? Server { get; init; } /// /// Cookies returned by server with the response /// - public CookieCollection Cookies { get; protected internal set; } + public CookieCollection? Cookies { get; protected internal set; } /// /// Headers returned by server with the response /// - public IList Headers { get; protected internal set; } + public IList? Headers { get; protected internal set; } /// /// Status of the request. Will return Error for transport errors. @@ -105,7 +105,7 @@ public abstract class RestResponseBase { /// /// Transport or other non-HTTP error generated while attempting request /// - public string ErrorMessage { get; set; } + public string? ErrorMessage { get; set; } /// /// The exception thrown during the request, if any diff --git a/src/RestSharp/RestClient.cs b/src/RestSharp/RestClient.cs index 8ae88be53..37012bc55 100644 --- a/src/RestSharp/RestClient.cs +++ b/src/RestSharp/RestClient.cs @@ -96,7 +96,7 @@ public RestClient(string baseUrl) : this(new Uri(Ensure.NotEmptyString(baseUrl, Func Encode { get; set; } = s => s.UrlEncode(); - Func EncodeQuery { get; set; } = (s, encoding) => s.UrlEncode(encoding); + Func EncodeQuery { get; set; } = (s, encoding) => s.UrlEncode(encoding)!; /// /// Allows to use a custom way to encode URL parameters @@ -136,7 +136,7 @@ public RestClient AddDefaultParameter(Parameter p) { ); case ParameterType.Cookie: { lock (_cookieContainer) { - _cookieContainer.Add(new Cookie(p.Name, p.Value!.ToString())); + _cookieContainer.Add(new Cookie(p.Name!, p.Value!.ToString())); } break; } @@ -164,7 +164,7 @@ public Uri BuildUri(RestRequest request) { return new Uri(finalUri!); } - internal string? BuildUriWithoutQueryParameters(RestRequest request) { + internal string BuildUriWithoutQueryParameters(RestRequest request) { DoBuildUriValidations(request); var applied = GetUrlSegmentParamsValues(request); @@ -231,7 +231,7 @@ UrlSegmentParamsValues GetUrlSegmentParamsValues(RestRequest request) { foreach (var parameter in parameters) { var paramPlaceHolder = $"{{{parameter.Name}}}"; - var paramValue = parameter.Encode ? Encode(parameter.Value!.ToString()) : parameter.Value!.ToString(); + var paramValue = parameter.Encode ? Encode(parameter.Value!.ToString()!) : parameter.Value!.ToString(); if (hasResource) assembled = assembled.Replace(paramPlaceHolder, paramValue); @@ -241,12 +241,12 @@ UrlSegmentParamsValues GetUrlSegmentParamsValues(RestRequest request) { return new UrlSegmentParamsValues(builder.Uri, assembled); } - static string? MergeBaseUrlAndResource(Uri? baseUrl, string? resource) { + static string MergeBaseUrlAndResource(Uri? baseUrl, string? resource) { var assembled = resource; if (!IsNullOrEmpty(assembled) && assembled!.StartsWith("/")) assembled = assembled.Substring(1); - if (baseUrl == null || IsNullOrEmpty(baseUrl.AbsoluteUri)) return assembled; + if (baseUrl == null || IsNullOrEmpty(baseUrl.AbsoluteUri)) return assembled ?? ""; var usingBaseUri = baseUrl.AbsoluteUri.EndsWith("/") || IsNullOrEmpty(assembled) ? baseUrl : new Uri(baseUrl.AbsoluteUri + "/"); @@ -295,7 +295,7 @@ string EncodeParameter(Parameter parameter, Encoding encoding) { ? $"{parameter.Name}={StringOrEmpty(parameter.Value)}" : $"{EncodeQuery(parameter.Name!, encoding)}={EncodeQuery(StringOrEmpty(parameter.Value), encoding)}"; - static string StringOrEmpty(object? value) => value == null ? "" : value.ToString(); + static string StringOrEmpty(object? value) => value == null ? "" : value.ToString()!; } internal RestResponse Deserialize(RestRequest request, RestResponse raw) { diff --git a/src/RestSharp/RestClientOptions.cs b/src/RestSharp/RestClientOptions.cs index 61a32df85..1f4283b02 100644 --- a/src/RestSharp/RestClientOptions.cs +++ b/src/RestSharp/RestClientOptions.cs @@ -23,7 +23,7 @@ namespace RestSharp; public class RestClientOptions { - static readonly Version Version = new AssemblyName(typeof(RestClientOptions).Assembly.FullName).Version; + static readonly Version Version = new AssemblyName(typeof(RestClientOptions).Assembly.FullName!).Version!; static readonly string DefaultUserAgent = $"RestSharp/{Version}"; diff --git a/src/RestSharp/Serializers/DeserializeAsAttribute.cs b/src/RestSharp/Serializers/DeserializeAsAttribute.cs index 6752e7d7f..39f97984d 100644 --- a/src/RestSharp/Serializers/DeserializeAsAttribute.cs +++ b/src/RestSharp/Serializers/DeserializeAsAttribute.cs @@ -8,7 +8,7 @@ public sealed class DeserializeAsAttribute : Attribute { /// /// The name to use for the serialized element /// - public string Name { get; set; } + public string? Name { get; set; } /// /// Sets if the property to Deserialize is an Attribute or Element (Default: false) diff --git a/src/RestSharp/Serializers/Json/SystemTextJsonSerializer.cs b/src/RestSharp/Serializers/Json/SystemTextJsonSerializer.cs index b25be8420..ef57e2d6c 100644 --- a/src/RestSharp/Serializers/Json/SystemTextJsonSerializer.cs +++ b/src/RestSharp/Serializers/Json/SystemTextJsonSerializer.cs @@ -20,7 +20,7 @@ public class SystemTextJsonSerializer : IRestSerializer { public string? Serialize(Parameter bodyParameter) => Serialize(bodyParameter.Value); - public T? Deserialize(RestResponse response) => JsonSerializer.Deserialize(response.Content, _options); + public T? Deserialize(RestResponse response) => JsonSerializer.Deserialize(response.Content!, _options); public string[] SupportedContentTypes { get; } = { "application/json", "text/json", "text/x-json", "text/javascript", "*+json" diff --git a/src/RestSharp/Serializers/Xml/DotNetXmlDeserializer.cs b/src/RestSharp/Serializers/Xml/DotNetXmlDeserializer.cs index 230f9312e..aade10166 100644 --- a/src/RestSharp/Serializers/Xml/DotNetXmlDeserializer.cs +++ b/src/RestSharp/Serializers/Xml/DotNetXmlDeserializer.cs @@ -14,22 +14,22 @@ public class DotNetXmlDeserializer : IXmlDeserializer { /// /// Name of the root element to use when serializing /// - public string RootElement { get; set; } + public string? RootElement { get; set; } /// /// XML namespace to use when serializing /// - public string Namespace { get; set; } + public string? Namespace { get; set; } - public string DateFormat { get; set; } + public string? DateFormat { get; set; } public T? Deserialize(RestResponse response) { if (string.IsNullOrEmpty(response.Content)) return default; - using var stream = new MemoryStream(Encoding.GetBytes(response.Content)); + using var stream = new MemoryStream(Encoding.GetBytes(response.Content!)); var serializer = new System.Xml.Serialization.XmlSerializer(typeof(T)); - return (T)serializer.Deserialize(stream); + return (T?)serializer.Deserialize(stream); } } \ No newline at end of file diff --git a/src/RestSharp/Serializers/Xml/DotNetXmlSerializer.cs b/src/RestSharp/Serializers/Xml/DotNetXmlSerializer.cs index 58c884b6f..c2aa9d768 100644 --- a/src/RestSharp/Serializers/Xml/DotNetXmlSerializer.cs +++ b/src/RestSharp/Serializers/Xml/DotNetXmlSerializer.cs @@ -53,12 +53,12 @@ public string Serialize(object obj) { /// /// XML namespace to use when serializing /// - public string Namespace { get; set; } + public string? Namespace { get; set; } /// /// Format string to use when serializing dates /// - public string DateFormat { get; set; } + public string? DateFormat { get; set; } /// /// Content type for serialized content diff --git a/src/RestSharp/Serializers/Xml/IXmlDeserializer.cs b/src/RestSharp/Serializers/Xml/IXmlDeserializer.cs index ccb77b01b..a85ea9970 100644 --- a/src/RestSharp/Serializers/Xml/IXmlDeserializer.cs +++ b/src/RestSharp/Serializers/Xml/IXmlDeserializer.cs @@ -1,7 +1,7 @@ namespace RestSharp.Serializers.Xml; public interface IXmlDeserializer : IDeserializer, IWithRootElement { - string Namespace { get; set; } + string? Namespace { get; set; } - string DateFormat { get; set; } + string? DateFormat { get; set; } } \ No newline at end of file diff --git a/src/RestSharp/Serializers/Xml/IXmlSerializer.cs b/src/RestSharp/Serializers/Xml/IXmlSerializer.cs index 4b29d3dff..27d845c52 100644 --- a/src/RestSharp/Serializers/Xml/IXmlSerializer.cs +++ b/src/RestSharp/Serializers/Xml/IXmlSerializer.cs @@ -1,7 +1,7 @@ namespace RestSharp.Serializers.Xml; public interface IXmlSerializer : ISerializer, IWithRootElement { - string Namespace { get; set; } + string? Namespace { get; set; } - string DateFormat { get; set; } + string? DateFormat { get; set; } } \ No newline at end of file diff --git a/src/RestSharp/Serializers/Xml/XmlAttributeDeserializer.cs b/src/RestSharp/Serializers/Xml/XmlAttributeDeserializer.cs index 6cec90f48..768d88fdd 100644 --- a/src/RestSharp/Serializers/Xml/XmlAttributeDeserializer.cs +++ b/src/RestSharp/Serializers/Xml/XmlAttributeDeserializer.cs @@ -5,7 +5,7 @@ namespace RestSharp.Serializers.Xml; public class XmlAttributeDeserializer : XmlDeserializer { - protected override object? GetValueFromXml(XElement root, XName name, PropertyInfo prop, bool useExactName) { + protected override object? GetValueFromXml(XElement? root, XName name, PropertyInfo prop, bool useExactName) { var isAttribute = false; //Check for the DeserializeAs attribute on the property @@ -18,7 +18,7 @@ public class XmlAttributeDeserializer : XmlDeserializer { if (!isAttribute) return base.GetValueFromXml(root, name, prop, useExactName); - var attributeVal = GetAttributeByName(root, name, useExactName); + var attributeVal = GetAttributeByName(root!, name, useExactName); return attributeVal?.Value ?? base.GetValueFromXml(root, name, prop, useExactName); } diff --git a/src/RestSharp/Serializers/Xml/XmlDeserializer.cs b/src/RestSharp/Serializers/Xml/XmlDeserializer.cs index 3fdc767bb..cb581476d 100644 --- a/src/RestSharp/Serializers/Xml/XmlDeserializer.cs +++ b/src/RestSharp/Serializers/Xml/XmlDeserializer.cs @@ -15,22 +15,22 @@ public class XmlDeserializer : IXmlDeserializer { public string? RootElement { get; set; } - public string Namespace { get; set; } + public string? Namespace { get; set; } - public string DateFormat { get; set; } + public string? DateFormat { get; set; } public virtual T? Deserialize(RestResponse response) { if (string.IsNullOrEmpty(response.Content)) return default; - var doc = XDocument.Parse(response.Content); + var doc = XDocument.Parse(response.Content!); var root = doc.Root; if (RootElement != null && doc.Root != null) root = doc.Root.DescendantsAndSelf(RootElement.AsNamespaced(Namespace)).SingleOrDefault(); // autodetect xml namespace - if (!Namespace.HasValue()) + if (Namespace.IsEmpty()) RemoveNamespace(doc); var x = Activator.CreateInstance(); @@ -87,8 +87,8 @@ protected virtual object Map(object x, XElement? root) { if (attributes.Any()) { var attribute = (DeserializeAsAttribute)attributes.First(); - name = attribute.Name.AsNamespaced(Namespace); - isNameDefinedInAttribute = !string.IsNullOrEmpty(name?.LocalName); + name = attribute.Name!.AsNamespaced(Namespace); + isNameDefinedInAttribute = !string.IsNullOrEmpty(name.LocalName); deserializeFromContent = attribute.Content; @@ -108,7 +108,7 @@ protected virtual object Map(object x, XElement? root) { if (value == null) { // special case for text content node if (deserializeFromContent) { - var textNode = root.Nodes().FirstOrDefault(n => n is XText); + var textNode = root!.Nodes().FirstOrDefault(n => n is XText); if (textNode != null) { value = ((XText)textNode).Value; @@ -122,7 +122,7 @@ protected virtual object Map(object x, XElement? root) { if (type.IsGenericType) { var genericType = type.GetGenericArguments()[0]; var first = GetElementByName(root, genericType.Name); - var list = (IList)Activator.CreateInstance(type.AsType()); + var list = (IList)Activator.CreateInstance(type.AsType())!; if (first != null && root != null) { var elements = root.Elements(first.Name); @@ -149,8 +149,7 @@ protected virtual object Map(object x, XElement? root) { var asType = type.AsType(); if (asType == typeof(bool)) { - var toConvert = value.ToString() - .ToLower(Culture); + var toConvert = value.ToString()!.ToLower(Culture); prop.SetValue(x, XmlConvert.ToBoolean(toConvert), null); } @@ -167,12 +166,12 @@ protected virtual object Map(object x, XElement? root) { } } else if (type.IsEnum) { - var converted = type.AsType().FindEnumValue(value.ToString(), Culture); + var converted = type.AsType().FindEnumValue(value.ToString()!, Culture); prop.SetValue(x, converted, null); } else if (asType == typeof(Uri)) { - var uri = new Uri(value.ToString(), UriKind.RelativeOrAbsolute); + var uri = new Uri(value.ToString()!, UriKind.RelativeOrAbsolute); prop.SetValue(x, uri, null); } @@ -180,9 +179,9 @@ protected virtual object Map(object x, XElement? root) { prop.SetValue(x, value, null); } else if (asType == typeof(DateTime)) { - value = DateFormat.HasValue() - ? DateTime.ParseExact(value.ToString(), DateFormat, Culture) - : DateTime.Parse(value.ToString(), Culture); + value = DateFormat.IsNotEmpty() + ? DateTime.ParseExact(value.ToString()!, DateFormat!, Culture) + : DateTime.Parse(value.ToString()!, Culture); prop.SetValue(x, value, null); } @@ -209,7 +208,7 @@ protected virtual object Map(object x, XElement? root) { } } else if (asType == typeof(decimal)) { - value = decimal.Parse(value.ToString(), Culture); + value = decimal.Parse(value.ToString()!, Culture); prop.SetValue(x, value, null); } else if (asType == typeof(Guid)) { @@ -217,20 +216,20 @@ protected virtual object Map(object x, XElement? root) { value = string.IsNullOrEmpty(raw) ? Guid.Empty - : new Guid(value.ToString()); + : new Guid(value.ToString()!); prop.SetValue(x, value, null); } else if (asType == typeof(TimeSpan)) { - var timeSpan = XmlConvert.ToTimeSpan(value.ToString()); + var timeSpan = XmlConvert.ToTimeSpan(value.ToString()!); prop.SetValue(x, timeSpan, null); } else if (type.IsGenericType) { - var list = (IList)Activator.CreateInstance(asType); + var list = (IList)Activator.CreateInstance(asType)!; var container = GetElementByName(root, name); - if (container.HasElements) { + if (container?.HasElements == true) { var first = container.Elements().FirstOrDefault(); if (first != null) { @@ -246,14 +245,14 @@ protected virtual object Map(object x, XElement? root) { else if (asType.IsSubclassOfRawGeneric(typeof(List<>))) { // handles classes that derive from List // e.g. a collection that also has attributes - var list = HandleListDerivative(root, prop.Name, asType); + var list = HandleListDerivative(root!, prop.Name, asType); prop.SetValue(x, list, null); } else { //fallback to type converters if possible - if (TryGetFromString(value.ToString(), out var result, asType)) { + if (TryGetFromString(value.ToString()!, out var result, asType)) { prop.SetValue(x, result, null); } else { @@ -294,16 +293,16 @@ void PopulateListFromElements(Type t, IEnumerable elements, IList list object HandleListDerivative(XElement root, string propName, Type type) { var t = type.IsGenericType ? type.GetGenericArguments()[0] - : type.BaseType.GetGenericArguments()[0]; + : type.BaseType!.GetGenericArguments()[0]; - var list = (IList)Activator.CreateInstance(type); + var list = (IList)Activator.CreateInstance(type)!; IList elements = root.Descendants(t.Name.AsNamespaced(Namespace)).ToList(); var name = t.Name; var attribute = t.GetAttribute(); - if (attribute != null) + if (attribute?.Name != null) name = attribute.Name; if (!elements.Any()) { @@ -351,7 +350,7 @@ object HandleListDerivative(XElement root, string propName, Type type) { item = element.Value.ChangeType(t); } else { - item = Activator.CreateInstance(t); + item = Activator.CreateInstance(t)!; Map(item, element); } @@ -378,23 +377,23 @@ object HandleListDerivative(XElement root, string propName, Type type) { return val; } - protected virtual XElement? GetElementByName(XElement root, XName name) { + protected virtual XElement? GetElementByName(XElement? root, XName name) { var lowerName = name.LocalName.ToLower(Culture).AsNamespaced(name.NamespaceName); var camelName = name.LocalName.ToCamelCase(Culture).AsNamespaced(name.NamespaceName); - if (root.Element(name) != null) + if (root?.Element(name) != null) return root.Element(name); - if (root.Element(lowerName) != null) + if (root?.Element(lowerName) != null) return root.Element(lowerName); - if (root.Element(camelName) != null) + if (root?.Element(camelName) != null) return root.Element(camelName); // try looking for element that matches sanitized property name (Order by depth) - var orderedDescendants = root.Descendants() + var orderedDescendants = root?.Descendants() .OrderBy(d => d.Ancestors().Count()) - .ToList(); + .ToList() ?? new List(); var element = orderedDescendants .FirstOrDefault(d => d.Name.LocalName.RemoveUnderscoresAndDashes() == name.LocalName) ?? @@ -408,8 +407,8 @@ object HandleListDerivative(XElement root, string propName, Type type) { ); return element == null && - name == "Value".AsNamespaced(name.NamespaceName) && - (!root.HasAttributes || root.Attributes().All(x => x.Name != name)) + name == "Value".AsNamespaced(name.NamespaceName) && root != null && + (root.HasAttributes || root.Attributes().All(x => x.Name != name)) ? root : element; } diff --git a/src/RestSharp/Serializers/Xml/XmlExtensions.cs b/src/RestSharp/Serializers/Xml/XmlExtensions.cs index fb8578f36..2c619f523 100644 --- a/src/RestSharp/Serializers/Xml/XmlExtensions.cs +++ b/src/RestSharp/Serializers/Xml/XmlExtensions.cs @@ -13,10 +13,10 @@ public static class XmlExtensions { /// Element name /// XML Namespace /// - public static XName AsNamespaced(this string name, string @namespace) { - XName xName = name; + public static XName AsNamespaced(this string? name, string? @namespace) { + XName xName = Ensure.NotNull(name, nameof(name)); - if (@namespace.HasValue()) xName = XName.Get(name, @namespace); + if (name != null && @namespace.IsNotEmpty()) xName = XName.Get(name, @namespace!); return xName; } diff --git a/src/RestSharp/Serializers/Xml/XmlRestSerializer.cs b/src/RestSharp/Serializers/Xml/XmlRestSerializer.cs index 129e77b55..ad50172ba 100644 --- a/src/RestSharp/Serializers/Xml/XmlRestSerializer.cs +++ b/src/RestSharp/Serializers/Xml/XmlRestSerializer.cs @@ -17,9 +17,9 @@ namespace RestSharp.Serializers.Xml; public class XmlRestSerializer : IRestSerializer, IXmlSerializer, IXmlDeserializer { - XmlSerilizationOptions _options = XmlSerilizationOptions.Default; - IXmlDeserializer _xmlDeserializer; - IXmlSerializer _xmlSerializer; + XmlSerializationOptions _options = XmlSerializationOptions.Default; + IXmlDeserializer _xmlDeserializer; + IXmlSerializer _xmlSerializer; public XmlRestSerializer() : this(new XmlSerializer(), new XmlDeserializer()) { } @@ -34,13 +34,16 @@ public XmlRestSerializer(IXmlSerializer xmlSerializer, IXmlDeserializer xmlDeser public string ContentType { get; set; } = Serializers.ContentType.Xml; - public string? Serialize(object? obj) => _xmlSerializer.Serialize(obj); + public string? Serialize(object? obj) => _xmlSerializer.Serialize(Ensure.NotNull(obj, nameof(obj))); public T? Deserialize(RestResponse response) => _xmlDeserializer.Deserialize(response); public string? Serialize(Parameter parameter) { if (parameter is not XmlParameter xmlParameter) - throw new InvalidOperationException("Supplied parameter is not an XML parameter"); + throw new ArgumentException("Supplied parameter is not an XML parameter", nameof(parameter)); + + if (parameter.Value == null) + throw new ArgumentNullException(nameof(parameter), "Parameter value is null"); var savedNamespace = _xmlSerializer.Namespace; _xmlSerializer.Namespace = xmlParameter.XmlNamespace ?? savedNamespace; @@ -61,30 +64,32 @@ public string? RootElement { } } - public string Namespace { + public string? Namespace { get => _options.Namespace; set { - _options.Namespace = value; - _xmlSerializer.Namespace = value; - _xmlDeserializer.Namespace = value; + var ns = Ensure.NotEmptyString(value, nameof(Namespace)); + _options.Namespace = ns; + _xmlSerializer.Namespace = ns; + _xmlDeserializer.Namespace = ns; } } - public string DateFormat { + public string? DateFormat { get => _options.DateFormat; set { - _options.DateFormat = value; - _xmlSerializer.DateFormat = value; - _xmlDeserializer.DateFormat = value; + var dateFormat = Ensure.NotEmptyString(value, nameof(DataFormat)); + _options.DateFormat = dateFormat; + _xmlSerializer.DateFormat = dateFormat; + _xmlDeserializer.DateFormat = dateFormat; } } - public XmlRestSerializer WithOptions(XmlSerilizationOptions options) { + public XmlRestSerializer WithOptions(XmlSerializationOptions options) { _options = options; return this; } - public XmlRestSerializer WithXmlSerializer(XmlSerilizationOptions? options = null) where T : IXmlSerializer, new() { + public XmlRestSerializer WithXmlSerializer(XmlSerializationOptions? options = null) where T : IXmlSerializer, new() { if (options != null) _options = options; return WithXmlSerializer( @@ -101,7 +106,7 @@ public XmlRestSerializer WithXmlSerializer(IXmlSerializer xmlSerializer) { return this; } - public XmlRestSerializer WithXmlDeserializer(XmlSerilizationOptions? options = null) where T : IXmlDeserializer, new() { + public XmlRestSerializer WithXmlDeserializer(XmlSerializationOptions? options = null) where T : IXmlDeserializer, new() { if (options != null) _options = options; return WithXmlDeserializer( @@ -119,23 +124,23 @@ public XmlRestSerializer WithXmlDeserializer(IXmlDeserializer xmlDeserializer) { } } -public class XmlSerilizationOptions { +public class XmlSerializationOptions { /// /// Name of the root element to use when serializing /// - public string RootElement { get; set; } + public string? RootElement { get; set; } /// /// XML namespace to use when serializing /// - public string Namespace { get; set; } + public string? Namespace { get; set; } /// /// Format string to use when serializing dates /// - public string DateFormat { get; set; } + public string? DateFormat { get; set; } - public CultureInfo Culture { get; set; } + public CultureInfo? Culture { get; set; } - public static XmlSerilizationOptions Default => new() { Culture = CultureInfo.InvariantCulture }; + public static XmlSerializationOptions Default => new() { Culture = CultureInfo.InvariantCulture }; } \ No newline at end of file diff --git a/src/RestSharp/Serializers/Xml/XmlSerializer.cs b/src/RestSharp/Serializers/Xml/XmlSerializer.cs index 3ce4aafc2..c2c8ccff1 100644 --- a/src/RestSharp/Serializers/Xml/XmlSerializer.cs +++ b/src/RestSharp/Serializers/Xml/XmlSerializer.cs @@ -79,12 +79,12 @@ public string Serialize(object obj) { /// /// XML namespace to use when serializing /// - public string Namespace { get; set; } + public string? Namespace { get; set; } /// /// Format string to use when serializing dates /// - public string DateFormat { get; set; } + public string? DateFormat { get; set; } /// /// Content type for serialized content @@ -115,11 +115,11 @@ void Map(XContainer root, object obj) { var options = prop.GetAttribute(); if (options != null) { - name = options.Name.HasValue() + name = options.Name.IsNotEmpty() ? options.Name : name; - name = options.TransformName(name); + name = options.TransformName(name!); useAttribute = options.Attribute; @@ -159,11 +159,11 @@ void Map(XContainer root, object obj) { var type = item.GetType(); var setting = type.GetAttribute(); - var itemTypeName = setting != null && setting.Name.HasValue() + var itemTypeName = setting != null && setting.Name.IsNotEmpty() ? setting.Name : type.Name; - var instance = new XElement(itemTypeName.AsNamespaced(Namespace)); + var instance = new XElement(itemTypeName!.AsNamespaced(Namespace)); Map(instance, item); @@ -189,12 +189,12 @@ void Map(XContainer root, object obj) { string GetSerializedValue(object obj) { var output = obj switch { - DateTime time when DateFormat.HasValue() => time.ToString(DateFormat, CultureInfo.InvariantCulture), - bool b => b.ToString().ToLowerInvariant(), - _ => obj + DateTime time when DateFormat.IsNotEmpty() => time.ToString(DateFormat, CultureInfo.InvariantCulture), + bool b => b.ToString().ToLowerInvariant(), + _ => obj }; - return IsNumeric(obj) ? SerializeNumber(obj) : output.ToString(); + return IsNumeric(obj) ? SerializeNumber(obj) : output.ToString()!; } static string SerializeNumber(object number) diff --git a/test/Directory.Build.props b/test/Directory.Build.props index 336a5e32a..cdb2a6932 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -4,6 +4,7 @@ true false net6.0 + disable diff --git a/test/RestSharp.Tests.Shared/Fixtures/RequestBodyCapturer.cs b/test/RestSharp.Tests.Shared/Fixtures/RequestBodyCapturer.cs index 5a88e799f..3adc07fec 100644 --- a/test/RestSharp.Tests.Shared/Fixtures/RequestBodyCapturer.cs +++ b/test/RestSharp.Tests.Shared/Fixtures/RequestBodyCapturer.cs @@ -1,18 +1,15 @@ using System.Net; using RestSharp.Tests.Shared.Extensions; -namespace RestSharp.Tests.Shared.Fixtures; +namespace RestSharp.Tests.Shared.Fixtures; public class RequestBodyCapturer { public const string Resource = "Capture"; - public static string? CapturedContentType { get; set; } - - public static bool CapturedHasEntityBody { get; set; } - - public static string? CapturedEntityBody { get; set; } - - public static Uri? CapturedUrl { get; set; } + public static string CapturedContentType { get; set; } + public static bool CapturedHasEntityBody { get; set; } + public static string CapturedEntityBody { get; set; } + public static Uri CapturedUrl { get; set; } public static void Capture(HttpListenerContext context) { var request = context.Request; diff --git a/test/RestSharp.Tests.Shared/Fixtures/SimpleServer.cs b/test/RestSharp.Tests.Shared/Fixtures/SimpleServer.cs index 96baf2bfc..d53863c2f 100644 --- a/test/RestSharp.Tests.Shared/Fixtures/SimpleServer.cs +++ b/test/RestSharp.Tests.Shared/Fixtures/SimpleServer.cs @@ -12,9 +12,9 @@ public sealed class SimpleServer : IDisposable { public string ServerUrl { get; } SimpleServer( - int port, - Action? handler = null, - AuthenticationSchemes authenticationSchemes = AuthenticationSchemes.Anonymous + int port, + Action handler = null, + AuthenticationSchemes authenticationSchemes = AuthenticationSchemes.Anonymous ) { Url = $"http://localhost:{port}/"; ServerUrl = $"http://{Environment.MachineName}:{port}/"; @@ -29,8 +29,8 @@ public void Dispose() { } public static SimpleServer Create( - Action? handler = null, - AuthenticationSchemes authenticationSchemes = AuthenticationSchemes.Anonymous + Action handler = null, + AuthenticationSchemes authenticationSchemes = AuthenticationSchemes.Anonymous ) { var port = Random.Next(1000, 9999); return new SimpleServer(port, handler, authenticationSchemes); diff --git a/test/RestSharp.Tests.Shared/Fixtures/TestHttpServer.cs b/test/RestSharp.Tests.Shared/Fixtures/TestHttpServer.cs index faf8f9ab2..8fb323d53 100644 --- a/test/RestSharp.Tests.Shared/Fixtures/TestHttpServer.cs +++ b/test/RestSharp.Tests.Shared/Fixtures/TestHttpServer.cs @@ -53,8 +53,8 @@ async Task HandleRequests(CancellationToken cancellationToken) { var context = await _listener.GetContextAsync(); try { - Dictionary? parameters = null; - TestRequestHandler handler; + Dictionary parameters = null; + TestRequestHandler handler; lock (_requestHandlersLock) { handler = _requestHandlers.FirstOrDefault( @@ -62,7 +62,7 @@ async Task HandleRequests(CancellationToken cancellationToken) { ); } - string? responseString = null; + string responseString = null; if (handler != null) { //add the query string parameters to the pre-defined url parameters that were set from MatchesUrl() diff --git a/test/RestSharp.Tests.Shared/Fixtures/TestRequestHandler.cs b/test/RestSharp.Tests.Shared/Fixtures/TestRequestHandler.cs index 850a33867..e83a8ba01 100644 --- a/test/RestSharp.Tests.Shared/Fixtures/TestRequestHandler.cs +++ b/test/RestSharp.Tests.Shared/Fixtures/TestRequestHandler.cs @@ -1,7 +1,7 @@ using System.Net; using System.Text.RegularExpressions; -namespace RestSharp.Tests.Shared.Fixtures; +namespace RestSharp.Tests.Shared.Fixtures; public class TestRequestHandler { readonly Regex _comparisonRegex; @@ -24,7 +24,7 @@ public TestRequestHandler(string url, Action> HandlerAction { get; } Regex CreateComparisonRegex(string url) { @@ -45,7 +45,7 @@ Regex CreateComparisonRegex(string url) { return new Regex(regexString); } - public bool TryMatchUrl(string rawUrl, string httpMethod, out Dictionary? parameters) { + public bool TryMatchUrl(string rawUrl, string httpMethod, out Dictionary parameters) { var match = _comparisonRegex.Match(rawUrl); var isMethodMatched = HttpMethod == null || HttpMethod.Split(',').Contains(httpMethod); diff --git a/test/RestSharp.Tests.Shared/Fixtures/WebServer.cs b/test/RestSharp.Tests.Shared/Fixtures/WebServer.cs index 5578db88c..cbd4f4673 100644 --- a/test/RestSharp.Tests.Shared/Fixtures/WebServer.cs +++ b/test/RestSharp.Tests.Shared/Fixtures/WebServer.cs @@ -3,10 +3,10 @@ namespace RestSharp.Tests.Shared.Fixtures; public class WebServer { - readonly HttpListener _listener = new(); - Action? _responderMethod; + readonly HttpListener _listener = new(); + Action _responderMethod; - public WebServer(string prefix, Action? method, AuthenticationSchemes authenticationSchemes) { + public WebServer(string prefix, Action method, AuthenticationSchemes authenticationSchemes) { if (string.IsNullOrEmpty(prefix)) throw new ArgumentException("URI prefix is required"); @@ -19,6 +19,7 @@ public WebServer(string prefix, Action? method, Authenticat public async Task Run(CancellationToken token) { var taskFactory = new TaskFactory(token); _listener.Start(); + try { while (!token.IsCancellationRequested && _listener.IsListening) { try { @@ -29,9 +30,6 @@ public async Task Run(CancellationToken token) { _responderMethod?.Invoke(ctx); ctx.Response.OutputStream.Close(); } - // catch (HttpListenerException) { - // // it's ok - // } catch (Exception e) { Console.WriteLine(e.ToString()); } @@ -40,11 +38,13 @@ public async Task Run(CancellationToken token) { catch (Exception e) { Console.WriteLine(e.ToString()); } - - Task GetContextAsync() => taskFactory.FromAsync( - (callback, state) => ((HttpListener)state!).BeginGetContext(callback, state), - iar => ((HttpListener)iar.AsyncState!).EndGetContext(iar), - _listener); + + Task GetContextAsync() + => taskFactory.FromAsync( + (callback, state) => ((HttpListener)state!).BeginGetContext(callback, state), + iar => ((HttpListener)iar.AsyncState!).EndGetContext(iar), + _listener + ); } public void Stop() { diff --git a/test/RestSharp.Tests/OAuth1AuthenticatorTests.cs b/test/RestSharp.Tests/OAuth1AuthenticatorTests.cs index 83d3601e1..e7266a971 100644 --- a/test/RestSharp.Tests/OAuth1AuthenticatorTests.cs +++ b/test/RestSharp.Tests/OAuth1AuthenticatorTests.cs @@ -41,17 +41,17 @@ public void Authenticate_ShouldAddAuthorizationAsTextValueToRequest_OnHttpAuthor var authParameter = request.Parameters.Single(x => x.Name == "Authorization"); var value = (string)authParameter.Value; - Assert.True(value.Contains("OAuth")); - Assert.True(value.Contains("realm=\"Realm\"")); - Assert.True(value.Contains("oauth_timestamp=")); - Assert.True(value.Contains("oauth_signature=\"ConsumerSecret")); - Assert.True(value.Contains("oauth_nonce=")); - Assert.True(value.Contains("oauth_consumer_key=\"ConsumerKey\"")); - Assert.True(value.Contains("oauth_signature_method=\"PLAINTEXT\"")); - Assert.True(value.Contains("oauth_version=\"Version\"")); - Assert.True(value.Contains("x_auth_mode=\"client_auth\"")); - Assert.True(value.Contains("x_auth_username=\"ClientUsername\"")); - Assert.True(value.Contains("x_auth_password=\"ClientPassword\"")); + Assert.Contains("OAuth", value); + Assert.Contains("realm=\"Realm\"", value); + Assert.Contains("oauth_timestamp=", value); + Assert.Contains("oauth_signature=\"ConsumerSecret", value); + Assert.Contains("oauth_nonce=", value); + Assert.Contains("oauth_consumer_key=\"ConsumerKey\"", value); + Assert.Contains("oauth_signature_method=\"PLAINTEXT\"", value); + Assert.Contains("oauth_version=\"Version\"", value); + Assert.Contains("x_auth_mode=\"client_auth\"", value); + Assert.Contains("x_auth_username=\"ClientUsername\"", value); + Assert.Contains("x_auth_password=\"ClientPassword\"", value); } [Fact] @@ -197,6 +197,7 @@ public void Authenticate_ShouldAllowEmptyConsumerSecret_OnHttpAuthorizationHeade var authParameter = request.Parameters.Single(x => x.Name == "Authorization"); var value = (string)authParameter.Value; + Assert.NotNull(value); Assert.NotEmpty(value); Assert.Contains("OAuth", value!); Assert.Contains("oauth_signature=\"" + OAuthTools.UrlEncodeStrict("&"), value); diff --git a/test/RestSharp.Tests/OAuthTests.cs b/test/RestSharp.Tests/OAuthTests.cs index 867ab74c7..4f2f94051 100644 --- a/test/RestSharp.Tests/OAuthTests.cs +++ b/test/RestSharp.Tests/OAuthTests.cs @@ -57,7 +57,7 @@ public void PercentEncode_Encodes_Correctly(string value, string expected) { [InlineData("", 2048)] [InlineData(" !\"#$%&'()*+,", 2048)] public void RsaSha1_Signs_Correctly(string value, int keySize) { - var hasher = new SHA1Managed(); + var hasher = SHA1.Create(); var hash = hasher.ComputeHash(value.GetBytes()); using var crypto = new RSACryptoServiceProvider(keySize) { PersistKeyInCsp = false }; diff --git a/test/RestSharp.Tests/StringExtensionsTests.cs b/test/RestSharp.Tests/StringExtensionsTests.cs index d86be1886..045be6d9f 100644 --- a/test/RestSharp.Tests/StringExtensionsTests.cs +++ b/test/RestSharp.Tests/StringExtensionsTests.cs @@ -7,8 +7,8 @@ namespace RestSharp.Tests; public class StringExtensionsTests { [Fact] public void UrlEncode_Throws_ArgumentNullException_For_Null_Input() { - string? nullString = null; - + string nullString = null; + // ReSharper disable once ExpressionIsAlwaysNull Assert.Throws(() => nullString!.UrlEncode()); } @@ -70,24 +70,4 @@ public void ToCamelCase(string start, string finish) { Assert.Equal(finish, result); } - - [Fact] - public void Does_not_throw_on_invalid_encoding() { - const string value = "SomeValue"; - - var bytes = Encoding.UTF8.GetBytes(value); - - var decoded = bytes.AsString("blah"); - decoded.Should().Be(value); - } - - [Fact] - public void Does_not_throw_on_missing_encoding() { - const string value = "SomeValue"; - - var bytes = Encoding.UTF8.GetBytes(value); - - var decoded = bytes.AsString(null); - decoded.Should().Be(value); - } } \ No newline at end of file From 08ff3c6377496503945100bca5270bea269fb89a Mon Sep 17 00:00:00 2001 From: Alexey Zimarev Date: Tue, 14 Dec 2021 12:38:10 +0100 Subject: [PATCH 04/10] Fixing more warnings --- .../JsonNetSerializer.cs | 2 + .../Xml/XmlAttributeDeserializer.cs | 2 +- .../Serializers/Xml/XmlDeserializer.cs | 40 +++++++++---------- .../Serializers/Xml/XmlExtensions.cs | 4 +- .../Serializers/Xml/XmlSerializer.cs | 10 ++--- .../RestSharp.InteractiveTests.csproj | 2 +- .../RestSharp.Serializers.Json.Tests.csproj | 3 -- .../RestSharp.Serializers.Xml.Tests.csproj | 7 ---- .../OAuth1AuthenticatorTests.cs | 2 - test/RestSharp.Tests/RestSharp.Tests.csproj | 3 -- 10 files changed, 31 insertions(+), 44 deletions(-) diff --git a/src/RestSharp.Serializers.NewtonsoftJson/JsonNetSerializer.cs b/src/RestSharp.Serializers.NewtonsoftJson/JsonNetSerializer.cs index ce9ca6a34..067db9377 100644 --- a/src/RestSharp.Serializers.NewtonsoftJson/JsonNetSerializer.cs +++ b/src/RestSharp.Serializers.NewtonsoftJson/JsonNetSerializer.cs @@ -48,6 +48,8 @@ public class JsonNetSerializer : IRestSerializer { public string? Serialize(Parameter bodyParameter) => Serialize(bodyParameter.Value); public T? Deserialize(RestResponse response) { + if (response.Content == null) + throw new DeserializationException(response, new InvalidOperationException("Response content is null")); using var reader = new JsonTextReader(new StringReader(response.Content)) { CloseInput = true }; return _serializer.Deserialize(reader); diff --git a/src/RestSharp/Serializers/Xml/XmlAttributeDeserializer.cs b/src/RestSharp/Serializers/Xml/XmlAttributeDeserializer.cs index 768d88fdd..222c2d96e 100644 --- a/src/RestSharp/Serializers/Xml/XmlAttributeDeserializer.cs +++ b/src/RestSharp/Serializers/Xml/XmlAttributeDeserializer.cs @@ -5,7 +5,7 @@ namespace RestSharp.Serializers.Xml; public class XmlAttributeDeserializer : XmlDeserializer { - protected override object? GetValueFromXml(XElement? root, XName name, PropertyInfo prop, bool useExactName) { + protected override object? GetValueFromXml(XElement? root, XName? name, PropertyInfo prop, bool useExactName) { var isAttribute = false; //Check for the DeserializeAs attribute on the property diff --git a/src/RestSharp/Serializers/Xml/XmlDeserializer.cs b/src/RestSharp/Serializers/Xml/XmlDeserializer.cs index cb581476d..7f477b788 100644 --- a/src/RestSharp/Serializers/Xml/XmlDeserializer.cs +++ b/src/RestSharp/Serializers/Xml/XmlDeserializer.cs @@ -88,7 +88,7 @@ protected virtual object Map(object x, XElement? root) { var attribute = (DeserializeAsAttribute)attributes.First(); name = attribute.Name!.AsNamespaced(Namespace); - isNameDefinedInAttribute = !string.IsNullOrEmpty(name.LocalName); + isNameDefinedInAttribute = !string.IsNullOrEmpty(name?.LocalName); deserializeFromContent = attribute.Content; @@ -335,7 +335,7 @@ object HandleListDerivative(XElement root, string propName, Type type) { // get properties too, not just list items // only if this isn't a generic type if (!type.IsGenericType) - Map(list, root.Element(propName.AsNamespaced(Namespace)) ?? root); + Map(list, root.Element(propName.AsNamespaced(Namespace)!) ?? root); return list; } @@ -357,7 +357,7 @@ object HandleListDerivative(XElement root, string propName, Type type) { return item; } - protected virtual object? GetValueFromXml(XElement? root, XName name, PropertyInfo prop, bool useExactName) { + protected virtual object? GetValueFromXml(XElement? root, XName? name, PropertyInfo prop, bool useExactName) { object? val = null; if (root == null) return val; @@ -377,18 +377,18 @@ object HandleListDerivative(XElement root, string propName, Type type) { return val; } - protected virtual XElement? GetElementByName(XElement? root, XName name) { - var lowerName = name.LocalName.ToLower(Culture).AsNamespaced(name.NamespaceName); - var camelName = name.LocalName.ToCamelCase(Culture).AsNamespaced(name.NamespaceName); + protected virtual XElement? GetElementByName(XElement? root, XName? name) { + var lowerName = name?.LocalName.ToLower(Culture).AsNamespaced(name.NamespaceName); + var camelName = name?.LocalName.ToCamelCase(Culture).AsNamespaced(name.NamespaceName); - if (root?.Element(name) != null) - return root.Element(name); + if (root?.Element(name!) != null) + return root.Element(name!); - if (root?.Element(lowerName) != null) - return root.Element(lowerName); + if (root?.Element(lowerName!) != null) + return root.Element(lowerName!); - if (root?.Element(camelName) != null) - return root.Element(camelName); + if (root?.Element(camelName!) != null) + return root.Element(camelName!); // try looking for element that matches sanitized property name (Order by depth) var orderedDescendants = root?.Descendants() @@ -396,31 +396,31 @@ object HandleListDerivative(XElement root, string propName, Type type) { .ToList() ?? new List(); var element = orderedDescendants - .FirstOrDefault(d => d.Name.LocalName.RemoveUnderscoresAndDashes() == name.LocalName) ?? + .FirstOrDefault(d => d.Name.LocalName.RemoveUnderscoresAndDashes() == name?.LocalName) ?? orderedDescendants .FirstOrDefault( d => string.Equals( d.Name.LocalName.RemoveUnderscoresAndDashes(), - name.LocalName, + name?.LocalName, StringComparison.OrdinalIgnoreCase ) ); return element == null && - name == "Value".AsNamespaced(name.NamespaceName) && root != null && + name == "Value".AsNamespaced(name?.NamespaceName) && root != null && (root.HasAttributes || root.Attributes().All(x => x.Name != name)) ? root : element; } - protected virtual XAttribute? GetAttributeByName(XElement root, XName name, bool useExactName) { + protected virtual XAttribute? GetAttributeByName(XElement root, XName? name, bool useExactName) { var names = useExactName ? null - : new List { - name.LocalName, - name.LocalName.ToLower(Culture) + : new List { + name?.LocalName, + name?.LocalName.ToLower(Culture) .AsNamespaced(name.NamespaceName), - name.LocalName.ToCamelCase(Culture) + name?.LocalName.ToCamelCase(Culture) .AsNamespaced(name.NamespaceName) }; diff --git a/src/RestSharp/Serializers/Xml/XmlExtensions.cs b/src/RestSharp/Serializers/Xml/XmlExtensions.cs index 2c619f523..1834a2165 100644 --- a/src/RestSharp/Serializers/Xml/XmlExtensions.cs +++ b/src/RestSharp/Serializers/Xml/XmlExtensions.cs @@ -13,8 +13,8 @@ public static class XmlExtensions { /// Element name /// XML Namespace /// - public static XName AsNamespaced(this string? name, string? @namespace) { - XName xName = Ensure.NotNull(name, nameof(name)); + public static XName? AsNamespaced(this string? name, string? @namespace) { + XName? xName = name; if (name != null && @namespace.IsNotEmpty()) xName = XName.Get(name, @namespace!); diff --git a/src/RestSharp/Serializers/Xml/XmlSerializer.cs b/src/RestSharp/Serializers/Xml/XmlSerializer.cs index c2c8ccff1..fdf27ea2f 100644 --- a/src/RestSharp/Serializers/Xml/XmlSerializer.cs +++ b/src/RestSharp/Serializers/Xml/XmlSerializer.cs @@ -35,7 +35,7 @@ public string Serialize(object obj) { if (options != null) name = options.TransformName(options.Name ?? name); - var root = new XElement(name.AsNamespaced(Namespace)); + var root = new XElement(name.AsNamespaced(Namespace)!); if (obj is IList list) { var itemTypeName = ""; @@ -50,7 +50,7 @@ public string Serialize(object obj) { if (itemTypeName == "") itemTypeName = type.Name; - var instance = new XElement(itemTypeName.AsNamespaced(Namespace)); + var instance = new XElement(itemTypeName.AsNamespaced(Namespace)!); Map(instance, item); root.Add(instance); @@ -61,7 +61,7 @@ public string Serialize(object obj) { } if (RootElement != null) { - var wrapper = new XElement(RootElement.AsNamespaced(Namespace), root); + var wrapper = new XElement(RootElement.AsNamespaced(Namespace)!, root); doc.Add(wrapper); } else { @@ -135,7 +135,7 @@ void Map(XContainer root, object obj) { } var nsName = name.AsNamespaced(Namespace); - var element = new XElement(nsName); + var element = new XElement(nsName!); if (propType.GetTypeInfo().IsPrimitive || propType.GetTypeInfo().IsValueType || @@ -163,7 +163,7 @@ void Map(XContainer root, object obj) { ? setting.Name : type.Name; - var instance = new XElement(itemTypeName!.AsNamespaced(Namespace)); + var instance = new XElement(itemTypeName!.AsNamespaced(Namespace)!); Map(instance, item); diff --git a/test/RestSharp.InteractiveTests/RestSharp.InteractiveTests.csproj b/test/RestSharp.InteractiveTests/RestSharp.InteractiveTests.csproj index 0055c78bc..8b96e9ad2 100644 --- a/test/RestSharp.InteractiveTests/RestSharp.InteractiveTests.csproj +++ b/test/RestSharp.InteractiveTests/RestSharp.InteractiveTests.csproj @@ -1,7 +1,7 @@ Exe - net6.0 + false diff --git a/test/RestSharp.Serializers.Json.Tests/RestSharp.Serializers.Json.Tests.csproj b/test/RestSharp.Serializers.Json.Tests/RestSharp.Serializers.Json.Tests.csproj index a2ee248bb..eb6f293b6 100644 --- a/test/RestSharp.Serializers.Json.Tests/RestSharp.Serializers.Json.Tests.csproj +++ b/test/RestSharp.Serializers.Json.Tests/RestSharp.Serializers.Json.Tests.csproj @@ -1,7 +1,4 @@ - - net6.0 - diff --git a/test/RestSharp.Serializers.Xml.Tests/RestSharp.Serializers.Xml.Tests.csproj b/test/RestSharp.Serializers.Xml.Tests/RestSharp.Serializers.Xml.Tests.csproj index 615758042..c42ef984f 100644 --- a/test/RestSharp.Serializers.Xml.Tests/RestSharp.Serializers.Xml.Tests.csproj +++ b/test/RestSharp.Serializers.Xml.Tests/RestSharp.Serializers.Xml.Tests.csproj @@ -1,11 +1,4 @@ - - - net6.0 - enable - enable - - diff --git a/test/RestSharp.Tests/OAuth1AuthenticatorTests.cs b/test/RestSharp.Tests/OAuth1AuthenticatorTests.cs index e7266a971..a4b6191c9 100644 --- a/test/RestSharp.Tests/OAuth1AuthenticatorTests.cs +++ b/test/RestSharp.Tests/OAuth1AuthenticatorTests.cs @@ -179,8 +179,6 @@ public void Authenticate_ShouldEncodeOAuthTokenParameter(OAuthType type, string [Theory] [InlineData(OAuthType.AccessToken)] [InlineData(OAuthType.ProtectedResource)] - [InlineData(OAuthType.AccessToken)] - [InlineData(OAuthType.ProtectedResource)] public void Authenticate_ShouldAllowEmptyConsumerSecret_OnHttpAuthorizationHeaderHandling(OAuthType type) { // Arrange const string url = "https://no-query.string"; diff --git a/test/RestSharp.Tests/RestSharp.Tests.csproj b/test/RestSharp.Tests/RestSharp.Tests.csproj index 72cc9fd3d..f29aad0a5 100644 --- a/test/RestSharp.Tests/RestSharp.Tests.csproj +++ b/test/RestSharp.Tests/RestSharp.Tests.csproj @@ -1,7 +1,4 @@  - - net6.0 - From a184eca8e751b280e7dd0344ceeaec71571438cc Mon Sep 17 00:00:00 2001 From: Alexey Zimarev Date: Tue, 14 Dec 2021 13:34:31 +0100 Subject: [PATCH 05/10] Moved XML serializer out --- RestSharp.sln | 33 ++++++++++++++ .../DeserializeAsAttribute.cs | 3 +- .../RestSharp.Serializers.Xml.csproj | 11 +++++ .../SerializeAsAttribute.cs | 1 + .../XmlAttributeDeserializer.cs | 2 +- .../XmlDeserializer.cs | 44 +++++++++---------- .../XmlExtensions.cs | 0 .../XmlSerializer.cs | 0 .../XmlSerializerClientExtensions.cs | 38 ++++++++++++++++ src/RestSharp/Properties/AssemblyInfo.cs | 3 ++ .../Serializers/Xml/XmlRestSerializer.cs | 2 +- .../Fixtures/TestServer.cs | 2 +- .../MultipartFormDataTests.cs | 10 ++--- .../RestSharp.IntegrationTests/OAuth1Tests.cs | 4 +- .../ResourceStringParametersTests.cs | 2 +- .../RestSharp.IntegrationTests.csproj | 6 ++- .../NamespacedXmlTests.cs | 8 ++-- .../RestSharp.Serializers.Xml.Tests.csproj | 37 +++++++++------- .../SampleClasses/BearerToken.cs | 4 +- .../SampleClasses/BooleanTest.cs | 2 +- .../SampleClasses/ColorWithValue.cs | 4 +- .../SampleClasses/DeserializeAsTest/misc.cs | 4 +- .../SampleClasses/EmployeeTracker.cs | 2 +- .../SampleClasses/EnumTest.cs | 2 +- .../SampleClasses/Goodreads.cs | 2 +- .../GoogleWeatherWithAttributes.cs | 4 +- .../SampleClasses/HeaderAndRows.cs | 4 +- .../SampleClasses/JsonLists.cs | 2 +- .../SampleClasses/Lastfm.cs | 2 +- .../SampleClasses/ListSamples.cs | 2 +- .../SampleClasses/Oddball.cs | 4 +- .../SampleClasses/SOUser.cs | 2 +- .../SampleClasses/Struct.cs | 2 +- .../SampleClasses/TwilioCallList.cs | 2 +- .../SampleClasses/eventful.cs | 20 +-------- .../SampleClasses/foursq.cs | 2 +- .../SampleClasses/googleweather.cs | 2 +- .../SampleClasses/misc.cs | 4 +- .../SampleClasses/nullables.cs | 2 +- .../SampleClasses/twitter.cs | 4 +- .../XmlAttributeDeserializerTests.cs | 6 +-- .../XmlDeserializerTests.cs | 14 +++--- .../XmlSerializerTests.cs | 6 +-- .../Fixtures/WebServer.cs | 10 ++++- .../RestSharp.Tests/Fixtures/CultureChange.cs | 23 ---------- test/RestSharp.Tests/JwtAuthTests.cs | 2 +- test/RestSharp.Tests/RestSharp.Tests.csproj | 3 ++ 47 files changed, 192 insertions(+), 156 deletions(-) rename src/{RestSharp/Serializers => RestSharp.Serializers.Xml}/DeserializeAsAttribute.cs (90%) create mode 100644 src/RestSharp.Serializers.Xml/RestSharp.Serializers.Xml.csproj rename src/{RestSharp/Serializers => RestSharp.Serializers.Xml}/SerializeAsAttribute.cs (98%) rename src/{RestSharp/Serializers/Xml => RestSharp.Serializers.Xml}/XmlAttributeDeserializer.cs (91%) rename src/{RestSharp/Serializers/Xml => RestSharp.Serializers.Xml}/XmlDeserializer.cs (91%) rename src/{RestSharp/Serializers/Xml => RestSharp.Serializers.Xml}/XmlExtensions.cs (100%) rename src/{RestSharp/Serializers/Xml => RestSharp.Serializers.Xml}/XmlSerializer.cs (100%) create mode 100644 src/RestSharp.Serializers.Xml/XmlSerializerClientExtensions.cs delete mode 100644 test/RestSharp.Tests/Fixtures/CultureChange.cs diff --git a/RestSharp.sln b/RestSharp.sln index 83b6d020b..2f893b3ac 100644 --- a/RestSharp.sln +++ b/RestSharp.sln @@ -27,6 +27,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RestSharp.InteractiveTests" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RestSharp.Serializers.Xml.Tests", "test\RestSharp.Serializers.Xml.Tests\RestSharp.Serializers.Xml.Tests.csproj", "{E6D94C12-9AD7-46E6-AB62-3676F25FDE51}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RestSharp.Serializers.Xml", "src\RestSharp.Serializers.Xml\RestSharp.Serializers.Xml.csproj", "{4A35B1C5-520D-4267-BA70-2DCEAC0A5662}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug.Appveyor|Any CPU = Debug.Appveyor|Any CPU @@ -316,6 +318,36 @@ Global {E6D94C12-9AD7-46E6-AB62-3676F25FDE51}.Release|x64.Build.0 = Release|Any CPU {E6D94C12-9AD7-46E6-AB62-3676F25FDE51}.Release|x86.ActiveCfg = Release|Any CPU {E6D94C12-9AD7-46E6-AB62-3676F25FDE51}.Release|x86.Build.0 = Release|Any CPU + {4A35B1C5-520D-4267-BA70-2DCEAC0A5662}.Debug.Appveyor|Any CPU.ActiveCfg = Debug|Any CPU + {4A35B1C5-520D-4267-BA70-2DCEAC0A5662}.Debug.Appveyor|Any CPU.Build.0 = Debug|Any CPU + {4A35B1C5-520D-4267-BA70-2DCEAC0A5662}.Debug.Appveyor|ARM.ActiveCfg = Debug|Any CPU + {4A35B1C5-520D-4267-BA70-2DCEAC0A5662}.Debug.Appveyor|ARM.Build.0 = Debug|Any CPU + {4A35B1C5-520D-4267-BA70-2DCEAC0A5662}.Debug.Appveyor|Mixed Platforms.ActiveCfg = Debug|Any CPU + {4A35B1C5-520D-4267-BA70-2DCEAC0A5662}.Debug.Appveyor|Mixed Platforms.Build.0 = Debug|Any CPU + {4A35B1C5-520D-4267-BA70-2DCEAC0A5662}.Debug.Appveyor|x64.ActiveCfg = Debug|Any CPU + {4A35B1C5-520D-4267-BA70-2DCEAC0A5662}.Debug.Appveyor|x64.Build.0 = Debug|Any CPU + {4A35B1C5-520D-4267-BA70-2DCEAC0A5662}.Debug.Appveyor|x86.ActiveCfg = Debug|Any CPU + {4A35B1C5-520D-4267-BA70-2DCEAC0A5662}.Debug.Appveyor|x86.Build.0 = Debug|Any CPU + {4A35B1C5-520D-4267-BA70-2DCEAC0A5662}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4A35B1C5-520D-4267-BA70-2DCEAC0A5662}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4A35B1C5-520D-4267-BA70-2DCEAC0A5662}.Debug|ARM.ActiveCfg = Debug|Any CPU + {4A35B1C5-520D-4267-BA70-2DCEAC0A5662}.Debug|ARM.Build.0 = Debug|Any CPU + {4A35B1C5-520D-4267-BA70-2DCEAC0A5662}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {4A35B1C5-520D-4267-BA70-2DCEAC0A5662}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {4A35B1C5-520D-4267-BA70-2DCEAC0A5662}.Debug|x64.ActiveCfg = Debug|Any CPU + {4A35B1C5-520D-4267-BA70-2DCEAC0A5662}.Debug|x64.Build.0 = Debug|Any CPU + {4A35B1C5-520D-4267-BA70-2DCEAC0A5662}.Debug|x86.ActiveCfg = Debug|Any CPU + {4A35B1C5-520D-4267-BA70-2DCEAC0A5662}.Debug|x86.Build.0 = Debug|Any CPU + {4A35B1C5-520D-4267-BA70-2DCEAC0A5662}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4A35B1C5-520D-4267-BA70-2DCEAC0A5662}.Release|Any CPU.Build.0 = Release|Any CPU + {4A35B1C5-520D-4267-BA70-2DCEAC0A5662}.Release|ARM.ActiveCfg = Release|Any CPU + {4A35B1C5-520D-4267-BA70-2DCEAC0A5662}.Release|ARM.Build.0 = Release|Any CPU + {4A35B1C5-520D-4267-BA70-2DCEAC0A5662}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {4A35B1C5-520D-4267-BA70-2DCEAC0A5662}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {4A35B1C5-520D-4267-BA70-2DCEAC0A5662}.Release|x64.ActiveCfg = Release|Any CPU + {4A35B1C5-520D-4267-BA70-2DCEAC0A5662}.Release|x64.Build.0 = Release|Any CPU + {4A35B1C5-520D-4267-BA70-2DCEAC0A5662}.Release|x86.ActiveCfg = Release|Any CPU + {4A35B1C5-520D-4267-BA70-2DCEAC0A5662}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -332,5 +364,6 @@ Global {997AEFE5-D7D4-4033-A31A-07F476D6FE5D} = {1C42C435-8826-4044-8775-A1DA40EF4866} {6D7D1D60-4473-4C52-800C-9B892C6640A5} = {9051DDA0-E563-45D5-9504-085EBAACF469} {E6D94C12-9AD7-46E6-AB62-3676F25FDE51} = {9051DDA0-E563-45D5-9504-085EBAACF469} + {4A35B1C5-520D-4267-BA70-2DCEAC0A5662} = {8C7B43EB-2F93-483C-B433-E28F9386AD67} EndGlobalSection EndGlobal diff --git a/src/RestSharp/Serializers/DeserializeAsAttribute.cs b/src/RestSharp.Serializers.Xml/DeserializeAsAttribute.cs similarity index 90% rename from src/RestSharp/Serializers/DeserializeAsAttribute.cs rename to src/RestSharp.Serializers.Xml/DeserializeAsAttribute.cs index 39f97984d..29d2d486b 100644 --- a/src/RestSharp/Serializers/DeserializeAsAttribute.cs +++ b/src/RestSharp.Serializers.Xml/DeserializeAsAttribute.cs @@ -1,4 +1,5 @@ -namespace RestSharp.Serializers; +// ReSharper disable once CheckNamespace +namespace RestSharp.Serializers; /// /// Allows control how class and property names and values are deserialized by XmlAttributeDeserializer diff --git a/src/RestSharp.Serializers.Xml/RestSharp.Serializers.Xml.csproj b/src/RestSharp.Serializers.Xml/RestSharp.Serializers.Xml.csproj new file mode 100644 index 000000000..f0455ce76 --- /dev/null +++ b/src/RestSharp.Serializers.Xml/RestSharp.Serializers.Xml.csproj @@ -0,0 +1,11 @@ + + + + RestSharp.Serializers.Xml + + + + + + + diff --git a/src/RestSharp/Serializers/SerializeAsAttribute.cs b/src/RestSharp.Serializers.Xml/SerializeAsAttribute.cs similarity index 98% rename from src/RestSharp/Serializers/SerializeAsAttribute.cs rename to src/RestSharp.Serializers.Xml/SerializeAsAttribute.cs index 7e43a6ec8..28b330784 100644 --- a/src/RestSharp/Serializers/SerializeAsAttribute.cs +++ b/src/RestSharp.Serializers.Xml/SerializeAsAttribute.cs @@ -1,6 +1,7 @@ using System.Globalization; using RestSharp.Extensions; +// ReSharper disable once CheckNamespace namespace RestSharp.Serializers; /// diff --git a/src/RestSharp/Serializers/Xml/XmlAttributeDeserializer.cs b/src/RestSharp.Serializers.Xml/XmlAttributeDeserializer.cs similarity index 91% rename from src/RestSharp/Serializers/Xml/XmlAttributeDeserializer.cs rename to src/RestSharp.Serializers.Xml/XmlAttributeDeserializer.cs index 222c2d96e..a314bdb25 100644 --- a/src/RestSharp/Serializers/Xml/XmlAttributeDeserializer.cs +++ b/src/RestSharp.Serializers.Xml/XmlAttributeDeserializer.cs @@ -18,7 +18,7 @@ public class XmlAttributeDeserializer : XmlDeserializer { if (!isAttribute) return base.GetValueFromXml(root, name, prop, useExactName); - var attributeVal = GetAttributeByName(root!, name, useExactName); + var attributeVal = GetAttributeByName(root!, name!, useExactName); return attributeVal?.Value ?? base.GetValueFromXml(root, name, prop, useExactName); } diff --git a/src/RestSharp/Serializers/Xml/XmlDeserializer.cs b/src/RestSharp.Serializers.Xml/XmlDeserializer.cs similarity index 91% rename from src/RestSharp/Serializers/Xml/XmlDeserializer.cs rename to src/RestSharp.Serializers.Xml/XmlDeserializer.cs index 7f477b788..b59ff4b91 100644 --- a/src/RestSharp/Serializers/Xml/XmlDeserializer.cs +++ b/src/RestSharp.Serializers.Xml/XmlDeserializer.cs @@ -1,4 +1,4 @@ -using System.Collections; +using System.Collections; using System.ComponentModel; using System.Globalization; using System.Reflection; @@ -23,7 +23,7 @@ public class XmlDeserializer : IXmlDeserializer { if (string.IsNullOrEmpty(response.Content)) return default; - var doc = XDocument.Parse(response.Content!); + var doc = XDocument.Parse(response.Content); var root = doc.Root; if (RootElement != null && doc.Root != null) @@ -87,16 +87,13 @@ protected virtual object Map(object x, XElement? root) { if (attributes.Any()) { var attribute = (DeserializeAsAttribute)attributes.First(); - name = attribute.Name!.AsNamespaced(Namespace); + name = attribute.Name.AsNamespaced(Namespace); isNameDefinedInAttribute = !string.IsNullOrEmpty(name?.LocalName); deserializeFromContent = attribute.Content; if (deserializeFromContentAttributeAlreadyUsed && deserializeFromContent) - throw new ArgumentException( - "Class cannot have two properties marked with " + - "SerializeAs(Content = true) attribute." - ); + throw new ArgumentException("Class cannot have two properties marked with SerializeAs(Content = true) attribute."); deserializeFromContentAttributeAlreadyUsed |= deserializeFromContent; } @@ -149,7 +146,8 @@ protected virtual object Map(object x, XElement? root) { var asType = type.AsType(); if (asType == typeof(bool)) { - var toConvert = value.ToString()!.ToLower(Culture); + var toConvert = value.ToString()! + .ToLower(Culture); prop.SetValue(x, XmlConvert.ToBoolean(toConvert), null); } @@ -302,17 +300,17 @@ object HandleListDerivative(XElement root, string propName, Type type) { var name = t.Name; var attribute = t.GetAttribute(); - if (attribute?.Name != null) + if (attribute != null) name = attribute.Name; if (!elements.Any()) { - var lowerName = name.ToLower(Culture).AsNamespaced(Namespace); + var lowerName = name?.ToLower(Culture).AsNamespaced(Namespace); elements = root.Descendants(lowerName).ToList(); } if (!elements.Any()) { - var camelName = name.ToCamelCase(Culture).AsNamespaced(Namespace); + var camelName = name?.ToCamelCase(Culture).AsNamespaced(Namespace); elements = root.Descendants(camelName).ToList(); } @@ -323,7 +321,7 @@ object HandleListDerivative(XElement root, string propName, Type type) { .ToList(); if (!elements.Any()) { - var lowerName = name.ToLower(Culture).AsNamespaced(Namespace); + var lowerName = name?.ToLower(Culture).AsNamespaced(Namespace); elements = root.Descendants() .Where(e => e.Name.LocalName.RemoveUnderscoresAndDashes() == lowerName) @@ -364,7 +362,7 @@ object HandleListDerivative(XElement root, string propName, Type type) { var element = GetElementByName(root, name); if (element == null) { - var attribute = GetAttributeByName(root, name, useExactName); + var attribute = GetAttributeByName(root, name!, useExactName); if (attribute != null) val = attribute.Value; @@ -391,9 +389,9 @@ object HandleListDerivative(XElement root, string propName, Type type) { return root.Element(camelName!); // try looking for element that matches sanitized property name (Order by depth) - var orderedDescendants = root?.Descendants() + var orderedDescendants = root!.Descendants() .OrderBy(d => d.Ancestors().Count()) - .ToList() ?? new List(); + .ToList(); var element = orderedDescendants .FirstOrDefault(d => d.Name.LocalName.RemoveUnderscoresAndDashes() == name?.LocalName) ?? @@ -407,21 +405,19 @@ object HandleListDerivative(XElement root, string propName, Type type) { ); return element == null && - name == "Value".AsNamespaced(name?.NamespaceName) && root != null && - (root.HasAttributes || root.Attributes().All(x => x.Name != name)) + name == "Value".AsNamespaced(name?.NamespaceName) && + (!root.HasAttributes || root.Attributes().All(x => x.Name != name)) ? root : element; } - protected virtual XAttribute? GetAttributeByName(XElement root, XName? name, bool useExactName) { + protected virtual XAttribute? GetAttributeByName(XElement root, XName name, bool useExactName) { var names = useExactName ? null - : new List { - name?.LocalName, - name?.LocalName.ToLower(Culture) - .AsNamespaced(name.NamespaceName), - name?.LocalName.ToCamelCase(Culture) - .AsNamespaced(name.NamespaceName) + : new List { + name.LocalName, + name.LocalName.ToLower(Culture).AsNamespaced(name.NamespaceName)!, + name.LocalName.ToCamelCase(Culture).AsNamespaced(name.NamespaceName)! }; return root.DescendantsAndSelf() diff --git a/src/RestSharp/Serializers/Xml/XmlExtensions.cs b/src/RestSharp.Serializers.Xml/XmlExtensions.cs similarity index 100% rename from src/RestSharp/Serializers/Xml/XmlExtensions.cs rename to src/RestSharp.Serializers.Xml/XmlExtensions.cs diff --git a/src/RestSharp/Serializers/Xml/XmlSerializer.cs b/src/RestSharp.Serializers.Xml/XmlSerializer.cs similarity index 100% rename from src/RestSharp/Serializers/Xml/XmlSerializer.cs rename to src/RestSharp.Serializers.Xml/XmlSerializer.cs diff --git a/src/RestSharp.Serializers.Xml/XmlSerializerClientExtensions.cs b/src/RestSharp.Serializers.Xml/XmlSerializerClientExtensions.cs new file mode 100644 index 000000000..c0ec75bcf --- /dev/null +++ b/src/RestSharp.Serializers.Xml/XmlSerializerClientExtensions.cs @@ -0,0 +1,38 @@ +// Copyright © 2009-2020 John Sheehan, Andrew Young, Alexey Zimarev and RestSharp community +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace RestSharp.Serializers.Xml; + +[PublicAPI] +public static class XmlSerializerClientExtensions { + public static RestClient UseXmlSerializer( + this RestClient restClient, + string? xmlNamespace = null, + string? rootElement = null, + bool useAttributeDeserializer = false + ) { + var xmlSerializer = new XmlSerializer { + Namespace = xmlNamespace, + RootElement = rootElement + }; + + var xmlDeserializer = useAttributeDeserializer ? new XmlAttributeDeserializer() : new XmlDeserializer(); + + var serializer = new XmlRestSerializer() + .WithXmlSerializer(xmlSerializer) + .WithXmlDeserializer(xmlDeserializer); + + return restClient.UseSerializer(() => serializer); + } +} \ No newline at end of file diff --git a/src/RestSharp/Properties/AssemblyInfo.cs b/src/RestSharp/Properties/AssemblyInfo.cs index 44d73bf55..cf7b969d5 100644 --- a/src/RestSharp/Properties/AssemblyInfo.cs +++ b/src/RestSharp/Properties/AssemblyInfo.cs @@ -6,5 +6,8 @@ ), InternalsVisibleTo( "RestSharp.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100fda57af14a288d46e3efea89617037585c4de57159cd536ca6dff792ea1d6addc665f2fccb4285413d9d44db5a1be87cb82686db200d16325ed9c42c89cd4824d8cc447f7cee2ac000924c3bceeb1b7fcb5cc1a3901785964d48ce14172001084134f4dcd9973c3776713b595443b1064bb53e2eeb924969244d354e46495e9d" + ), + InternalsVisibleTo( + "RestSharp.Serializers.Xml, PublicKey=0024000004800000940000000602000000240000525341310004000001000100fda57af14a288d46e3efea89617037585c4de57159cd536ca6dff792ea1d6addc665f2fccb4285413d9d44db5a1be87cb82686db200d16325ed9c42c89cd4824d8cc447f7cee2ac000924c3bceeb1b7fcb5cc1a3901785964d48ce14172001084134f4dcd9973c3776713b595443b1064bb53e2eeb924969244d354e46495e9d" )] [assembly: CLSCompliant(true)] \ No newline at end of file diff --git a/src/RestSharp/Serializers/Xml/XmlRestSerializer.cs b/src/RestSharp/Serializers/Xml/XmlRestSerializer.cs index ad50172ba..9bc55c6fa 100644 --- a/src/RestSharp/Serializers/Xml/XmlRestSerializer.cs +++ b/src/RestSharp/Serializers/Xml/XmlRestSerializer.cs @@ -21,7 +21,7 @@ public class XmlRestSerializer : IRestSerializer, IXmlSerializer, IXmlDeserializ IXmlDeserializer _xmlDeserializer; IXmlSerializer _xmlSerializer; - public XmlRestSerializer() : this(new XmlSerializer(), new XmlDeserializer()) { } + public XmlRestSerializer() : this(new DotNetXmlSerializer(), new DotNetXmlDeserializer()) { } public XmlRestSerializer(IXmlSerializer xmlSerializer, IXmlDeserializer xmlDeserializer) { _xmlDeserializer = xmlDeserializer; diff --git a/test/RestSharp.IntegrationTests/Fixtures/TestServer.cs b/test/RestSharp.IntegrationTests/Fixtures/TestServer.cs index d3b0a9742..0a4a74063 100644 --- a/test/RestSharp.IntegrationTests/Fixtures/TestServer.cs +++ b/test/RestSharp.IntegrationTests/Fixtures/TestServer.cs @@ -10,7 +10,7 @@ public class HttpServer { const string Address = "http://localhost:5151"; - public HttpServer(ITestOutputHelper? output = null) { + public HttpServer(ITestOutputHelper output = null) { var builder = WebApplication.CreateBuilder(); if (output != null) diff --git a/test/RestSharp.IntegrationTests/MultipartFormDataTests.cs b/test/RestSharp.IntegrationTests/MultipartFormDataTests.cs index 39dc5a512..6a5c79b0d 100644 --- a/test/RestSharp.IntegrationTests/MultipartFormDataTests.cs +++ b/test/RestSharp.IntegrationTests/MultipartFormDataTests.cs @@ -79,7 +79,7 @@ public async Task MultipartFormData() { AddParameters(request); - string? boundary = null; + string boundary = null; request.OnBeforeRequest += http => boundary = http.Content!.GetFormBoundary(); var response = await _client.ExecuteAsync(request); @@ -101,7 +101,7 @@ public async Task MultipartFormData_HasDefaultContentType() { request.AddParameter("controlName", "test", "application/json", ParameterType.RequestBody); - string? boundary = null; + string boundary = null; request.OnBeforeRequest = http => boundary = http.Content!.GetFormBoundary(); var response = await _client.ExecuteAsync(request); @@ -127,7 +127,7 @@ public async Task MultipartFormData_WithCustomContentType() { request.AddFile("fileName", path); request.AddParameter("controlName", "test", "application/json", ParameterType.RequestBody); - string? boundary = null; + string boundary = null; request.OnBeforeRequest = http => boundary = http.Content!.GetFormBoundary(); var response = await _client.ExecuteAsync(request); @@ -150,7 +150,7 @@ public async Task MultipartFormData_WithParameterAndFile_Async() { request.AddParameter("controlName", "test", "application/json", ParameterType.RequestBody); - string? boundary = null; + string boundary = null; request.OnBeforeRequest = http => boundary = http.Content!.GetFormBoundary(); var response = await _client.ExecuteAsync(request); @@ -166,7 +166,7 @@ public async Task MultipartFormDataAsync() { AddParameters(request); - string? boundary = null; + string boundary = null; request.OnBeforeRequest = http => boundary = http.Content!.GetFormBoundary(); diff --git a/test/RestSharp.IntegrationTests/OAuth1Tests.cs b/test/RestSharp.IntegrationTests/OAuth1Tests.cs index 194660d40..f27dbeab5 100644 --- a/test/RestSharp.IntegrationTests/OAuth1Tests.cs +++ b/test/RestSharp.IntegrationTests/OAuth1Tests.cs @@ -319,8 +319,8 @@ public async Task Can_Query_Vimeo() { Assert.NotNull(response); Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.NotNull(response.Content); - Assert.False(response.Content.Contains("\"stat\":\"fail\"")); - Assert.True(response.Content.Contains("\"stat\":\"ok\"")); + response.Content.Should().NotContain("\"stat\":\"fail\""); + response.Content.Should().Contain("\"stat\":\"ok\""); } [Fact(Skip = diff --git a/test/RestSharp.IntegrationTests/ResourceStringParametersTests.cs b/test/RestSharp.IntegrationTests/ResourceStringParametersTests.cs index b75894b45..eecbf6ccd 100644 --- a/test/RestSharp.IntegrationTests/ResourceStringParametersTests.cs +++ b/test/RestSharp.IntegrationTests/ResourceStringParametersTests.cs @@ -24,7 +24,7 @@ public async Task Should_keep_to_parameters_with_the_same_name() { } static class RequestHandler { - public static Uri? Url { get; private set; } + public static Uri Url { get; private set; } public static void Handle(HttpListenerContext context) { Url = context.Request.Url; diff --git a/test/RestSharp.IntegrationTests/RestSharp.IntegrationTests.csproj b/test/RestSharp.IntegrationTests/RestSharp.IntegrationTests.csproj index ff1cc94b9..cffe9a94f 100644 --- a/test/RestSharp.IntegrationTests/RestSharp.IntegrationTests.csproj +++ b/test/RestSharp.IntegrationTests/RestSharp.IntegrationTests.csproj @@ -1,5 +1,9 @@  + + disable + + @@ -12,6 +16,6 @@ - + \ No newline at end of file diff --git a/test/RestSharp.Serializers.Xml.Tests/NamespacedXmlTests.cs b/test/RestSharp.Serializers.Xml.Tests/NamespacedXmlTests.cs index 386ed6405..148fc9d93 100644 --- a/test/RestSharp.Serializers.Xml.Tests/NamespacedXmlTests.cs +++ b/test/RestSharp.Serializers.Xml.Tests/NamespacedXmlTests.cs @@ -1,10 +1,8 @@ using System.Xml.Linq; -using RestSharp.Serializers.Xml; -using RestSharp.Tests.SampleClasses; -using RestSharp.Tests.SampleClasses.DeserializeAsTest; -using RestSharp.Tests.SampleClasses.Lastfm; +using RestSharp.Serializers.Xml.Tests.SampleClasses; +using RestSharp.Serializers.Xml.Tests.SampleClasses.DeserializeAsTest; -namespace RestSharp.Tests; +namespace RestSharp.Serializers.Xml.Tests; public class NamespacedXmlTests { const string GuidString = "AC1FC4BC-087A-4242-B8EE-C53EBE9887A5"; diff --git a/test/RestSharp.Serializers.Xml.Tests/RestSharp.Serializers.Xml.Tests.csproj b/test/RestSharp.Serializers.Xml.Tests/RestSharp.Serializers.Xml.Tests.csproj index c42ef984f..a121cfbc1 100644 --- a/test/RestSharp.Serializers.Xml.Tests/RestSharp.Serializers.Xml.Tests.csproj +++ b/test/RestSharp.Serializers.Xml.Tests/RestSharp.Serializers.Xml.Tests.csproj @@ -1,24 +1,27 @@ + + disable + - + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/BearerToken.cs b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/BearerToken.cs index 02a03d1d6..0c858ec19 100644 --- a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/BearerToken.cs +++ b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/BearerToken.cs @@ -1,6 +1,4 @@ -using RestSharp.Serializers; - -namespace RestSharp.Tests.SampleClasses; +namespace RestSharp.Serializers.Xml.Tests.SampleClasses; public class BearerToken { public string AccessToken { get; set; } diff --git a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/BooleanTest.cs b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/BooleanTest.cs index 9944aa4df..8e8bec8c8 100644 --- a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/BooleanTest.cs +++ b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/BooleanTest.cs @@ -1,4 +1,4 @@ -namespace RestSharp.Tests.SampleClasses; +namespace RestSharp.Serializers.Xml.Tests.SampleClasses; public class BooleanTest { public bool Value { get; set; } diff --git a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/ColorWithValue.cs b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/ColorWithValue.cs index d4c4bc245..c7411c903 100644 --- a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/ColorWithValue.cs +++ b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/ColorWithValue.cs @@ -1,6 +1,4 @@ -using RestSharp.Serializers; - -namespace RestSharp.Tests.SampleClasses; +namespace RestSharp.Serializers.Xml.Tests.SampleClasses; [DeserializeAs(Name = "Color")] public class ColorWithValue { diff --git a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/DeserializeAsTest/misc.cs b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/DeserializeAsTest/misc.cs index 0bf8ce704..60cbaa244 100644 --- a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/DeserializeAsTest/misc.cs +++ b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/DeserializeAsTest/misc.cs @@ -1,6 +1,4 @@ -using RestSharp.Serializers; - -namespace RestSharp.Tests.SampleClasses.DeserializeAsTest; +namespace RestSharp.Serializers.Xml.Tests.SampleClasses.DeserializeAsTest; public class NodeWithAttributeAndValue { [DeserializeAs(Name = "attribute-value", Attribute = true)] diff --git a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/EmployeeTracker.cs b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/EmployeeTracker.cs index 9d6fdb5dc..ae33edc94 100644 --- a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/EmployeeTracker.cs +++ b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/EmployeeTracker.cs @@ -1,4 +1,4 @@ -namespace RestSharp.Tests.SampleClasses; +namespace RestSharp.Serializers.Xml.Tests.SampleClasses; public class EmployeeTracker { /// diff --git a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/EnumTest.cs b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/EnumTest.cs index ea5d85d39..12439e94c 100644 --- a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/EnumTest.cs +++ b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/EnumTest.cs @@ -1,4 +1,4 @@ -namespace RestSharp.Tests.SampleClasses; +namespace RestSharp.Serializers.Xml.Tests.SampleClasses; public enum ByteEnum : byte { EnumMin = 0, EnumMax = 255 } diff --git a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/Goodreads.cs b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/Goodreads.cs index dcb257005..1f06ffcc2 100644 --- a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/Goodreads.cs +++ b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/Goodreads.cs @@ -1,4 +1,4 @@ -namespace RestSharp.Tests.SampleClasses; +namespace RestSharp.Serializers.Xml.Tests.SampleClasses; public class GoodReadsReviewCollection { public int Start { get; set; } diff --git a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/GoogleWeatherWithAttributes.cs b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/GoogleWeatherWithAttributes.cs index 2045a7da7..2b702cbdd 100644 --- a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/GoogleWeatherWithAttributes.cs +++ b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/GoogleWeatherWithAttributes.cs @@ -1,6 +1,4 @@ -using RestSharp.Serializers; - -namespace RestSharp.Tests.SampleClasses; +namespace RestSharp.Serializers.Xml.Tests.SampleClasses; public class GoogleWeatherApi { public string Version { get; set; } diff --git a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/HeaderAndRows.cs b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/HeaderAndRows.cs index 80afef944..1d3339f49 100644 --- a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/HeaderAndRows.cs +++ b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/HeaderAndRows.cs @@ -1,6 +1,4 @@ -using RestSharp.Serializers; - -namespace RestSharp.Tests.SampleClasses; +namespace RestSharp.Serializers.Xml.Tests.SampleClasses; public class Header { public string Title { get; set; } diff --git a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/JsonLists.cs b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/JsonLists.cs index 0c5437871..d1e016882 100644 --- a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/JsonLists.cs +++ b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/JsonLists.cs @@ -1,4 +1,4 @@ -namespace RestSharp.Tests.SampleClasses; +namespace RestSharp.Serializers.Xml.Tests.SampleClasses; public class JsonLists { public List Names { get; set; } diff --git a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/Lastfm.cs b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/Lastfm.cs index f8778d119..75fb02730 100644 --- a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/Lastfm.cs +++ b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/Lastfm.cs @@ -1,4 +1,4 @@ -namespace RestSharp.Tests.SampleClasses.Lastfm; +namespace RestSharp.Serializers.Xml.Tests.SampleClasses; public class Event : LastfmBase { public string id { get; set; } diff --git a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/ListSamples.cs b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/ListSamples.cs index c1d7cef91..c214b7008 100644 --- a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/ListSamples.cs +++ b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/ListSamples.cs @@ -1,4 +1,4 @@ -namespace RestSharp.Tests.SampleClasses; +namespace RestSharp.Serializers.Xml.Tests.SampleClasses; public class SimpleTypesListSample { public List Names { get; set; } diff --git a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/Oddball.cs b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/Oddball.cs index 63a56ad6f..3eef8c02a 100644 --- a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/Oddball.cs +++ b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/Oddball.cs @@ -1,6 +1,4 @@ -using RestSharp.Serializers; - -namespace RestSharp.Tests.SampleClasses; +namespace RestSharp.Serializers.Xml.Tests.SampleClasses; [DeserializeAs(Name = "oddballRootName")] public class Oddball { diff --git a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/SOUser.cs b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/SOUser.cs index af2afa67e..90901f617 100644 --- a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/SOUser.cs +++ b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/SOUser.cs @@ -1,4 +1,4 @@ -namespace RestSharp.Tests.SampleClasses; +namespace RestSharp.Serializers.Xml.Tests.SampleClasses; public class SoUser { public int Id { get; set; } diff --git a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/Struct.cs b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/Struct.cs index 510cc4e36..3965c5a5d 100644 --- a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/Struct.cs +++ b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/Struct.cs @@ -1,4 +1,4 @@ -namespace RestSharp.Tests.SampleClasses; +namespace RestSharp.Serializers.Xml.Tests.SampleClasses; public struct SimpleStruct { public string One { get; set; } diff --git a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/TwilioCallList.cs b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/TwilioCallList.cs index d3cc9c6df..f3e3c3d1b 100644 --- a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/TwilioCallList.cs +++ b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/TwilioCallList.cs @@ -1,4 +1,4 @@ -namespace RestSharp.Tests.SampleClasses; +namespace RestSharp.Serializers.Xml.Tests.SampleClasses; public class TwilioCallList : List { public int Page { get; set; } diff --git a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/eventful.cs b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/eventful.cs index 3489c313e..820d514bf 100644 --- a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/eventful.cs +++ b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/eventful.cs @@ -1,4 +1,4 @@ -namespace RestSharp.Tests.SampleClasses; +namespace RestSharp.Serializers.Xml.Tests.SampleClasses; public class VenueSearch { public string total_items { get; set; } @@ -106,22 +106,4 @@ public class ServiceImage1 { public string width { get; set; } public string height { get; set; } -} - -public class Event { - public string id { get; set; } - - public string url { get; set; } - - public string title { get; set; } - - public string description { get; set; } - - public string start_time { get; set; } - - public string venue_name { get; set; } - - public string venue_id { get; set; } - - public List performers { get; set; } } \ No newline at end of file diff --git a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/foursq.cs b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/foursq.cs index ac6ecb80b..a362c0634 100644 --- a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/foursq.cs +++ b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/foursq.cs @@ -1,4 +1,4 @@ -namespace RestSharp.Tests.SampleClasses; +namespace RestSharp.Serializers.Xml.Tests.SampleClasses; public class VenuesResponse { public List Groups { get; set; } diff --git a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/googleweather.cs b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/googleweather.cs index 7b0b893ad..25c8508ea 100644 --- a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/googleweather.cs +++ b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/googleweather.cs @@ -1,4 +1,4 @@ -namespace RestSharp.Tests.SampleClasses; +namespace RestSharp.Serializers.Xml.Tests.SampleClasses; public class xml_api_reply { public string version { get; set; } diff --git a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/misc.cs b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/misc.cs index 7ebf5de96..3ab733479 100644 --- a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/misc.cs +++ b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/misc.cs @@ -1,6 +1,4 @@ -using RestSharp.Serializers; - -namespace RestSharp.Tests.SampleClasses; +namespace RestSharp.Serializers.Xml.Tests.SampleClasses; public class PersonForXml { public string Name { get; set; } diff --git a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/nullables.cs b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/nullables.cs index a6b9c97f8..0b2b1ed14 100644 --- a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/nullables.cs +++ b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/nullables.cs @@ -1,4 +1,4 @@ -namespace RestSharp.Tests.SampleClasses; +namespace RestSharp.Serializers.Xml.Tests.SampleClasses; public class NullableValues { public int? Id { get; set; } diff --git a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/twitter.cs b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/twitter.cs index 050c0dbf2..75d6c6051 100644 --- a/test/RestSharp.Serializers.Xml.Tests/SampleClasses/twitter.cs +++ b/test/RestSharp.Serializers.Xml.Tests/SampleClasses/twitter.cs @@ -1,6 +1,4 @@ -using RestSharp.Serializers; - -namespace RestSharp.Tests.SampleClasses; +namespace RestSharp.Serializers.Xml.Tests.SampleClasses; public class status { public bool truncated { get; set; } diff --git a/test/RestSharp.Serializers.Xml.Tests/XmlAttributeDeserializerTests.cs b/test/RestSharp.Serializers.Xml.Tests/XmlAttributeDeserializerTests.cs index 2e63a0c72..99ae2a7ab 100644 --- a/test/RestSharp.Serializers.Xml.Tests/XmlAttributeDeserializerTests.cs +++ b/test/RestSharp.Serializers.Xml.Tests/XmlAttributeDeserializerTests.cs @@ -1,10 +1,8 @@ using System.Globalization; using System.Xml.Linq; -using RestSharp.Serializers.Xml; -using RestSharp.Tests.SampleClasses; -using Event = RestSharp.Tests.SampleClasses.Lastfm.Event; +using RestSharp.Serializers.Xml.Tests.SampleClasses; -namespace RestSharp.Tests; +namespace RestSharp.Serializers.Xml.Tests; public class XmlAttributeDeserializerTests { const string GuidString = "AC1FC4BC-087A-4242-B8EE-C53EBE9887A5"; diff --git a/test/RestSharp.Serializers.Xml.Tests/XmlDeserializerTests.cs b/test/RestSharp.Serializers.Xml.Tests/XmlDeserializerTests.cs index 69d696c6b..adb2cb32c 100644 --- a/test/RestSharp.Serializers.Xml.Tests/XmlDeserializerTests.cs +++ b/test/RestSharp.Serializers.Xml.Tests/XmlDeserializerTests.cs @@ -1,11 +1,9 @@ using System.Globalization; using System.Xml.Linq; -using RestSharp.Serializers.Xml; -using RestSharp.Tests.SampleClasses; -using RestSharp.Tests.SampleClasses.DeserializeAsTest; -using Event = RestSharp.Tests.SampleClasses.Lastfm.Event; +using RestSharp.Serializers.Xml.Tests.SampleClasses; +using RestSharp.Serializers.Xml.Tests.SampleClasses.DeserializeAsTest; -namespace RestSharp.Tests; +namespace RestSharp.Serializers.Xml.Tests; public class XmlDeserializerTests { const string GuidString = "AC1FC4BC-087A-4242-B8EE-C53EBE9887A5"; @@ -312,14 +310,14 @@ static string CreateXmlWithEmptyInlineList() { static string CreateXmlWithAttributesAndNullValues() { var doc = new XDocument(); var root = new XElement("NullableValues"); - var idElement = new XElement("Id", null); + var idElement = new XElement("Id", null!); idElement.SetAttributeValue("SomeAttribute", "SomeAttribute_Value"); root.Add( idElement, - new XElement("StartDate", null), - new XElement("UniqueId", null) + new XElement("StartDate", null!), + new XElement("UniqueId", null!) ); doc.Add(root); diff --git a/test/RestSharp.Serializers.Xml.Tests/XmlSerializerTests.cs b/test/RestSharp.Serializers.Xml.Tests/XmlSerializerTests.cs index 9448800da..c3db38ae7 100644 --- a/test/RestSharp.Serializers.Xml.Tests/XmlSerializerTests.cs +++ b/test/RestSharp.Serializers.Xml.Tests/XmlSerializerTests.cs @@ -1,10 +1,8 @@ using System.Globalization; using System.Xml.Linq; -using RestSharp.Serializers; -using RestSharp.Serializers.Xml; -using RestSharp.Tests.SampleClasses; +using RestSharp.Serializers.Xml.Tests.SampleClasses; -namespace RestSharp.Tests; +namespace RestSharp.Serializers.Xml.Tests; public class XmlSerializerTests { public XmlSerializerTests() { diff --git a/test/RestSharp.Tests.Shared/Fixtures/WebServer.cs b/test/RestSharp.Tests.Shared/Fixtures/WebServer.cs index cbd4f4673..84f8865cf 100644 --- a/test/RestSharp.Tests.Shared/Fixtures/WebServer.cs +++ b/test/RestSharp.Tests.Shared/Fixtures/WebServer.cs @@ -42,7 +42,15 @@ public async Task Run(CancellationToken token) { Task GetContextAsync() => taskFactory.FromAsync( (callback, state) => ((HttpListener)state!).BeginGetContext(callback, state), - iar => ((HttpListener)iar.AsyncState!).EndGetContext(iar), + iar => { + try { + return ((HttpListener)iar.AsyncState!).EndGetContext(iar); + } + catch (HttpListenerException e) { + // it's ok + return null; + } + }, _listener ); } diff --git a/test/RestSharp.Tests/Fixtures/CultureChange.cs b/test/RestSharp.Tests/Fixtures/CultureChange.cs deleted file mode 100644 index e6abe3d29..000000000 --- a/test/RestSharp.Tests/Fixtures/CultureChange.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.Globalization; - -namespace RestSharp.Tests.Fixtures; - -public class CultureChange : IDisposable { - public CultureChange(string culture) { - Ensure.NotEmpty(culture, nameof(culture)); - - PreviousCulture = Thread.CurrentThread.CurrentCulture; - - Thread.CurrentThread.CurrentCulture = new CultureInfo(culture); - } - - public CultureInfo? PreviousCulture { get; private set; } - - public void Dispose() { - if (PreviousCulture == null) return; - - Thread.CurrentThread.CurrentCulture = PreviousCulture; - - PreviousCulture = null; - } -} \ No newline at end of file diff --git a/test/RestSharp.Tests/JwtAuthTests.cs b/test/RestSharp.Tests/JwtAuthTests.cs index c771fe03a..f7133b353 100644 --- a/test/RestSharp.Tests/JwtAuthTests.cs +++ b/test/RestSharp.Tests/JwtAuthTests.cs @@ -71,7 +71,7 @@ public void Set_Auth_Header_Only_Once() { var paramList = request.Parameters.Where(p => p.Name.Equals("Authorization")).ToList(); - Assert.Equal(1, paramList.Count); + paramList.Should().HaveCount(1); var authParam = paramList[0]; diff --git a/test/RestSharp.Tests/RestSharp.Tests.csproj b/test/RestSharp.Tests/RestSharp.Tests.csproj index f29aad0a5..9db982d04 100644 --- a/test/RestSharp.Tests/RestSharp.Tests.csproj +++ b/test/RestSharp.Tests/RestSharp.Tests.csproj @@ -25,4 +25,7 @@ + + + \ No newline at end of file From dc1babd3d64982ad6493fe00c561f03538a9e164 Mon Sep 17 00:00:00 2001 From: Alexey Zimarev Date: Tue, 14 Dec 2021 13:43:29 +0100 Subject: [PATCH 06/10] Use non-default XML serializer --- test/RestSharp.IntegrationTests/StatusCodeTests.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/RestSharp.IntegrationTests/StatusCodeTests.cs b/test/RestSharp.IntegrationTests/StatusCodeTests.cs index ce62bdc7d..22d32fa57 100644 --- a/test/RestSharp.IntegrationTests/StatusCodeTests.cs +++ b/test/RestSharp.IntegrationTests/StatusCodeTests.cs @@ -1,5 +1,6 @@ using System.Net; using RestSharp.Serializers; +using RestSharp.Serializers.Xml; using RestSharp.Tests.Shared.Extensions; using RestSharp.Tests.Shared.Fixtures; @@ -9,6 +10,7 @@ public class StatusCodeTests : IDisposable { public StatusCodeTests() { _server = SimpleServer.Create(UrlToStatusCodeHandler); _client = new RestClient(_server.Url); + _client.UseXmlSerializer(); } public void Dispose() => _server.Dispose(); @@ -81,7 +83,7 @@ public async Task Handles_GET_Request_404_Error() { Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); } - [Fact(Skip = "Not sure why this hangs")] + [Fact] public async Task Reports_1xx_Status_Code_Success_Accurately() { var request = new RestRequest("100"); var response = await _client.ExecuteAsync(request); From 88aad951615d1e3a6d7647809eaba894a696f6b9 Mon Sep 17 00:00:00 2001 From: Alexey Zimarev Date: Tue, 14 Dec 2021 17:16:06 +0100 Subject: [PATCH 07/10] Added a guard against using content type with no body --- .../Request/InvalidRequestException.cs | 22 ++++++++++ src/RestSharp/Request/RequestContent.cs | 42 +++++++++++-------- .../Request/RestRequestExtensions.cs | 5 ++- src/RestSharp/RestSharp.csproj | 5 +++ src/RestSharp/Serializers/ContentType.cs | 2 + .../RequestBodyTests.cs | 11 +++-- .../RestSharp.IntegrationTests.csproj | 5 +++ 7 files changed, 70 insertions(+), 22 deletions(-) create mode 100644 src/RestSharp/Request/InvalidRequestException.cs diff --git a/src/RestSharp/Request/InvalidRequestException.cs b/src/RestSharp/Request/InvalidRequestException.cs new file mode 100644 index 000000000..5c3294a52 --- /dev/null +++ b/src/RestSharp/Request/InvalidRequestException.cs @@ -0,0 +1,22 @@ +// Copyright © 2009-2020 John Sheehan, Andrew Young, Alexey Zimarev and RestSharp community +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +namespace RestSharp; + +public class InvalidRequestException : Exception { + public InvalidRequestException(string message, RestRequest? request = null) : base(message) => Request = request; + + public RestRequest? Request { get; } +} \ No newline at end of file diff --git a/src/RestSharp/Request/RequestContent.cs b/src/RestSharp/Request/RequestContent.cs index c52a7390f..79430647c 100644 --- a/src/RestSharp/Request/RequestContent.cs +++ b/src/RestSharp/Request/RequestContent.cs @@ -13,6 +13,7 @@ // limitations under the License. // +using System.Net.Http.Formatting; using System.Net.Http.Headers; using System.Runtime.Serialization; using RestSharp.Extensions; @@ -61,26 +62,28 @@ void AddFiles() { } HttpContent Serialize(Parameter body) { - if (body.DataFormat == DataFormat.None) { - var stringContent = new StringContent(body.Value!.ToString()!, _client.Options.Encoding, body.ContentType); - return stringContent; - } - - if (!_client.Serializers.TryGetValue(body.DataFormat, out var serializer)) - throw new InvalidDataContractException( - $"Can't find serializer for content type {body.DataFormat}" - ); + return body.DataFormat switch { + DataFormat.None => new StringContent(body.Value!.ToString()!, _client.Options.Encoding, body.ContentType), + _ => GetSerialized() + }; + + HttpContent GetSerialized() { + if (!_client.Serializers.TryGetValue(body.DataFormat, out var serializer)) + throw new InvalidDataContractException( + $"Can't find serializer for content type {body.DataFormat}" + ); - var content = serializer.Serialize(body); + var content = serializer.Serialize(body); - if (content == null) - throw new SerializationException("Request body serialized to null"); + if (content == null) + throw new SerializationException("Request body serialized to null"); - return new StringContent( - content, - _client.Options.Encoding, - body.ContentType ?? serializer.ContentType - ); + return new StringContent( + content, + _client.Options.Encoding, + body.ContentType ?? serializer.ContentType + ); + } } static bool BodyShouldBeMultipartForm(Parameter bodyParameter) { @@ -154,7 +157,10 @@ void AddHeader(Parameter parameter) { } string GetContentTypeHeader(string contentType) { - var boundary = Content!.GetFormBoundary(); + if (Content == null) + throw new InvalidRequestException("Content type headers should not be used when there's no body in the request"); + + var boundary = Content.GetFormBoundary(); return boundary.IsEmpty() ? contentType : $"{contentType}; boundary=\"{boundary}\""; } diff --git a/src/RestSharp/Request/RestRequestExtensions.cs b/src/RestSharp/Request/RestRequestExtensions.cs index d056626c7..fa2ab1fb1 100644 --- a/src/RestSharp/Request/RestRequestExtensions.cs +++ b/src/RestSharp/Request/RestRequestExtensions.cs @@ -3,6 +3,7 @@ namespace RestSharp; +[PublicAPI] public static class RestRequestExtensions { static readonly Regex PortSplitRegex = new(@":\d+"); @@ -190,7 +191,9 @@ bool IsAllowedProperty(string propertyName) => includedProperties.Length == 0 || includedProperties.Length > 0 && includedProperties.Contains(propertyName); } - public static RestRequest AddObject(this RestRequest request, object obj) => request.With(x => x.AddObject(obj, new string[] { })); + public static RestRequest AddObject(this RestRequest request, object obj) { + return request.With(x => x.AddObject(obj, new string[] { })); + } static void CheckAndThrowsForInvalidHost(string name, string value) { static bool InvalidHost(string host) => Uri.CheckHostName(PortSplitRegex.Split(host)[0]) == UriHostNameType.Unknown; diff --git a/src/RestSharp/RestSharp.csproj b/src/RestSharp/RestSharp.csproj index 1034dcb6d..7866e7285 100644 --- a/src/RestSharp/RestSharp.csproj +++ b/src/RestSharp/RestSharp.csproj @@ -5,4 +5,9 @@ + + + ..\..\..\..\..\..\Library\Frameworks\Mono.framework\Versions\6.12.0\lib\mono\4.5\System.Net.Http.Formatting.dll + + diff --git a/src/RestSharp/Serializers/ContentType.cs b/src/RestSharp/Serializers/ContentType.cs index 45629b0a7..5678f8dd2 100644 --- a/src/RestSharp/Serializers/ContentType.cs +++ b/src/RestSharp/Serializers/ContentType.cs @@ -5,6 +5,8 @@ public static class ContentType { public const string Xml = "application/xml"; + public const string Plain = "text/plain"; + public static readonly Dictionary FromDataFormat = new() { { DataFormat.Xml, Xml }, diff --git a/test/RestSharp.IntegrationTests/RequestBodyTests.cs b/test/RestSharp.IntegrationTests/RequestBodyTests.cs index d42ad7c73..68b3a3b34 100644 --- a/test/RestSharp.IntegrationTests/RequestBodyTests.cs +++ b/test/RestSharp.IntegrationTests/RequestBodyTests.cs @@ -1,17 +1,22 @@ -using RestSharp.IntegrationTests.Fixtures; +using System.Net.Http.Formatting; +using RestSharp.IntegrationTests.Fixtures; using RestSharp.Tests.Shared.Fixtures; namespace RestSharp.IntegrationTests; public class RequestBodyTests : IClassFixture { - readonly SimpleServer _server; + readonly ITestOutputHelper _output; + readonly SimpleServer _server; const string NewLine = "\r\n"; const string TextPlainContentType = "text/plain"; const string ExpectedTextContentType = $"{TextPlainContentType}; charset=utf-8"; - public RequestBodyTests(RequestBodyFixture fixture) => _server = fixture.Server; + public RequestBodyTests(RequestBodyFixture fixture, ITestOutputHelper output) { + _output = output; + _server = fixture.Server; + } async Task AssertBody(Method method) { var client = new RestClient(_server.Url); diff --git a/test/RestSharp.IntegrationTests/RestSharp.IntegrationTests.csproj b/test/RestSharp.IntegrationTests/RestSharp.IntegrationTests.csproj index cffe9a94f..87c5490f7 100644 --- a/test/RestSharp.IntegrationTests/RestSharp.IntegrationTests.csproj +++ b/test/RestSharp.IntegrationTests/RestSharp.IntegrationTests.csproj @@ -18,4 +18,9 @@ + + + ..\..\..\..\..\..\Library\Frameworks\Mono.framework\Versions\6.12.0\lib\mono\4.5\System.Net.Http.Formatting.dll + + \ No newline at end of file From 38d54cf7bb055119a03e176abc2a9bec70da632e Mon Sep 17 00:00:00 2001 From: Alexey Zimarev Date: Tue, 14 Dec 2021 17:19:21 +0100 Subject: [PATCH 08/10] Use Xml serializer in tests where it should be used --- .../StructuredSyntaxSuffixTests.cs | 22 +++---------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/test/RestSharp.IntegrationTests/StructuredSyntaxSuffixTests.cs b/test/RestSharp.IntegrationTests/StructuredSyntaxSuffixTests.cs index 342c75cb7..6a0be495b 100644 --- a/test/RestSharp.IntegrationTests/StructuredSyntaxSuffixTests.cs +++ b/test/RestSharp.IntegrationTests/StructuredSyntaxSuffixTests.cs @@ -1,4 +1,5 @@ using System.Net; +using RestSharp.Serializers.Xml; using RestSharp.Tests.Shared.Extensions; using RestSharp.Tests.Shared.Fixtures; @@ -60,7 +61,7 @@ public async Task By_default_content_types_with_JSON_structured_syntax_suffix_sh [Fact] public async Task By_default_content_types_with_XML_structured_syntax_suffix_should_deserialize_as_XML() { - var client = new RestClient(_url); + var client = new RestClient(_url).UseXmlSerializer(); var request = new RestRequest() .AddParameter("ct", "application/vnd.somebody.something+xml") @@ -74,7 +75,7 @@ public async Task By_default_content_types_with_XML_structured_syntax_suffix_sho [Fact] public async Task By_default_text_xml_content_type_should_deserialize_as_XML() { - var client = new RestClient(_url); + var client = new RestClient(_url).UseXmlSerializer(); var request = new RestRequest() .AddParameter("ct", "text/xml") @@ -85,21 +86,4 @@ public async Task By_default_text_xml_content_type_should_deserialize_as_XML() { Assert.Equal("Bob", response.Data.Name); Assert.Equal(50, response.Data.Age); } - - // [Fact] - // public void Should_allow_wildcard_content_types_to_be_defined() { - // var client = new RestClient(_url); - // - // // In spite of the content type, handle ALL structured syntax suffixes of "+xml" as JSON - // client.AddHandler("*+xml", new JsonSerializer()); - // - // var request = new RestRequest() - // .AddParameter("ct", "application/vnd.somebody.something+xml") - // .AddParameter("c", JsonContent); - // - // var response = client.Execute(request); - // - // Assert.Equal("Bob", response.Data.Name); - // Assert.Equal(50, response.Data.Age); - // } } \ No newline at end of file From f8f890d6112d032c1a09e97b084e5112a9f54f28 Mon Sep 17 00:00:00 2001 From: Alexey Zimarev Date: Tue, 14 Dec 2021 17:35:13 +0100 Subject: [PATCH 09/10] Removed unused and breaking ref --- src/RestSharp/Request/RequestContent.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/RestSharp/Request/RequestContent.cs b/src/RestSharp/Request/RequestContent.cs index 79430647c..02f709575 100644 --- a/src/RestSharp/Request/RequestContent.cs +++ b/src/RestSharp/Request/RequestContent.cs @@ -13,7 +13,6 @@ // limitations under the License. // -using System.Net.Http.Formatting; using System.Net.Http.Headers; using System.Runtime.Serialization; using RestSharp.Extensions; From 98cb2c8e1751af346192bd9e12276bafa42566c2 Mon Sep 17 00:00:00 2001 From: Alexey Zimarev Date: Wed, 15 Dec 2021 09:54:59 +0100 Subject: [PATCH 10/10] Remove the Formatting assembly reference --- src/RestSharp/RestSharp.csproj | 5 ----- test/RestSharp.IntegrationTests/RequestBodyTests.cs | 9 ++------- .../RestSharp.IntegrationTests.csproj | 5 ----- .../SystemTextJsonTests.cs | 2 +- test/RestSharp.Tests.Shared/Fixtures/WebServer.cs | 2 +- 5 files changed, 4 insertions(+), 19 deletions(-) diff --git a/src/RestSharp/RestSharp.csproj b/src/RestSharp/RestSharp.csproj index 7866e7285..1034dcb6d 100644 --- a/src/RestSharp/RestSharp.csproj +++ b/src/RestSharp/RestSharp.csproj @@ -5,9 +5,4 @@ - - - ..\..\..\..\..\..\Library\Frameworks\Mono.framework\Versions\6.12.0\lib\mono\4.5\System.Net.Http.Formatting.dll - - diff --git a/test/RestSharp.IntegrationTests/RequestBodyTests.cs b/test/RestSharp.IntegrationTests/RequestBodyTests.cs index 68b3a3b34..4c408c461 100644 --- a/test/RestSharp.IntegrationTests/RequestBodyTests.cs +++ b/test/RestSharp.IntegrationTests/RequestBodyTests.cs @@ -1,11 +1,9 @@ -using System.Net.Http.Formatting; -using RestSharp.IntegrationTests.Fixtures; +using RestSharp.IntegrationTests.Fixtures; using RestSharp.Tests.Shared.Fixtures; namespace RestSharp.IntegrationTests; public class RequestBodyTests : IClassFixture { - readonly ITestOutputHelper _output; readonly SimpleServer _server; const string NewLine = "\r\n"; @@ -13,10 +11,7 @@ public class RequestBodyTests : IClassFixture { const string TextPlainContentType = "text/plain"; const string ExpectedTextContentType = $"{TextPlainContentType}; charset=utf-8"; - public RequestBodyTests(RequestBodyFixture fixture, ITestOutputHelper output) { - _output = output; - _server = fixture.Server; - } + public RequestBodyTests(RequestBodyFixture fixture) => _server = fixture.Server; async Task AssertBody(Method method) { var client = new RestClient(_server.Url); diff --git a/test/RestSharp.IntegrationTests/RestSharp.IntegrationTests.csproj b/test/RestSharp.IntegrationTests/RestSharp.IntegrationTests.csproj index 87c5490f7..cffe9a94f 100644 --- a/test/RestSharp.IntegrationTests/RestSharp.IntegrationTests.csproj +++ b/test/RestSharp.IntegrationTests/RestSharp.IntegrationTests.csproj @@ -18,9 +18,4 @@ - - - ..\..\..\..\..\..\Library\Frameworks\Mono.framework\Versions\6.12.0\lib\mono\4.5\System.Net.Http.Formatting.dll - - \ No newline at end of file diff --git a/test/RestSharp.Serializers.Json.Tests/SystemTextJsonTests.cs b/test/RestSharp.Serializers.Json.Tests/SystemTextJsonTests.cs index 3163d8fd3..b269d7fe3 100644 --- a/test/RestSharp.Serializers.Json.Tests/SystemTextJsonTests.cs +++ b/test/RestSharp.Serializers.Json.Tests/SystemTextJsonTests.cs @@ -9,7 +9,7 @@ namespace RestSharp.Serializers.Json.Tests; public class SystemTextJsonTests { static readonly Fixture Fixture = new(); - string? _body; + string _body; [Fact] public async Task Use_JsonNet_For_Requests() { diff --git a/test/RestSharp.Tests.Shared/Fixtures/WebServer.cs b/test/RestSharp.Tests.Shared/Fixtures/WebServer.cs index 84f8865cf..35c311bc4 100644 --- a/test/RestSharp.Tests.Shared/Fixtures/WebServer.cs +++ b/test/RestSharp.Tests.Shared/Fixtures/WebServer.cs @@ -46,7 +46,7 @@ Task GetContextAsync() try { return ((HttpListener)iar.AsyncState!).EndGetContext(iar); } - catch (HttpListenerException e) { + catch (HttpListenerException) { // it's ok return null; }