From 1dc9ba6ab42e691154a2cc351058c39467de1408 Mon Sep 17 00:00:00 2001 From: Andrew Omondi Date: Fri, 13 Jan 2023 10:08:43 +0300 Subject: [PATCH 1/3] Adds support for nullable ref types --- CHANGELOG.md | 6 +++ .../Microsoft.Kiota.Abstractions.Tests.csproj | 1 + src/IRequestAdapter.cs | 16 +++--- src/IResponseHandler.cs | 2 +- src/Microsoft.Kiota.Abstractions.csproj | 7 ++- src/NativeResponseHandler.cs | 8 +-- src/NativeResponseWrapper.cs | 20 ++++---- src/RequestHeaders.cs | 4 ++ src/RequestInformation.cs | 29 +++++------ src/ResponseHandlerOption.cs | 2 +- src/authentication/AllowedHostsValidator.cs | 2 +- .../AnonymousAuthenticationProvider.cs | 4 +- .../ApiKeyAuthenticationProvider.cs | 5 +- .../BaseBearerTokenAuthenticationProvider.cs | 2 +- src/authentication/IAccessTokenProvider.cs | 2 +- src/authentication/IAuthenticationProvider.cs | 4 +- src/extensions/IDictionaryExtensions.cs | 4 +- src/extensions/StringExtensions.cs | 4 +- src/serialization/IParseNode.cs | 12 ++--- src/serialization/ISerializationWriter.cs | 50 +++++++++---------- src/store/IBackingStore.cs | 10 ++-- src/store/InMemoryBackingStore.cs | 26 +++++----- 22 files changed, 118 insertions(+), 102 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c4b36b2..e1d513b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +## [1.0.0-rc.4] - 2023-01-17 + +### Changed + +- Adds support for nullable reference types + ## [1.0.0-rc.3] - 2023-01-09 ### Changed diff --git a/Microsoft.Kiota.Abstractions.Tests/Microsoft.Kiota.Abstractions.Tests.csproj b/Microsoft.Kiota.Abstractions.Tests/Microsoft.Kiota.Abstractions.Tests.csproj index 7784eaed..13d32140 100644 --- a/Microsoft.Kiota.Abstractions.Tests/Microsoft.Kiota.Abstractions.Tests.csproj +++ b/Microsoft.Kiota.Abstractions.Tests/Microsoft.Kiota.Abstractions.Tests.csproj @@ -5,6 +5,7 @@ net462;net6.0 latest Library + true diff --git a/src/IRequestAdapter.cs b/src/IRequestAdapter.cs index 4850380f..e46d8afc 100644 --- a/src/IRequestAdapter.cs +++ b/src/IRequestAdapter.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. // ------------------------------------------------------------------------------ @@ -32,7 +32,7 @@ public interface IRequestAdapter /// The error factories mapping to use in case of a failed request. /// The to use for cancelling the requests. /// The deserialized response model. - Task SendAsync(RequestInformation requestInfo, ParsableFactory factory, Dictionary> errorMapping = default, CancellationToken cancellationToken = default) where ModelType : IParsable; + Task SendAsync(RequestInformation requestInfo, ParsableFactory factory, Dictionary>? errorMapping = default, CancellationToken cancellationToken = default) where ModelType : IParsable; /// /// Executes the HTTP request specified by the given RequestInformation and returns the deserialized response model collection. /// @@ -41,7 +41,7 @@ public interface IRequestAdapter /// The error factories mapping to use in case of a failed request. /// The to use for cancelling the requests. /// The deserialized response model collection. - Task> SendCollectionAsync(RequestInformation requestInfo, ParsableFactory factory, Dictionary> errorMapping = default, CancellationToken cancellationToken = default) where ModelType : IParsable; + Task?> SendCollectionAsync(RequestInformation requestInfo, ParsableFactory factory, Dictionary>? errorMapping = default, CancellationToken cancellationToken = default) where ModelType : IParsable; /// /// Executes the HTTP request specified by the given RequestInformation and returns the deserialized primitive response model. /// @@ -49,7 +49,7 @@ public interface IRequestAdapter /// The error factories mapping to use in case of a failed request. /// The to use for cancelling the requests. /// The deserialized primitive response model. - Task SendPrimitiveAsync(RequestInformation requestInfo, Dictionary> errorMapping = default, CancellationToken cancellationToken = default); + Task SendPrimitiveAsync(RequestInformation requestInfo, Dictionary>? errorMapping = default, CancellationToken cancellationToken = default); /// /// Executes the HTTP request specified by the given RequestInformation and returns the deserialized primitive response model collection. /// @@ -57,7 +57,7 @@ public interface IRequestAdapter /// The error factories mapping to use in case of a failed request. /// The to use for cancelling the requests. /// The deserialized primitive response model collection. - Task> SendPrimitiveCollectionAsync(RequestInformation requestInfo, Dictionary> errorMapping = default, CancellationToken cancellationToken = default); + Task?> SendPrimitiveCollectionAsync(RequestInformation requestInfo, Dictionary>? errorMapping = default, CancellationToken cancellationToken = default); /// /// Executes the HTTP request specified by the given RequestInformation with no return content. /// @@ -65,11 +65,11 @@ public interface IRequestAdapter /// The error factories mapping to use in case of a failed request. /// The to use for cancelling the requests. /// A Task to await completion. - Task SendNoContentAsync(RequestInformation requestInfo, Dictionary> errorMapping = default, CancellationToken cancellationToken = default); + Task SendNoContentAsync(RequestInformation requestInfo, Dictionary>? errorMapping = default, CancellationToken cancellationToken = default); /// /// The base url for every request. /// - string BaseUrl { get; set; } + string? BaseUrl { get; set; } /// /// Converts the given RequestInformation into a native HTTP request used by the implementing adapter. /// @@ -77,6 +77,6 @@ public interface IRequestAdapter /// The RequestInformation object to use for the HTTP request. /// The to use for cancelling the requests. /// The native HTTP request. - Task ConvertToNativeRequestAsync(RequestInformation requestInfo, CancellationToken cancellationToken = default); + Task ConvertToNativeRequestAsync(RequestInformation requestInfo, CancellationToken cancellationToken = default); } } diff --git a/src/IResponseHandler.cs b/src/IResponseHandler.cs index e8369599..67aad082 100644 --- a/src/IResponseHandler.cs +++ b/src/IResponseHandler.cs @@ -22,6 +22,6 @@ public interface IResponseHandler /// The type of the native response object. /// The type of the response model object. /// A task that represents the asynchronous operation and contains the deserialized response. - Task HandleResponseAsync(NativeResponseType response, Dictionary> errorMappings); + Task HandleResponseAsync(NativeResponseType response, Dictionary>? errorMappings); } } diff --git a/src/Microsoft.Kiota.Abstractions.csproj b/src/Microsoft.Kiota.Abstractions.csproj index 686bf691..47b297c8 100644 --- a/src/Microsoft.Kiota.Abstractions.csproj +++ b/src/Microsoft.Kiota.Abstractions.csproj @@ -6,7 +6,7 @@ © Microsoft Corporation. All rights reserved. Kiota Abstractions Library for dotnet Microsoft - netstandard2.0 + netstandard2.0;net6.0; latest true https://github.com/microsoft/kiota-abstractions-dotnet @@ -14,12 +14,15 @@ true true 1.0.0 - rc.3 + rc.4 true false false 35MSSharedLib1024.snk true + latest + enable + true diff --git a/src/NativeResponseHandler.cs b/src/NativeResponseHandler.cs index 5eff1d47..f83d197d 100644 --- a/src/NativeResponseHandler.cs +++ b/src/NativeResponseHandler.cs @@ -17,17 +17,17 @@ public class NativeResponseHandler : IResponseHandler /// /// The value of the response /// - public object Value; + public object? Value; /// /// The error mappings for the response to use when deserializing failed responses bodies. Where an error code like 401 applies specifically to that status code, a class code like 4XX applies to all status codes within the range if an the specific error code is not present. /// - public Dictionary> ErrorMappings { get; set; } + public Dictionary>? ErrorMappings { get; set; } /// - public Task HandleResponseAsync(NativeResponseType response, Dictionary> errorMappings) + public Task HandleResponseAsync(NativeResponseType response, Dictionary>? errorMappings) { - Value = response; + Value = response ?? throw new ArgumentNullException(nameof(response)); ErrorMappings = errorMappings; return Task.FromResult(default(ModelType)); } diff --git a/src/NativeResponseWrapper.cs b/src/NativeResponseWrapper.cs index ce15f38e..dd16f455 100644 --- a/src/NativeResponseWrapper.cs +++ b/src/NativeResponseWrapper.cs @@ -22,11 +22,11 @@ public class NativeResponseWrapper /// The request headers of the request /// Request options /// - public static async Task CallAndGetNativeType( - Func, Action>, IEnumerable, IResponseHandler, Task> originalCall, - Action q = default, - Action> h = default, - IEnumerable o = default) where NativeResponseType : class + public static async Task CallAndGetNativeType( + Func?, Action>?, IEnumerable?, IResponseHandler, Task> originalCall, + Action? q = default, + Action>? h = default, + IEnumerable? o = default) where NativeResponseType : class { var responseHandler = new NativeResponseHandler(); await originalCall.Invoke(q, h, o, responseHandler); @@ -42,12 +42,12 @@ public static async Task CallAndGetNativeTypeThe query parameters of the request /// The request headers of the request /// Request options - public static async Task CallAndGetNativeType( - Func, Action>, IEnumerable, IResponseHandler, Task> originalCall, + public static async Task CallAndGetNativeType( + Func?, Action>?, IEnumerable?, IResponseHandler, Task> originalCall, RequestBodyType requestBody, - Action q = default, - Action> h = default, - IEnumerable o = default) where NativeResponseType : class + Action? q = default, + Action>? h = default, + IEnumerable? o = default) where NativeResponseType : class { var responseHandler = new NativeResponseHandler(); await originalCall.Invoke(requestBody, q, h, o, responseHandler); diff --git a/src/RequestHeaders.cs b/src/RequestHeaders.cs index a651b674..0de4df2f 100644 --- a/src/RequestHeaders.cs +++ b/src/RequestHeaders.cs @@ -35,7 +35,9 @@ public void Add(string headerName, params string[] headerValues) { /// public bool IsReadOnly => false; /// +#pragma warning disable CS8603 // Possible null reference return. //Can't change signature of overriden method implementation public IEnumerable this[string key] { get => TryGetValue(key, out var result) ? result : null; set => Add(key, value); } +#pragma warning restore CS8603 // Possible null reference return. /// /// Removes the specified value from the header with the specified name. @@ -75,7 +77,9 @@ public void Clear() { /// public bool ContainsKey(string key) => !string.IsNullOrEmpty(key) && _headers.ContainsKey(key); /// +#pragma warning disable CS8604 // Possible null reference argument. //Can't change signature of overriden method implementation public void Add(string key, IEnumerable value) => Add(key, value?.ToArray()); +#pragma warning restore CS8604 // Possible null reference argument. /// public bool Remove(string key) { if(string.IsNullOrEmpty(key)) diff --git a/src/RequestInformation.cs b/src/RequestInformation.cs index 8bcca284..5f55e95a 100644 --- a/src/RequestInformation.cs +++ b/src/RequestInformation.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. // ------------------------------------------------------------------------------ @@ -19,7 +19,7 @@ namespace Microsoft.Kiota.Abstractions /// public class RequestInformation { - private Uri _rawUri; + private Uri? _rawUri; /// /// The URI of the request. /// @@ -37,11 +37,11 @@ public Uri URI { else if(PathParameters.TryGetValue("request-raw-url", out var rawUrl) && rawUrl is string rawUrlString) { URI = new Uri(rawUrlString); - return _rawUri; + return _rawUri!; } else { - if(UrlTemplate.IndexOf("{+baseurl}", StringComparison.OrdinalIgnoreCase) >= 0 && !PathParameters.ContainsKey("baseurl")) + if(UrlTemplate?.IndexOf("{+baseurl}", StringComparison.OrdinalIgnoreCase) >= 0 && !PathParameters.ContainsKey("baseurl")) throw new InvalidOperationException($"{nameof(PathParameters)} must contain a value for \"baseurl\" for the url to be built."); var parsedUrlTemplate = new UriTemplate(UrlTemplate); @@ -78,7 +78,7 @@ public Uri URI { /// /// The Url template for the current request. /// - public string UrlTemplate { get; set; } + public string? UrlTemplate { get; set; } /// /// The path parameters to use for the URL template when generating the URI. /// @@ -109,11 +109,11 @@ public void AddQueryParameters(object source) ) ) .Where(x => x.Value != null && - !QueryParameters.ContainsKey(x.Name) && + !QueryParameters.ContainsKey(x.Name!) && !string.IsNullOrEmpty(x.Value.ToString()) && // no need to add an empty string value (x.Value is not ICollection collection || collection.Count > 0))) // no need to add empty collection { - QueryParameters.AddOrReplace(property.Name, property.Value); + QueryParameters.AddOrReplace(property.Name!, property.Value!); } } /// @@ -130,7 +130,7 @@ public void AddHeaders(RequestHeaders headers) { /// /// The Request Body. /// - public Stream Content { get; set; } + public Stream Content { get; set; } = Stream.Null; private readonly Dictionary _requestOptions = new Dictionary(StringComparer.OrdinalIgnoreCase); /// /// Gets the options for this request. Options are unique by type. If an option of the same type is added twice, the last one wins. @@ -144,7 +144,7 @@ public void AddRequestOptions(IEnumerable options) { if(options == null) return; foreach(var option in options.Where(x => x != null)) - _requestOptions.AddOrReplace(option.GetType().FullName, option); + _requestOptions.AddOrReplace(option.GetType().FullName!, option); } /// /// Removes given options from the current request. @@ -153,14 +153,14 @@ public void AddRequestOptions(IEnumerable options) public void RemoveRequestOptions(params IRequestOption[] options) { if(!options?.Any() ?? false) throw new ArgumentNullException(nameof(options)); - foreach(var optionName in options.Where(x => x != null).Select(x => x.GetType().FullName)) - _requestOptions.Remove(optionName); + foreach(var optionName in options!.Where(x => x != null).Select(x => x.GetType().FullName)) + _requestOptions.Remove(optionName!); } /// /// Gets a instance of the matching type. /// - public T GetRequestOption() => _requestOptions.TryGetValue(typeof(T).FullName, out var requestOption) ? (T)requestOption : default; + public T? GetRequestOption() => _requestOptions.TryGetValue(typeof(T).FullName!, out var requestOption) ? (T)requestOption : default; /// /// Adds a as a for the request. @@ -190,7 +190,7 @@ public void SetStreamContent(Stream content) Content = content; Headers.Add(ContentTypeHeader, BinaryContentType); } - private static ActivitySource _activitySource = new(typeof(RequestInformation).Namespace); + private static ActivitySource _activitySource = new(typeof(RequestInformation).Namespace!); /// /// Sets the request body from a model with the specified content type. /// @@ -223,7 +223,8 @@ public void SetContentFromParsable(IRequestAdapter requestAdapter, string con Headers.Add(ContentTypeHeader, contentType); Content = writer.GetSerializedContent(); } - private void setRequestType(object result, Activity activity) { + private void setRequestType(object? result, Activity? activity) + { if (activity == null) return; if (result == null) return; activity.SetTag("com.microsoft.kiota.request.type", result.GetType().FullName); diff --git a/src/ResponseHandlerOption.cs b/src/ResponseHandlerOption.cs index 66fc9601..6044ad8c 100644 --- a/src/ResponseHandlerOption.cs +++ b/src/ResponseHandlerOption.cs @@ -12,6 +12,6 @@ public class ResponseHandlerOption : IRequestOption /// /// The to use for a request /// - public IResponseHandler ResponseHandler { get; set; } + public IResponseHandler? ResponseHandler { get; set; } } } diff --git a/src/authentication/AllowedHostsValidator.cs b/src/authentication/AllowedHostsValidator.cs index d034b535..c544cdd2 100644 --- a/src/authentication/AllowedHostsValidator.cs +++ b/src/authentication/AllowedHostsValidator.cs @@ -19,7 +19,7 @@ public class AllowedHostsValidator /// The constructor /// /// Collection of valid Hosts - public AllowedHostsValidator(IEnumerable validHosts = null) + public AllowedHostsValidator(IEnumerable? validHosts = null) { _allowedHosts = new HashSet(validHosts ?? Array.Empty(), StringComparer.OrdinalIgnoreCase); } diff --git a/src/authentication/AnonymousAuthenticationProvider.cs b/src/authentication/AnonymousAuthenticationProvider.cs index caeb6ac8..0d77f3c8 100644 --- a/src/authentication/AnonymousAuthenticationProvider.cs +++ b/src/authentication/AnonymousAuthenticationProvider.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. // ------------------------------------------------------------------------------ @@ -14,7 +14,7 @@ namespace Microsoft.Kiota.Abstractions.Authentication public class AnonymousAuthenticationProvider : IAuthenticationProvider { /// - public Task AuthenticateRequestAsync(RequestInformation request, Dictionary additionalAuthenticationContext = default, CancellationToken cancellationToken = default) + public Task AuthenticateRequestAsync(RequestInformation request, Dictionary? additionalAuthenticationContext = default, CancellationToken cancellationToken = default) { return Task.CompletedTask; } diff --git a/src/authentication/ApiKeyAuthenticationProvider.cs b/src/authentication/ApiKeyAuthenticationProvider.cs index 30bfffac..9378ca81 100644 --- a/src/authentication/ApiKeyAuthenticationProvider.cs +++ b/src/authentication/ApiKeyAuthenticationProvider.cs @@ -41,9 +41,10 @@ public ApiKeyAuthenticationProvider(string apiKey, string parameterName, KeyLoca KeyLoc = keyLocation; AllowedHostsValidator = new AllowedHostsValidator(allowedHosts); } - private static ActivitySource _activitySource = new(typeof(RequestInformation).Namespace); + private static ActivitySource _activitySource = new(typeof(RequestInformation).Namespace!); /// - public Task AuthenticateRequestAsync(RequestInformation request, Dictionary additionalAuthenticationContext = null, CancellationToken cancellationToken = default) { + public Task AuthenticateRequestAsync(RequestInformation request, Dictionary? additionalAuthenticationContext = default, CancellationToken cancellationToken = default) + { if (request == null) throw new ArgumentNullException(nameof(request)); using var span = _activitySource?.StartActivity(nameof(AuthenticateRequestAsync)); diff --git a/src/authentication/BaseBearerTokenAuthenticationProvider.cs b/src/authentication/BaseBearerTokenAuthenticationProvider.cs index 44c77239..ed9e6f58 100644 --- a/src/authentication/BaseBearerTokenAuthenticationProvider.cs +++ b/src/authentication/BaseBearerTokenAuthenticationProvider.cs @@ -29,7 +29,7 @@ public BaseBearerTokenAuthenticationProvider(IAccessTokenProvider accessTokenPro private const string ClaimsKey = "claims"; /// - public async Task AuthenticateRequestAsync(RequestInformation request, Dictionary additionalAuthenticationContext = default, CancellationToken cancellationToken = default) + public async Task AuthenticateRequestAsync(RequestInformation request, Dictionary? additionalAuthenticationContext = default, CancellationToken cancellationToken = default) { if(request == null) throw new ArgumentNullException(nameof(request)); if(additionalAuthenticationContext != null && diff --git a/src/authentication/IAccessTokenProvider.cs b/src/authentication/IAccessTokenProvider.cs index caaf3829..ef20dec3 100644 --- a/src/authentication/IAccessTokenProvider.cs +++ b/src/authentication/IAccessTokenProvider.cs @@ -20,7 +20,7 @@ public interface IAccessTokenProvider /// Additional authentication context to pass to the authentication library. /// The cancellation token for the task /// A Task that holds the access token to use for the request. - Task GetAuthorizationTokenAsync(Uri uri, Dictionary additionalAuthenticationContext = default, CancellationToken cancellationToken = default); + Task GetAuthorizationTokenAsync(Uri uri, Dictionary? additionalAuthenticationContext = default, CancellationToken cancellationToken = default); /// /// Returns the for the provider. /// diff --git a/src/authentication/IAuthenticationProvider.cs b/src/authentication/IAuthenticationProvider.cs index 5d4cea83..a0a555b1 100644 --- a/src/authentication/IAuthenticationProvider.cs +++ b/src/authentication/IAuthenticationProvider.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. // ------------------------------------------------------------------------------ @@ -20,6 +20,6 @@ public interface IAuthenticationProvider /// Additional authentication context to pass to the authentication library. /// The cancellation token for the task /// A task to await for the authentication to be completed. - Task AuthenticateRequestAsync(RequestInformation request, Dictionary additionalAuthenticationContext = default, CancellationToken cancellationToken = default); + Task AuthenticateRequestAsync(RequestInformation request, Dictionary? additionalAuthenticationContext = default, CancellationToken cancellationToken = default); } } diff --git a/src/extensions/IDictionaryExtensions.cs b/src/extensions/IDictionaryExtensions.cs index cc7723b4..c7ca7e44 100644 --- a/src/extensions/IDictionaryExtensions.cs +++ b/src/extensions/IDictionaryExtensions.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. // ------------------------------------------------------------------------------ @@ -51,7 +51,7 @@ public static bool TryAdd(this IDictionary dictionar /// The key parameter. /// The value /// The previous value if any - public static TValue AddOrReplace(this IDictionary dictionary, TKey key, TValue value) + public static TValue? AddOrReplace(this IDictionary dictionary, TKey key, TValue value) { if(!dictionary.TryAdd(key, value)) { diff --git a/src/extensions/StringExtensions.cs b/src/extensions/StringExtensions.cs index dcf38ea7..453c18a6 100644 --- a/src/extensions/StringExtensions.cs +++ b/src/extensions/StringExtensions.cs @@ -14,7 +14,7 @@ public static class StringExtensions /// /// The string to lowercase. /// The input string with the first letter lowered. - public static string ToFirstCharacterLowerCase(this string input) - => string.IsNullOrEmpty(input) ? input : $"{char.ToLowerInvariant(input[0])}{input.Substring(1)}"; + public static string? ToFirstCharacterLowerCase(this string? input) + => string.IsNullOrEmpty(input) ? input : $"{char.ToLowerInvariant(input![0])}{input.Substring(1)}"; } } diff --git a/src/serialization/IParseNode.cs b/src/serialization/IParseNode.cs index f3b6a9fb..bf2210b6 100644 --- a/src/serialization/IParseNode.cs +++ b/src/serialization/IParseNode.cs @@ -16,13 +16,13 @@ public interface IParseNode /// Gets the string value of the node. /// /// The string value of the node. - string GetStringValue(); + string? GetStringValue(); /// /// Gets a new parse node for the given identifier. /// /// The identifier. /// The new parse node. - IParseNode GetChildNode(string identifier); + IParseNode? GetChildNode(string identifier); /// /// Gets the boolean value of the node. /// @@ -114,19 +114,19 @@ public interface IParseNode /// /// The factory to use to create the model object. /// The model object value of the node. - T GetObjectValue(ParsableFactory factory) where T : IParsable; + T? GetObjectValue(ParsableFactory factory) where T : IParsable; /// /// Callback called before the node is deserialized. /// - Action OnBeforeAssignFieldValues { get; set; } + Action? OnBeforeAssignFieldValues { get; set; } /// /// Callback called after the node is deserialized. /// - Action OnAfterAssignFieldValues { get; set; } + Action? OnAfterAssignFieldValues { get; set; } /// /// Gets the byte array value of the node. /// /// The byte array value of the node. - byte[] GetByteArrayValue(); + byte[]? GetByteArrayValue(); } } diff --git a/src/serialization/ISerializationWriter.cs b/src/serialization/ISerializationWriter.cs index 3ae07e86..f6ae0b41 100644 --- a/src/serialization/ISerializationWriter.cs +++ b/src/serialization/ISerializationWriter.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. // ------------------------------------------------------------------------------ @@ -18,127 +18,127 @@ public interface ISerializationWriter : IDisposable /// /// The key to be used for the written value. May be null. /// The string value to be written. - void WriteStringValue(string key, string value); + void WriteStringValue(string? key, string? value); /// /// Writes the specified boolean value to the stream with an optional given key. /// /// The key to be used for the written value. May be null. /// The byte boolean value to be written. - void WriteBoolValue(string key, bool? value); + void WriteBoolValue(string? key, bool? value); /// /// Writes the specified byte value to the stream with an optional given key. /// /// The key to be used for the written value. May be null. /// The byte value to be written. - void WriteByteValue(string key, byte? value); + void WriteByteValue(string? key, byte? value); /// /// Writes the specified sbyte value to the stream with an optional given key. /// /// The key to be used for the written value. May be null. /// The sbyte value to be written. - void WriteSbyteValue(string key, sbyte? value); + void WriteSbyteValue(string? key, sbyte? value); /// /// Writes the specified byte integer value to the stream with an optional given key. /// /// The key to be used for the written value. May be null. /// The byte integer value to be written. - void WriteIntValue(string key, int? value); + void WriteIntValue(string? key, int? value); /// /// Writes the specified float value to the stream with an optional given key. /// /// The key to be used for the written value. May be null. /// The float value to be written. - void WriteFloatValue(string key, float? value); + void WriteFloatValue(string? key, float? value); /// /// Writes the specified long value to the stream with an optional given key. /// /// The key to be used for the written value. May be null. /// The long value to be written. - void WriteLongValue(string key, long? value); + void WriteLongValue(string? key, long? value); /// /// Writes the specified double value to the stream with an optional given key. /// /// The key to be used for the written value. May be null. /// The double value to be written. - void WriteDoubleValue(string key, double? value); + void WriteDoubleValue(string? key, double? value); /// /// Writes the specified decimal value to the stream with an optional given key. /// /// The key to be used for the written value. May be null. /// The decimal value to be written. - void WriteDecimalValue(string key, decimal? value); + void WriteDecimalValue(string? key, decimal? value); /// /// Writes the specified Guid value to the stream with an optional given key. /// /// The key to be used for the written value. May be null. /// The Guid value to be written. - void WriteGuidValue(string key, Guid? value); + void WriteGuidValue(string? key, Guid? value); /// /// Writes the specified DateTimeOffset value to the stream with an optional given key. /// /// The key to be used for the written value. May be null. /// The DateTimeOffset value to be written. - void WriteDateTimeOffsetValue(string key, DateTimeOffset? value); + void WriteDateTimeOffsetValue(string? key, DateTimeOffset? value); /// /// Writes the specified TimeSpan value to the stream with an optional given key. /// /// The key to be used for the written value. May be null. /// The TimeSpan value to be written. - void WriteTimeSpanValue(string key, TimeSpan? value); + void WriteTimeSpanValue(string? key, TimeSpan? value); /// /// Writes the specified Date value to the stream with an optional given key. /// /// The key to be used for the written value. May be null. /// The Date value to be written. - void WriteDateValue(string key, Date? value); + void WriteDateValue(string? key, Date? value); /// /// Writes the specified Time value to the stream with an optional given key. /// /// The key to be used for the written value. May be null. /// The Time value to be written. - void WriteTimeValue(string key, Time? value); + void WriteTimeValue(string? key, Time? value); /// /// Writes the specified collection of primitive values to the stream with an optional given key. /// /// The key to be used for the written value. May be null. /// The collection of primitive values to be written. - void WriteCollectionOfPrimitiveValues(string key, IEnumerable values); + void WriteCollectionOfPrimitiveValues(string? key, IEnumerable? values); /// /// Writes the specified collection of model objects to the stream with an optional given key. /// /// The key to be used for the written value. May be null. /// The collection of model objects to be written. - void WriteCollectionOfObjectValues(string key, IEnumerable values) where T : IParsable; + void WriteCollectionOfObjectValues(string? key, IEnumerable? values) where T : IParsable; /// /// Writes the specified collection of enum values to the stream with an optional given key. /// /// The key to be used for the written value. May be null. /// The enum values to be written. - void WriteCollectionOfEnumValues(string key, IEnumerable values) where T : struct, Enum; + void WriteCollectionOfEnumValues(string? key, IEnumerable? values) where T : struct, Enum; /// /// Writes the specified byte array as a base64 string to the stream with an optional given key. /// /// The key to be used for the written value. May be null. /// The byte array to be written. - void WriteByteArrayValue(string key, byte[] value); + void WriteByteArrayValue(string? key, byte[]? value); /// /// Writes the specified model object to the stream with an optional given key. /// /// The key to be used for the written value. May be null. /// The model object to be written. /// The additional values to merge to the main value when serializing an intersection wrapper. - void WriteObjectValue(string key, T value, params IParsable[] additionalValuesToMerge) where T : IParsable; + void WriteObjectValue(string? key, T? value, params IParsable[] additionalValuesToMerge) where T : IParsable; /// /// Writes the specified enum value to the stream with an optional given key. /// /// The key to be used for the written value. May be null. /// The enum value to be written. - void WriteEnumValue(string key, T? value) where T : struct, Enum; + void WriteEnumValue(string? key, T? value) where T : struct, Enum; /// /// Writes a null value for the specified key. /// /// The key to be used for the written value. May be null. - void WriteNullValue(string key); + void WriteNullValue(string? key); /// /// Writes the specified additional data to the stream. /// @@ -152,14 +152,14 @@ public interface ISerializationWriter : IDisposable /// /// Callback called before the serialization process starts. /// - Action OnBeforeObjectSerialization { get; set; } + Action? OnBeforeObjectSerialization { get; set; } /// /// Callback called after the serialization process ends. /// - Action OnAfterObjectSerialization { get; set; } + Action? OnAfterObjectSerialization { get; set; } /// /// Callback called right after the serialization process starts. /// - Action OnStartObjectSerialization { get; set; } + Action? OnStartObjectSerialization { get; set; } } } diff --git a/src/store/IBackingStore.cs b/src/store/IBackingStore.cs index f58512f3..487658cc 100644 --- a/src/store/IBackingStore.cs +++ b/src/store/IBackingStore.cs @@ -15,17 +15,17 @@ public interface IBackingStore /// Gets a value from the backing store based on its key. Returns null if the value hasn't changed and "ReturnOnlyChangedValues" is true. /// The value from the backing store. /// The key to lookup the backing store with. - T Get(string key); + T? Get(string key); /// /// Sets or updates the stored value for the given key. /// Will trigger subscriptions callbacks. /// /// The key to store and retrieve the information. /// The value to be stored. - void Set(string key, T value); + void Set(string key, T? value); /// Enumerates all the values stored in the backing store. Values will be filtered if "ReturnOnlyChangedValues" is true. /// The values available in the backing store. - IEnumerable> Enumerate(); + IEnumerable> Enumerate(); /// /// Enumerates the keys for all values that changed to null. /// @@ -36,13 +36,13 @@ public interface IBackingStore /// /// Callback to be invoked on data changes where the first parameter is the data key, the second the previous value and the third the new value. /// The subscription Id to use when removing the subscription - string Subscribe(Action callback); + string Subscribe(Action callback); /// /// Creates a subscription to any data change happening, allowing to specify the subscription Id. /// /// Callback to be invoked on data changes where the first parameter is the data key, the second the previous value and the third the new value. /// The subscription Id to use. - void Subscribe(Action callback, string subscriptionId); + void Subscribe(Action callback, string subscriptionId); /// /// Removes a subscription from the store based on its subscription id. /// diff --git a/src/store/InMemoryBackingStore.cs b/src/store/InMemoryBackingStore.cs index c49f52e3..f0d2fc3a 100644 --- a/src/store/InMemoryBackingStore.cs +++ b/src/store/InMemoryBackingStore.cs @@ -20,15 +20,15 @@ public class InMemoryBackingStore : IBackingStore /// Determines whether the backing store should only return changed values when queried. /// public bool ReturnOnlyChangedValues { get; set; } - private readonly Dictionary> store = new(); - private readonly Dictionary> subscriptions = new(); + private readonly Dictionary> store = new(); + private readonly Dictionary> subscriptions = new(); /// /// Gets the specified object with the given key from the store. /// /// The key to search with /// An instance of - public T Get(string key) + public T? Get(string key) { if(string.IsNullOrEmpty(key)) throw new ArgumentNullException(nameof(key)); @@ -42,7 +42,7 @@ public T Get(string key) resultObject = collectionTuple.Item1;// return the actual collection } - return ReturnOnlyChangedValues && store[key].Item1 || !ReturnOnlyChangedValues ? (T)resultObject : default; + return ReturnOnlyChangedValues && store[key].Item1 || !ReturnOnlyChangedValues ? (T)resultObject! : default; } return default; } @@ -52,17 +52,17 @@ public T Get(string key) /// /// The key to use /// The object value to store - public void Set(string key, T value) + public void Set(string key, T? value) { if(string.IsNullOrEmpty(key)) throw new ArgumentNullException(nameof(key)); - var valueToAdd = new Tuple(InitializationCompleted, value); + var valueToAdd = new Tuple(InitializationCompleted, value); //If we are adding a collection, keep track of the size incase its modified with a call to Add or Remove if(value is ICollection collection) - valueToAdd = new Tuple(InitializationCompleted, new Tuple(collection, collection.Count)); + valueToAdd = new Tuple(InitializationCompleted, new Tuple(collection, collection.Count)); - Tuple oldValue = null; + Tuple? oldValue = null; if(!store.TryAdd(key, valueToAdd)) { oldValue = store[key]; @@ -85,13 +85,13 @@ public void Set(string key, T value) /// Enumerate the values in the store based on the configuration value. /// /// A collection of changed values or the whole store based on the configuration value. - public IEnumerable> Enumerate() + public IEnumerable> Enumerate() { if(ReturnOnlyChangedValues)// refresh the state of collection properties if they've changed in size. store.ToList().ForEach(x => EnsureCollectionPropertyIsConsistent(x.Key,x.Value.Item2)); return (ReturnOnlyChangedValues ? store.Where(x => x.Value.Item1) : store) - .Select(x => new KeyValuePair(x.Key, x.Value.Item2)); + .Select(x => new KeyValuePair(x.Key, x.Value.Item2)); } /// @@ -108,7 +108,7 @@ public IEnumerable EnumerateKeysForValuesChangedToNull() /// /// The callback to add /// The id of the subscription - public string Subscribe(Action callback) + public string Subscribe(Action callback) { var id = Guid.NewGuid().ToString(); Subscribe(callback, id); @@ -120,7 +120,7 @@ public string Subscribe(Action callback) /// /// The callback to add /// The subscription id to use for subscription - public void Subscribe(Action callback, string subscriptionId) + public void Subscribe(Action callback, string subscriptionId) { if(string.IsNullOrEmpty(subscriptionId)) throw new ArgumentNullException(nameof(subscriptionId)); @@ -161,7 +161,7 @@ public bool InitializationCompleted } } - private void EnsureCollectionPropertyIsConsistent(string key, object storeItem) + private void EnsureCollectionPropertyIsConsistent(string key, object? storeItem) { if(storeItem is Tuple collectionTuple // check if we put in a collection annotated with the size && collectionTuple.Item2 != collectionTuple.Item1.Count) // and the size has changed since we last updated From 89278e898114afa89a0776323924a61a9b5413bb Mon Sep 17 00:00:00 2001 From: Andrew Omondi Date: Fri, 13 Jan 2023 11:05:19 +0300 Subject: [PATCH 2/3] Fix sonarcloud code smells --- src/RequestInformation.cs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/RequestInformation.cs b/src/RequestInformation.cs index 5f55e95a..3438cf1a 100644 --- a/src/RequestInformation.cs +++ b/src/RequestInformation.cs @@ -67,7 +67,7 @@ public Uri URI { /// /// Object to be sanitized /// Sanitized object - private object GetSanitizedValue(object value) => value switch + private static object GetSanitizedValue(object value) => value switch { bool boolean => boolean.ToString().ToLower(),// pass in a lowercase string as the final url will be uppercase due to the way ToString() works for booleans DateTimeOffset dateTimeOffset => dateTimeOffset.ToString("o"),// Default to ISO 8601 for datetimeoffsets in the url. @@ -186,7 +186,7 @@ public void SetResponseHandler(IResponseHandler responseHandler) public void SetStreamContent(Stream content) { using var activity = _activitySource?.StartActivity(nameof(SetStreamContent)); - setRequestType(content, activity); + SetRequestType(content, activity); Content = content; Headers.Add(ContentTypeHeader, BinaryContentType); } @@ -201,8 +201,8 @@ public void SetStreamContent(Stream content) public void SetContentFromParsable(IRequestAdapter requestAdapter, string contentType, IEnumerable items) where T : IParsable { using var activity = _activitySource?.StartActivity(nameof(SetContentFromParsable)); - using var writer = getSerializationWriter(requestAdapter, contentType, items); - setRequestType(items.FirstOrDefault(static x => x != null), activity); + using var writer = GetSerializationWriter(requestAdapter, contentType, items); + SetRequestType(items.FirstOrDefault(static x => x != null), activity); writer.WriteCollectionOfObjectValues(null, items); Headers.Add(ContentTypeHeader, contentType); Content = writer.GetSerializedContent(); @@ -217,19 +217,19 @@ public void SetContentFromParsable(IRequestAdapter requestAdapter, string con public void SetContentFromParsable(IRequestAdapter requestAdapter, string contentType, T item) where T : IParsable { using var activity = _activitySource?.StartActivity(nameof(SetContentFromParsable)); - using var writer = getSerializationWriter(requestAdapter, contentType, item); - setRequestType(item, activity); + using var writer = GetSerializationWriter(requestAdapter, contentType, item); + SetRequestType(item, activity); writer.WriteObjectValue(null, item); Headers.Add(ContentTypeHeader, contentType); Content = writer.GetSerializedContent(); } - private void setRequestType(object? result, Activity? activity) + private static void SetRequestType(object? result, Activity? activity) { if (activity == null) return; if (result == null) return; activity.SetTag("com.microsoft.kiota.request.type", result.GetType().FullName); } - private ISerializationWriter getSerializationWriter(IRequestAdapter requestAdapter, string contentType, T item) + private static ISerializationWriter GetSerializationWriter(IRequestAdapter requestAdapter, string contentType, T item) { if(string.IsNullOrEmpty(contentType)) throw new ArgumentNullException(nameof(contentType)); if(requestAdapter == null) throw new ArgumentNullException(nameof(requestAdapter)); @@ -246,8 +246,8 @@ private ISerializationWriter getSerializationWriter(IRequestAdapter requestAd public void SetContentFromScalarCollection(IRequestAdapter requestAdapter, string contentType, IEnumerable items) { using var activity = _activitySource?.StartActivity(nameof(SetContentFromScalarCollection)); - using var writer = getSerializationWriter(requestAdapter, contentType, items); - setRequestType(items.FirstOrDefault(static x => x != null), activity); + using var writer = GetSerializationWriter(requestAdapter, contentType, items); + SetRequestType(items.FirstOrDefault(static x => x != null), activity); writer.WriteCollectionOfPrimitiveValues(null, items); Headers.Add(ContentTypeHeader, contentType); Content = writer.GetSerializedContent(); @@ -262,8 +262,8 @@ public void SetContentFromScalarCollection(IRequestAdapter requestAdapter, st public void SetContentFromScalar(IRequestAdapter requestAdapter, string contentType, T item) { using var activity = _activitySource?.StartActivity(nameof(SetContentFromScalar)); - using var writer = getSerializationWriter(requestAdapter, contentType, item); - setRequestType(item, activity); + using var writer = GetSerializationWriter(requestAdapter, contentType, item); + SetRequestType(item, activity); switch(item) { case string s: From 8a58f9ae72587869f59260f9e12fa2de7ea1a468 Mon Sep 17 00:00:00 2001 From: Andrew Omondi Date: Tue, 17 Jan 2023 09:02:14 +0300 Subject: [PATCH 3/3] Changes target to netstandard2.1 --- .../RequestHeadersTests.cs | 9 +++++---- src/Microsoft.Kiota.Abstractions.csproj | 2 +- src/RequestHeaders.cs | 4 +--- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/Microsoft.Kiota.Abstractions.Tests/RequestHeadersTests.cs b/Microsoft.Kiota.Abstractions.Tests/RequestHeadersTests.cs index 4d25541f..daa00cc6 100644 --- a/Microsoft.Kiota.Abstractions.Tests/RequestHeadersTests.cs +++ b/Microsoft.Kiota.Abstractions.Tests/RequestHeadersTests.cs @@ -42,7 +42,7 @@ public void RemovesValue() { instance.Remove("name", "value"); Assert.Equal(new [] { "value2" }, instance["name"]); instance.Remove("name", "value2"); - Assert.Null(instance["name"]); + Assert.Throws(() => instance["name"]); } [Fact] public void Removes() { @@ -50,7 +50,7 @@ public void Removes() { instance.Add("name", "value"); instance.Add("name", "value2"); Assert.True(instance.Remove("name")); - Assert.Null(instance["name"]); + Assert.Throws(() => instance["name"]); Assert.False(instance.Remove("name")); } [Fact] @@ -59,7 +59,7 @@ public void RemovesKVP() { instance.Add("name", "value"); instance.Add("name", "value2"); Assert.True(instance.Remove(new KeyValuePair>("name", new [] { "value", "value2" }))); - Assert.Null(instance["name"]); + Assert.Throws(() => instance["name"]); Assert.False(instance.Remove("name")); } [Fact] @@ -68,7 +68,8 @@ public void Clears() { instance.Add("name", "value"); instance.Add("name", "value2"); instance.Clear(); - Assert.Null(instance["name"]); + Assert.Throws(() => instance["name"]); + Assert.Empty(instance.Keys); } [Fact] public void GetsEnumerator() { diff --git a/src/Microsoft.Kiota.Abstractions.csproj b/src/Microsoft.Kiota.Abstractions.csproj index 47b297c8..7fcf941e 100644 --- a/src/Microsoft.Kiota.Abstractions.csproj +++ b/src/Microsoft.Kiota.Abstractions.csproj @@ -6,7 +6,7 @@ © Microsoft Corporation. All rights reserved. Kiota Abstractions Library for dotnet Microsoft - netstandard2.0;net6.0; + netstandard2.0;netstandard2.1; latest true https://github.com/microsoft/kiota-abstractions-dotnet diff --git a/src/RequestHeaders.cs b/src/RequestHeaders.cs index 0de4df2f..079e2043 100644 --- a/src/RequestHeaders.cs +++ b/src/RequestHeaders.cs @@ -35,9 +35,7 @@ public void Add(string headerName, params string[] headerValues) { /// public bool IsReadOnly => false; /// -#pragma warning disable CS8603 // Possible null reference return. //Can't change signature of overriden method implementation - public IEnumerable this[string key] { get => TryGetValue(key, out var result) ? result : null; set => Add(key, value); } -#pragma warning restore CS8603 // Possible null reference return. + public IEnumerable this[string key] { get => TryGetValue(key, out var result) ? result : throw new KeyNotFoundException($"Key not found : {key}"); set => Add(key, value); } /// /// Removes the specified value from the header with the specified name.