diff --git a/CryptoExchange.Net.UnitTests/CallResultTests.cs b/CryptoExchange.Net.UnitTests/CallResultTests.cs index 823fee8b..dd52d41d 100644 --- a/CryptoExchange.Net.UnitTests/CallResultTests.cs +++ b/CryptoExchange.Net.UnitTests/CallResultTests.cs @@ -121,6 +121,7 @@ public void TestWebCallResultSuccessAsError() null, HttpMethod.Get, new List>>(), + ResultDataSource.Server, new TestObjectResult(), null); var asResult = result.AsError(new ServerError("TestError2")); @@ -150,6 +151,7 @@ public void TestWebCallResultSuccessAsSuccess() null, HttpMethod.Get, new List>>(), + ResultDataSource.Server, new TestObjectResult(), null); var asResult = result.As(result.Data.InnerData); diff --git a/CryptoExchange.Net/Clients/RestApiClient.cs b/CryptoExchange.Net/Clients/RestApiClient.cs index 02643489..81e1ebb8 100644 --- a/CryptoExchange.Net/Clients/RestApiClient.cs +++ b/CryptoExchange.Net/Clients/RestApiClient.cs @@ -668,47 +668,47 @@ protected virtual async Task> GetResponseAsync( if (error.Code == null || error.Code == 0) error.Code = (int)response.StatusCode; - return new WebCallResult(response.StatusCode, response.ResponseHeaders, sw.Elapsed, responseLength, OutputOriginalData ? accessor.GetOriginalString() : null, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), default, error!); + return new WebCallResult(response.StatusCode, response.ResponseHeaders, sw.Elapsed, responseLength, OutputOriginalData ? accessor.GetOriginalString() : null, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), ResultDataSource.Server, default, error!); } if (typeof(T) == typeof(object)) // Success status code and expected empty response, assume it's correct - return new WebCallResult(statusCode, headers, sw.Elapsed, 0, null, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), default, null); + return new WebCallResult(statusCode, headers, sw.Elapsed, 0, null, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), ResultDataSource.Server, default, null); var valid = await accessor.Read(responseStream, outputOriginalData).ConfigureAwait(false); if (!valid) { // Invalid json var error = new ServerError("Failed to parse response: " + valid.Error!.Message, accessor.OriginalDataAvailable ? accessor.GetOriginalString() : "[Data only available when OutputOriginal = true in client options]"); - return new WebCallResult(response.StatusCode, response.ResponseHeaders, sw.Elapsed, responseLength, OutputOriginalData ? accessor.GetOriginalString() : null, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), default, error); + return new WebCallResult(response.StatusCode, response.ResponseHeaders, sw.Elapsed, responseLength, OutputOriginalData ? accessor.GetOriginalString() : null, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), ResultDataSource.Server, default, error); } // Json response received var parsedError = TryParseError(accessor); if (parsedError != null) // Success status code, but TryParseError determined it was an error response - return new WebCallResult(response.StatusCode, response.ResponseHeaders, sw.Elapsed, responseLength, OutputOriginalData ? accessor.GetOriginalString() : null, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), default, parsedError); + return new WebCallResult(response.StatusCode, response.ResponseHeaders, sw.Elapsed, responseLength, OutputOriginalData ? accessor.GetOriginalString() : null, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), ResultDataSource.Server, default, parsedError); var deserializeResult = accessor.Deserialize(); - return new WebCallResult(response.StatusCode, response.ResponseHeaders, sw.Elapsed, responseLength, OutputOriginalData ? accessor.GetOriginalString() : null, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), deserializeResult.Data, deserializeResult.Error); + return new WebCallResult(response.StatusCode, response.ResponseHeaders, sw.Elapsed, responseLength, OutputOriginalData ? accessor.GetOriginalString() : null, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), ResultDataSource.Server, deserializeResult.Data, deserializeResult.Error); } catch (HttpRequestException requestException) { // Request exception, can't reach server for instance var exceptionInfo = requestException.ToLogString(); - return new WebCallResult(null, null, sw.Elapsed, null, null, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), default, new WebError(exceptionInfo)); + return new WebCallResult(null, null, sw.Elapsed, null, null, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), ResultDataSource.Server, default, new WebError(exceptionInfo)); } catch (OperationCanceledException canceledException) { if (cancellationToken != default && canceledException.CancellationToken == cancellationToken) { // Cancellation token canceled by caller - return new WebCallResult(null, null, sw.Elapsed, null, null, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), default, new CancellationRequestedError()); + return new WebCallResult(null, null, sw.Elapsed, null, null, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), ResultDataSource.Server, default, new CancellationRequestedError()); } else { // Request timed out - return new WebCallResult(null, null, sw.Elapsed, null, null, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), default, new WebError($"Request timed out")); + return new WebCallResult(null, null, sw.Elapsed, null, null, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), ResultDataSource.Server, default, new WebError($"Request timed out")); } } finally @@ -962,14 +962,14 @@ internal async Task> SyncTimeAsync() { var timeSyncParams = GetTimeSyncInfo(); if (timeSyncParams == null) - return new WebCallResult(null, null, null, null, null, null, null, null, null, null, true, null); + return new WebCallResult(null, null, null, null, null, null, null, null, null, null, ResultDataSource.Server, true, null); if (await timeSyncParams.TimeSyncState.Semaphore.WaitAsync(0).ConfigureAwait(false)) { if (!timeSyncParams.SyncTime || DateTime.UtcNow - timeSyncParams.TimeSyncState.LastSyncTime < timeSyncParams.RecalculationInterval) { timeSyncParams.TimeSyncState.Semaphore.Release(); - return new WebCallResult(null, null, null, null, null, null, null, null, null, null, true, null); + return new WebCallResult(null, null, null, null, null, null, null, null, null, null, ResultDataSource.Server, true, null); } var localTime = DateTime.UtcNow; @@ -998,7 +998,7 @@ internal async Task> SyncTimeAsync() timeSyncParams.TimeSyncState.Semaphore.Release(); } - return new WebCallResult(null, null, null, null, null, null, null, null, null, null, true, null); + return new WebCallResult(null, null, null, null, null, null, null, null, null, null, ResultDataSource.Server, true, null); } private bool ShouldCache(RequestDefinition definition) diff --git a/CryptoExchange.Net/Converters/SystemTextJson/ObjectStringConverter.cs b/CryptoExchange.Net/Converters/SystemTextJson/ObjectStringConverter.cs index d6a50787..f2747cdc 100644 --- a/CryptoExchange.Net/Converters/SystemTextJson/ObjectStringConverter.cs +++ b/CryptoExchange.Net/Converters/SystemTextJson/ObjectStringConverter.cs @@ -25,7 +25,7 @@ public class ObjectStringConverter : JsonConverter if (string.IsNullOrEmpty(value)) return default; - return (T?)JsonDocument.Parse(value).Deserialize(typeof(T)); + return (T?)JsonDocument.Parse(value!).Deserialize(typeof(T)); } /// diff --git a/CryptoExchange.Net/Objects/CallResult.cs b/CryptoExchange.Net/Objects/CallResult.cs index 17e53ba0..5ee63bd1 100644 --- a/CryptoExchange.Net/Objects/CallResult.cs +++ b/CryptoExchange.Net/Objects/CallResult.cs @@ -349,6 +349,7 @@ public class WebCallResult: CallResult /// /// /// + /// /// /// public WebCallResult( @@ -362,6 +363,7 @@ public WebCallResult( string? requestBody, HttpMethod? requestMethod, IEnumerable>>? requestHeaders, + ResultDataSource dataSource, [AllowNull] T data, Error? error) : base(data, originalData, error) { @@ -375,6 +377,7 @@ public WebCallResult( RequestBody = requestBody; RequestHeaders = requestHeaders; RequestMethod = requestMethod; + DataSource = dataSource; } /// @@ -398,7 +401,7 @@ public WebCallResult( /// Create a new error result /// /// The error - public WebCallResult(Error? error) : this(null, null, null, null, null, null, null, null, null, null, default, error) { } + public WebCallResult(Error? error) : this(null, null, null, null, null, null, null, null, null, null, ResultDataSource.Server, default, error) { } /// /// Copy the WebCallResult to a new data type @@ -408,7 +411,7 @@ public WebCallResult(Error? error) : this(null, null, null, null, null, null, nu /// public new WebCallResult As([AllowNull] K data) { - return new WebCallResult(ResponseStatusCode, ResponseHeaders, ResponseTime, ResponseLength, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, data, Error); + return new WebCallResult(ResponseStatusCode, ResponseHeaders, ResponseTime, ResponseLength, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, DataSource, data, Error); } /// @@ -419,7 +422,7 @@ public WebCallResult(Error? error) : this(null, null, null, null, null, null, nu /// public new WebCallResult AsError(Error error) { - return new WebCallResult(ResponseStatusCode, ResponseHeaders, ResponseTime, ResponseLength, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, default, error); + return new WebCallResult(ResponseStatusCode, ResponseHeaders, ResponseTime, ResponseLength, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, DataSource, default, error); } /// @@ -428,9 +431,7 @@ public WebCallResult(Error? error) : this(null, null, null, null, null, null, nu /// internal WebCallResult Cached() { - var result = new WebCallResult(ResponseStatusCode, ResponseHeaders, ResponseTime, ResponseLength, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, default, Error); - result.DataSource = ResultDataSource.Cache; - return result; + return new WebCallResult(ResponseStatusCode, ResponseHeaders, ResponseTime, ResponseLength, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, ResultDataSource.Cache, Data, Error); } ///