Merge branch 'net5' into ghactions

This commit is contained in:
Jonas Dellinger 2020-11-14 09:43:08 +01:00
commit 6fc8b5a2f1
28 changed files with 111 additions and 90 deletions

View File

@ -2,7 +2,8 @@
"editor.detectIndentation": false, "editor.detectIndentation": false,
"editor.insertSpaces": true, "editor.insertSpaces": true,
"editor.tabSize": 2, "editor.tabSize": 2,
"omnisharp.enableEditorConfigSupport": true,
"files.associations": { "files.associations": {
"*.md": "mdx" "*.md": "mdx"
}, }
} }

View File

@ -3,7 +3,7 @@ namespace SpotifyAPI.Web.Auth
[System.Serializable] [System.Serializable]
public class AuthException : System.Exception public class AuthException : System.Exception
{ {
public AuthException(string error, string state) public AuthException(string? error, string? state)
{ {
Error = error; Error = error;
State = state; State = state;

View File

@ -35,16 +35,17 @@ namespace SpotifyAPI.Web.Auth
.WithModule(new ActionModule("/", HttpVerbs.Post, (ctx) => .WithModule(new ActionModule("/", HttpVerbs.Post, (ctx) =>
{ {
var query = ctx.Request.QueryString; var query = ctx.Request.QueryString;
if (query["error"] != null) var error = query["error"];
if (error != null)
{ {
throw new AuthException(query["error"], query["state"]); throw new AuthException(error, query["state"]);
} }
var requestType = query.Get("request_type"); var requestType = query.Get("request_type");
if (requestType == "token") if (requestType == "token")
{ {
ImplictGrantReceived?.Invoke(this, new ImplictGrantResponse( ImplictGrantReceived?.Invoke(this, new ImplictGrantResponse(
query["access_token"], query["token_type"], int.Parse(query["expires_in"]) query["access_token"]!, query["token_type"]!, int.Parse(query["expires_in"]!)
) )
{ {
State = query["state"] State = query["state"]
@ -52,7 +53,7 @@ namespace SpotifyAPI.Web.Auth
} }
if (requestType == "code") if (requestType == "code")
{ {
AuthorizationCodeReceived?.Invoke(this, new AuthorizationCodeResponse(query["code"]) AuthorizationCodeReceived?.Invoke(this, new AuthorizationCodeResponse(query["code"]!)
{ {
State = query["state"] State = query["state"]
}); });

View File

@ -10,6 +10,6 @@ namespace SpotifyAPI.Web.Auth
} }
public string Code { get; set; } = default!; public string Code { get; set; } = default!;
public string State { get; set; } = default!; public string? State { get; set; } = default!;
} }
} }

View File

@ -17,7 +17,7 @@ namespace SpotifyAPI.Web.Auth
public string AccessToken { get; set; } = default!; public string AccessToken { get; set; } = default!;
public string TokenType { get; set; } = default!; public string TokenType { get; set; } = default!;
public int ExpiresIn { get; set; } public int ExpiresIn { get; set; }
public string State { get; set; } = default!; public string? State { get; set; } = default!;
/// <summary> /// <summary>
/// Auto-Initalized to UTC Now /// Auto-Initalized to UTC Now

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.1;netstandard2.0</TargetFrameworks> <TargetFrameworks>net5.0;netstandard2.1;netstandard2.0</TargetFrameworks>
<LangVersion>8.0</LangVersion> <LangVersion>9.0</LangVersion>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<PackageId>SpotifyAPI.Web.Auth</PackageId> <PackageId>SpotifyAPI.Web.Auth</PackageId>
<Title>SpotifyAPI.Web.Auth</Title> <Title>SpotifyAPI.Web.Auth</Title>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework> <TargetFramework>net5.0</TargetFramework>
<UserSecretsId>da29eac4-4c22-4a7f-b393-379e83b60998</UserSecretsId> <UserSecretsId>da29eac4-4c22-4a7f-b393-379e83b60998</UserSecretsId>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@ -1,11 +1,10 @@
 <Router AppAssembly="@typeof(Program).Assembly">
<Router AppAssembly="@typeof(Program).Assembly"> <Found Context="routeData">
<Found Context="routeData"> <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" /> </Found>
</Found> <NotFound>
<NotFound> <LayoutView Layout="@typeof(MainLayout)">
<LayoutView Layout="@typeof(MainLayout)"> <p>Sorry, there's nothing at this address.</p>
<p>Sorry, there's nothing at this address.</p> </LayoutView>
</LayoutView> </NotFound>
</NotFound>
</Router> </Router>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework> <TargetFramework>net5.0</TargetFramework>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@ -1,10 +1,10 @@
<Router AppAssembly="@typeof(Program).Assembly"> <Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData"> <Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" /> <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found> </Found>
<NotFound> <NotFound>
<LayoutView Layout="@typeof(MainLayout)"> <LayoutView Layout="@typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p> <p>Sorry, there's nothing at this address.</p>
</LayoutView> </LayoutView>
</NotFound> </NotFound>
</Router> </Router>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework> <TargetFramework>net5.0</TargetFramework>
<RazorLangVersion>3.0</RazorLangVersion> <RazorLangVersion>3.0</RazorLangVersion>
</PropertyGroup> </PropertyGroup>

View File

@ -6,8 +6,8 @@
</ItemGroup> </ItemGroup>
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@ -6,8 +6,8 @@
</ItemGroup> </ItemGroup>
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup> </PropertyGroup>
</Project> </Project>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netcoreapp3.1;netcoreapp2.2</TargetFrameworks> <TargetFrameworks>net5.0;netcoreapp3.1;netcoreapp2.2</TargetFrameworks>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
</PropertyGroup> </PropertyGroup>

View File

@ -112,13 +112,13 @@ namespace SpotifyAPI.Web
Ensure.ArgumentNotNull(request, nameof(request)); Ensure.ArgumentNotNull(request, nameof(request));
Ensure.ArgumentNotNull(apiConnector, nameof(apiConnector)); Ensure.ArgumentNotNull(apiConnector, nameof(apiConnector));
var form = new List<KeyValuePair<string, string>> var form = new List<KeyValuePair<string?, string?>>
{ {
new KeyValuePair<string, string>("client_id", request.ClientId), new KeyValuePair<string?, string?>("client_id", request.ClientId),
new KeyValuePair<string, string>("grant_type", "authorization_code"), new KeyValuePair<string?, string?>("grant_type", "authorization_code"),
new KeyValuePair<string, string>("code", request.Code), new KeyValuePair<string?, string?>("code", request.Code),
new KeyValuePair<string, string>("redirect_uri", request.RedirectUri.ToString()), new KeyValuePair<string?, string?>("redirect_uri", request.RedirectUri.ToString()),
new KeyValuePair<string, string>("code_verifier", request.CodeVerifier), new KeyValuePair<string?, string?>("code_verifier", request.CodeVerifier),
}; };
return SendOAuthRequest<PKCETokenResponse>(apiConnector, form, null, null); return SendOAuthRequest<PKCETokenResponse>(apiConnector, form, null, null);
@ -129,11 +129,11 @@ namespace SpotifyAPI.Web
Ensure.ArgumentNotNull(request, nameof(request)); Ensure.ArgumentNotNull(request, nameof(request));
Ensure.ArgumentNotNull(apiConnector, nameof(apiConnector)); Ensure.ArgumentNotNull(apiConnector, nameof(apiConnector));
var form = new List<KeyValuePair<string, string>> var form = new List<KeyValuePair<string?, string?>>
{ {
new KeyValuePair<string, string>("client_id", request.ClientId), new KeyValuePair<string?, string?>("client_id", request.ClientId),
new KeyValuePair<string, string>("grant_type", "refresh_token"), new KeyValuePair<string?, string?>("grant_type", "refresh_token"),
new KeyValuePair<string, string>("refresh_token", request.RefreshToken), new KeyValuePair<string?, string?>("refresh_token", request.RefreshToken),
}; };
return SendOAuthRequest<PKCETokenResponse>(apiConnector, form, null, null); return SendOAuthRequest<PKCETokenResponse>(apiConnector, form, null, null);
@ -146,9 +146,9 @@ namespace SpotifyAPI.Web
Ensure.ArgumentNotNull(request, nameof(request)); Ensure.ArgumentNotNull(request, nameof(request));
Ensure.ArgumentNotNull(apiConnector, nameof(apiConnector)); Ensure.ArgumentNotNull(apiConnector, nameof(apiConnector));
var form = new List<KeyValuePair<string, string>> var form = new List<KeyValuePair<string?, string?>>
{ {
new KeyValuePair<string, string>("refresh_token", request.RefreshToken) new KeyValuePair<string?, string?>("refresh_token", request.RefreshToken)
}; };
#pragma warning disable CA2000 #pragma warning disable CA2000
return apiConnector.Post<AuthorizationCodeRefreshResponse>( return apiConnector.Post<AuthorizationCodeRefreshResponse>(
@ -164,9 +164,9 @@ namespace SpotifyAPI.Web
Ensure.ArgumentNotNull(request, nameof(request)); Ensure.ArgumentNotNull(request, nameof(request));
Ensure.ArgumentNotNull(apiConnector, nameof(apiConnector)); Ensure.ArgumentNotNull(apiConnector, nameof(apiConnector));
var form = new List<KeyValuePair<string, string>> var form = new List<KeyValuePair<string?, string?>>
{ {
new KeyValuePair<string, string>("code", request.Code) new KeyValuePair<string?, string?>("code", request.Code)
}; };
#pragma warning disable CA2000 #pragma warning disable CA2000
@ -183,9 +183,9 @@ namespace SpotifyAPI.Web
Ensure.ArgumentNotNull(request, nameof(request)); Ensure.ArgumentNotNull(request, nameof(request));
Ensure.ArgumentNotNull(apiConnector, nameof(apiConnector)); Ensure.ArgumentNotNull(apiConnector, nameof(apiConnector));
var form = new List<KeyValuePair<string, string>> var form = new List<KeyValuePair<string?, string?>>
{ {
new KeyValuePair<string, string>("grant_type", "client_credentials") new KeyValuePair<string?, string?>("grant_type", "client_credentials")
}; };
return SendOAuthRequest<ClientCredentialsTokenResponse>(apiConnector, form, request.ClientId, request.ClientSecret); return SendOAuthRequest<ClientCredentialsTokenResponse>(apiConnector, form, request.ClientId, request.ClientSecret);
@ -198,10 +198,10 @@ namespace SpotifyAPI.Web
Ensure.ArgumentNotNull(request, nameof(request)); Ensure.ArgumentNotNull(request, nameof(request));
Ensure.ArgumentNotNull(apiConnector, nameof(apiConnector)); Ensure.ArgumentNotNull(apiConnector, nameof(apiConnector));
var form = new List<KeyValuePair<string, string>> var form = new List<KeyValuePair<string?, string?>>
{ {
new KeyValuePair<string, string>("grant_type", "refresh_token"), new KeyValuePair<string?, string?>("grant_type", "refresh_token"),
new KeyValuePair<string, string>("refresh_token", request.RefreshToken) new KeyValuePair<string?, string?>("refresh_token", request.RefreshToken)
}; };
return SendOAuthRequest<AuthorizationCodeRefreshResponse>(apiConnector, form, request.ClientId, request.ClientSecret); return SendOAuthRequest<AuthorizationCodeRefreshResponse>(apiConnector, form, request.ClientId, request.ClientSecret);
@ -214,11 +214,11 @@ namespace SpotifyAPI.Web
Ensure.ArgumentNotNull(request, nameof(request)); Ensure.ArgumentNotNull(request, nameof(request));
Ensure.ArgumentNotNull(apiConnector, nameof(apiConnector)); Ensure.ArgumentNotNull(apiConnector, nameof(apiConnector));
var form = new List<KeyValuePair<string, string>> var form = new List<KeyValuePair<string?, string?>>
{ {
new KeyValuePair<string, string>("grant_type", "authorization_code"), new KeyValuePair<string?, string?>("grant_type", "authorization_code"),
new KeyValuePair<string, string>("code", request.Code), new KeyValuePair<string?, string?>("code", request.Code),
new KeyValuePair<string, string>("redirect_uri", request.RedirectUri.ToString()) new KeyValuePair<string?, string?>("redirect_uri", request.RedirectUri.ToString())
}; };
return SendOAuthRequest<AuthorizationCodeTokenResponse>(apiConnector, form, request.ClientId, request.ClientSecret); return SendOAuthRequest<AuthorizationCodeTokenResponse>(apiConnector, form, request.ClientId, request.ClientSecret);
@ -226,7 +226,7 @@ namespace SpotifyAPI.Web
private static Task<T> SendOAuthRequest<T>( private static Task<T> SendOAuthRequest<T>(
IAPIConnector apiConnector, IAPIConnector apiConnector,
List<KeyValuePair<string, string>> form, List<KeyValuePair<string?, string?>> form,
string? clientId, string? clientId,
string? clientSecret) string? clientSecret)
{ {

View File

@ -25,11 +25,17 @@ namespace SpotifyAPI.Web
var page = firstPage; var page = firstPage;
var results = new List<T>(); var results = new List<T>();
results.AddRange(firstPage.Items); if (page.Items != null)
{
results.AddRange(page.Items);
}
while (page.Next != null && await ShouldContinue(results, page).ConfigureAwait(false)) while (page.Next != null && await ShouldContinue(results, page).ConfigureAwait(false))
{ {
page = await connector.Get<Paging<T>>(new Uri(page.Next, UriKind.Absolute)).ConfigureAwait(false); page = await connector.Get<Paging<T>>(new Uri(page.Next, UriKind.Absolute)).ConfigureAwait(false);
results.AddRange(page.Items); if (page.Items != null)
{
results.AddRange(page.Items);
}
} }
return results; return results;
@ -45,12 +51,18 @@ namespace SpotifyAPI.Web
var page = firstPage; var page = firstPage;
var results = new List<T>(); var results = new List<T>();
results.AddRange(firstPage.Items); if (page.Items != null)
{
results.AddRange(page.Items);
}
while (page.Next != null && await ShouldContinue(results, page).ConfigureAwait(false)) while (page.Next != null && await ShouldContinue(results, page).ConfigureAwait(false))
{ {
var next = await connector.Get<TNext>(new Uri(page.Next, UriKind.Absolute)).ConfigureAwait(false); var next = await connector.Get<TNext>(new Uri(page.Next, UriKind.Absolute)).ConfigureAwait(false);
page = mapper(next); page = mapper(next);
results.AddRange(page.Items); if (page.Items != null)
{
results.AddRange(page.Items);
}
} }
return results; return results;

View File

@ -191,7 +191,7 @@ namespace SpotifyAPI.Web
var firstPage = await getFirstPage().ConfigureAwait(false); var firstPage = await getFirstPage().ConfigureAwait(false);
await foreach (var item in (paginator ?? DefaultPaginator) await foreach (var item in (paginator ?? DefaultPaginator)
.Paginate(firstPage, mapper, _apiConnector) .Paginate(firstPage, mapper, _apiConnector, cancellationToken)
.WithCancellation(cancellationToken) .WithCancellation(cancellationToken)
) )
{ {
@ -223,7 +223,7 @@ namespace SpotifyAPI.Web
var firstPage = await firstPageTask.ConfigureAwait(false); var firstPage = await firstPageTask.ConfigureAwait(false);
await foreach (var item in (paginator ?? DefaultPaginator) await foreach (var item in (paginator ?? DefaultPaginator)
.Paginate(firstPage, mapper, _apiConnector) .Paginate(firstPage, mapper, _apiConnector, cancellationToken)
.WithCancellation(cancellationToken) .WithCancellation(cancellationToken)
) )
{ {

View File

@ -14,7 +14,7 @@ namespace SpotifyAPI.Web
{ {
Ensure.ArgumentNotNull(response, nameof(response)); Ensure.ArgumentNotNull(response, nameof(response));
if (response.Headers.TryGetValue("Retry-After", out string retryAfter)) if (response.Headers.TryGetValue("Retry-After", out string? retryAfter))
{ {
RetryAfter = TimeSpan.FromSeconds(int.Parse(retryAfter, CultureInfo.InvariantCulture)); RetryAfter = TimeSpan.FromSeconds(int.Parse(retryAfter, CultureInfo.InvariantCulture));
} }

View File

@ -254,7 +254,7 @@ namespace SpotifyAPI.Web.Http
{ {
var request = CreateRequest(uri, method, parameters, body, headers); var request = CreateRequest(uri, method, parameters, body, headers);
IAPIResponse<T> apiResponse = await DoSerializedRequest<T>(request).ConfigureAwait(false); IAPIResponse<T> apiResponse = await DoSerializedRequest<T>(request).ConfigureAwait(false);
return apiResponse.Body; return apiResponse.Body!;
} }
public async Task<IResponse> SendAPIRequestDetailed( public async Task<IResponse> SendAPIRequestDetailed(

View File

@ -2,7 +2,7 @@ namespace SpotifyAPI.Web.Http
{ {
public class APIResponse<T> : IAPIResponse<T> public class APIResponse<T> : IAPIResponse<T>
{ {
public APIResponse(IResponse response, T body = default) public APIResponse(IResponse response, T? body = default)
{ {
Ensure.ArgumentNotNull(response, nameof(response)); Ensure.ArgumentNotNull(response, nameof(response));
@ -10,7 +10,7 @@ namespace SpotifyAPI.Web.Http
Response = response; Response = response;
} }
public T Body { get; set; } public T? Body { get; set; }
public IResponse Response { get; set; } public IResponse Response { get; set; }
} }

View File

@ -2,7 +2,7 @@ namespace SpotifyAPI.Web.Http
{ {
public interface IAPIResponse<out T> public interface IAPIResponse<out T>
{ {
T Body { get; } T? Body { get; }
IResponse Response { get; } IResponse Response { get; }
} }

View File

@ -15,7 +15,9 @@ namespace SpotifyAPI.Web.Http
string? parameters = null; string? parameters = null;
if (request.Parameters != null) if (request.Parameters != null)
{ {
parameters = string.Join(",", request.Parameters?.Select(kv => kv.Key + "=" + kv.Value).ToArray()); parameters = string.Join(",",
request.Parameters?.Select(kv => kv.Key + "=" + kv.Value)?.ToArray() ?? Array.Empty<string>()
);
} }
Console.WriteLine(OnRequestFormat, request.Method, request.Endpoint, parameters, request.Body); Console.WriteLine(OnRequestFormat, request.Method, request.Endpoint, parameters, request.Body);
@ -28,7 +30,7 @@ namespace SpotifyAPI.Web.Http
#if NETSTANDARD2_0 #if NETSTANDARD2_0
string? body = response.Body?.ToString().Replace("\n", ""); string? body = response.Body?.ToString().Replace("\n", "");
#else #else
string? body = response.Body?.ToString().Replace("\n", "", StringComparison.InvariantCulture); string? body = response.Body?.ToString()?.Replace("\n", "", StringComparison.InvariantCulture);
#endif #endif
body = body?.Substring(0, Math.Min(50, body?.Length ?? 0)); body = body?.Substring(0, Math.Min(50, body?.Length ?? 0));

View File

@ -37,9 +37,12 @@ namespace SpotifyAPI.Web
_bodyParamsCache[type] = new List<(PropertyInfo, BodyParamAttribute)>(); _bodyParamsCache[type] = new List<(PropertyInfo, BodyParamAttribute)>();
foreach (var prop in bodyProps) foreach (var prop in bodyProps)
{ {
var attribute = (BodyParamAttribute)prop.GetCustomAttribute(typeof(BodyParamAttribute)); var attribute = prop.GetCustomAttribute<BodyParamAttribute>();
_bodyParamsCache[type].Add((prop, attribute)); if (attribute != null)
AddBodyParam(body, prop, attribute); {
_bodyParamsCache[type].Add((prop, attribute));
AddBodyParam(body, prop, attribute);
}
} }
} }
@ -48,7 +51,7 @@ namespace SpotifyAPI.Web
private void AddBodyParam(JObject body, PropertyInfo prop, BodyParamAttribute attribute) private void AddBodyParam(JObject body, PropertyInfo prop, BodyParamAttribute attribute)
{ {
object value = prop.GetValue(this); object? value = prop.GetValue(this);
if (value != null) if (value != null)
{ {
body[attribute.Key ?? prop.Name] = JToken.FromObject(value); body[attribute.Key ?? prop.Name] = JToken.FromObject(value);
@ -81,9 +84,12 @@ namespace SpotifyAPI.Web
_queryParamsCache[type] = new List<(PropertyInfo, QueryParamAttribute)>(); _queryParamsCache[type] = new List<(PropertyInfo, QueryParamAttribute)>();
foreach (var prop in queryProps) foreach (var prop in queryProps)
{ {
var attribute = (QueryParamAttribute)prop.GetCustomAttribute(typeof(QueryParamAttribute)); var attribute = prop.GetCustomAttribute<QueryParamAttribute>();
_queryParamsCache[type].Add((prop, attribute)); if (attribute != null)
AddQueryParam(queryParams, prop, attribute); {
_queryParamsCache[type].Add((prop, attribute));
AddQueryParam(queryParams, prop, attribute);
}
} }
} }
@ -94,7 +100,7 @@ namespace SpotifyAPI.Web
private void AddQueryParam(Dictionary<string, string> queryParams, PropertyInfo prop, QueryParamAttribute attribute) private void AddQueryParam(Dictionary<string, string> queryParams, PropertyInfo prop, QueryParamAttribute attribute)
{ {
object value = prop.GetValue(this); object? value = prop.GetValue(this);
if (value != null) if (value != null)
{ {
if (value is IList<string> list) if (value is IList<string> list)
@ -140,7 +146,7 @@ namespace SpotifyAPI.Web
} }
else else
{ {
queryParams.Add(attribute.Key ?? prop.Name, value.ToString()); queryParams.Add(attribute.Key ?? prop.Name, value.ToString() ?? throw new Exception("ToString was null on a value"));
} }
} }
} }

View File

@ -70,6 +70,7 @@ namespace SpotifyAPI.Web
public Task<IResponse> HandleRetry(IRequest request, IResponse response, IRetryHandler.RetryFunc retry) public Task<IResponse> HandleRetry(IRequest request, IResponse response, IRetryHandler.RetryFunc retry)
{ {
Ensure.ArgumentNotNull(response, nameof(response)); Ensure.ArgumentNotNull(response, nameof(response));
Ensure.ArgumentNotNull(retry, nameof(retry));
return HandleRetryInternally(request, response, retry, RetryTimes); return HandleRetryInternally(request, response, retry, RetryTimes);
} }

View File

@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.1;netstandard2.0</TargetFrameworks> <TargetFrameworks>net5.0;netstandard2.1;netstandard2.0</TargetFrameworks>
<LangVersion>8.0</LangVersion> <LangVersion>9.0</LangVersion>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<PackageId>SpotifyAPI.Web</PackageId> <PackageId>SpotifyAPI.Web</PackageId>
<Title>SpotifyAPI.Web</Title> <Title>SpotifyAPI.Web</Title>

View File

@ -15,11 +15,10 @@ namespace SpotifyAPI.Web
public string Value { get; set; } public string Value { get; set; }
#if NETSTANDARD2_1
public static bool GetValue(Type enumType, Enum enumValue, [NotNullWhen(true)] out string? result)
#endif
#if NETSTANDARD2_0 #if NETSTANDARD2_0
public static bool GetValue(Type enumType, Enum enumValue, out string? result) public static bool GetValue(Type enumType, Enum enumValue, out string? result)
#else
public static bool GetValue(Type enumType, Enum enumValue, [NotNullWhen(true)] out string? result)
#endif #endif
{ {
Ensure.ArgumentNotNull(enumType, nameof(enumType)); Ensure.ArgumentNotNull(enumType, nameof(enumType));

View File

@ -19,9 +19,9 @@ namespace SpotifyAPI.Web
var newParameters = new Dictionary<string, string>(); var newParameters = new Dictionary<string, string>();
NameValueCollection existingParameters = HttpUtility.ParseQueryString(uri.Query); NameValueCollection existingParameters = HttpUtility.ParseQueryString(uri.Query);
foreach (string key in existingParameters.AllKeys) foreach (string key in existingParameters)
{ {
newParameters.Add(key, existingParameters[key]); newParameters.Add(key, existingParameters[key]!);
} }
foreach (KeyValuePair<string, string> parameter in parameters) foreach (KeyValuePair<string, string> parameter in parameters)
{ {

View File

@ -11,16 +11,16 @@ namespace SpotifyAPI.Web
_formatter = new URIParameterFormatter(); _formatter = new URIParameterFormatter();
} }
public object? GetFormat(Type formatType) public object? GetFormat(Type? formatType)
{ {
return formatType == typeof(ICustomFormatter) ? _formatter : null; return formatType == typeof(ICustomFormatter) ? _formatter : null;
} }
private class URIParameterFormatter : ICustomFormatter private class URIParameterFormatter : ICustomFormatter
{ {
public string Format(string format, object arg, IFormatProvider formatProvider) public string Format(string? format, object? arg, IFormatProvider? formatProvider)
{ {
return HttpUtility.UrlEncode(arg.ToString()); return HttpUtility.UrlEncode(arg?.ToString()) ?? string.Empty;
} }
} }
} }