Enabled nullable for most projects

This commit is contained in:
Jonas Dellinger 2020-05-25 18:00:38 +02:00
parent 020b60bec2
commit f1ca557c6e
157 changed files with 598 additions and 439 deletions

View File

@ -14,7 +14,7 @@ namespace SpotifyAPI.Web.Auth
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
public string Error { get; set; }
public string State { get; set; }
public string? Error { get; set; }
public string? State { get; set; }
}
}

View File

@ -12,13 +12,13 @@ namespace SpotifyAPI.Web.Auth
{
public class EmbedIOAuthServer : IAuthServer
{
public event Func<object, AuthorizationCodeResponse, Task> AuthorizationCodeReceived;
public event Func<object, ImplictGrantResponse, Task> ImplictGrantReceived;
public event Func<object, AuthorizationCodeResponse, Task>? AuthorizationCodeReceived;
public event Func<object, ImplictGrantResponse, Task>? ImplictGrantReceived;
private const string AssetsResourcePath = "SpotifyAPI.Web.Auth.Resources.auth_assets";
private const string DefaultResourcePath = "SpotifyAPI.Web.Auth.Resources.default_site";
private CancellationTokenSource _cancelTokenSource;
private CancellationTokenSource? _cancelTokenSource;
private readonly WebServer _webServer;
public EmbedIOAuthServer(Uri baseUri, int port)
@ -76,7 +76,7 @@ namespace SpotifyAPI.Web.Auth
public Task Stop()
{
_cancelTokenSource.Cancel();
_cancelTokenSource?.Cancel();
return Task.CompletedTask;
}

View File

@ -9,7 +9,7 @@ namespace SpotifyAPI.Web.Auth
Code = code;
}
public string Code { get; set; }
public string State { get; set; }
public string Code { get; set; } = default!;
public string State { get; set; } = default!;
}
}

View File

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

View File

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

View File

@ -3,6 +3,8 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<LangVersion>8.0</LangVersion>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>

View File

@ -1,4 +1,3 @@
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using System;
@ -18,12 +17,19 @@ namespace Example.CLI.PersistentConfig
public class Program
{
private const string CredentialsPath = "credentials.json";
private static readonly string clientId = Environment.GetEnvironmentVariable("SPOTIFY_CLIENT_ID");
private static readonly string clientSecret = Environment.GetEnvironmentVariable("SPOTIFY_CLIENT_SECRET");
private static EmbedIOAuthServer _server;
private static readonly string? clientId = Environment.GetEnvironmentVariable("SPOTIFY_CLIENT_ID");
private static readonly string? clientSecret = Environment.GetEnvironmentVariable("SPOTIFY_CLIENT_SECRET");
private static readonly EmbedIOAuthServer _server = new EmbedIOAuthServer(new Uri("http://localhost:5000/callback"), 5000);
public static async Task<int> Main()
{
if (string.IsNullOrEmpty(clientId) || string.IsNullOrEmpty(clientSecret))
{
throw new NullReferenceException(
"Please set SPOTIFY_CLIENT_ID and SPOTIFY_CLIENT_SECRET via environment variables before starting the program"
);
}
if (File.Exists(CredentialsPath))
{
await Start();
@ -42,7 +48,7 @@ namespace Example.CLI.PersistentConfig
var json = await File.ReadAllTextAsync(CredentialsPath);
var token = JsonConvert.DeserializeObject<AuthorizationCodeTokenResponse>(json);
var authenticator = new AuthorizationCodeAuthenticator(clientId, clientSecret, token);
var authenticator = new AuthorizationCodeAuthenticator(clientId!, clientSecret!, token);
authenticator.TokenRefreshed += (sender, token) => File.WriteAllText(CredentialsPath, JsonConvert.SerializeObject(token));
var config = SpotifyClientConfig.CreateDefault()
@ -61,11 +67,10 @@ namespace Example.CLI.PersistentConfig
private static async Task StartAuthentication()
{
_server = new EmbedIOAuthServer(new Uri("http://localhost:5000/callback"), 5000);
await _server.Start();
_server.AuthorizationCodeReceived += OnAuthorizationCodeReceived;
var request = new LoginRequest(_server.BaseUri, clientId, LoginRequest.ResponseType.Code)
var request = new LoginRequest(_server.BaseUri, clientId!, LoginRequest.ResponseType.Code)
{
Scope = new List<string> { UserReadEmail, UserReadPrivate, PlaylistReadPrivate }
};
@ -85,7 +90,7 @@ namespace Example.CLI.PersistentConfig
{
await _server.Stop();
AuthorizationCodeTokenResponse token = await new OAuthClient().RequestToken(
new AuthorizationCodeTokenRequest(clientId, clientSecret, response.Code, _server.BaseUri)
new AuthorizationCodeTokenRequest(clientId!, clientSecret!, response.Code, _server.BaseUri)
);
await File.WriteAllTextAsync(CredentialsPath, JsonConvert.SerializeObject(token));

View File

@ -28,7 +28,7 @@ namespace SpotifyAPI.Web
await client.Get(userId);
api.Verify(a => a.Get<PublicUser>(SpotifyUrls.User("userId")), Times.Once);
api.Verify(a => a.Get<PublicUser>(SpotifyUrls.User(userId)), Times.Once);
}
}
}

View File

@ -101,6 +101,7 @@ namespace SpotifyAPI.Web
private static APIConnector ValidateConfig(SpotifyClientConfig config)
{
Ensure.ArgumentNotNull(config, nameof(config));
return new APIConnector(
config.BaseAddress,
config.Authenticator,

View File

@ -7,11 +7,11 @@ namespace SpotifyAPI.Web
public class SpotifyClientConfig
{
public Uri BaseAddress { get; private set; }
public IAuthenticator Authenticator { get; private set; }
public IAuthenticator? Authenticator { get; private set; }
public IJSONSerializer JSONSerializer { get; private set; }
public IHTTPClient HTTPClient { get; private set; }
public IHTTPLogger HTTPLogger { get; private set; }
public IRetryHandler RetryHandler { get; private set; }
public IHTTPLogger? HTTPLogger { get; private set; }
public IRetryHandler? RetryHandler { get; private set; }
public IPaginator DefaultPaginator { get; private set; }
/// <summary>
@ -26,11 +26,11 @@ namespace SpotifyAPI.Web
/// <param name="defaultPaginator"></param>
public SpotifyClientConfig(
Uri baseAddress,
IAuthenticator authenticator,
IAuthenticator? authenticator,
IJSONSerializer jsonSerializer,
IHTTPClient httpClient,
IRetryHandler retryHandler,
IHTTPLogger httpLogger,
IRetryHandler? retryHandler,
IHTTPLogger? httpLogger,
IPaginator defaultPaginator
)
{

View File

@ -7,9 +7,9 @@ using System.Runtime.Serialization;
namespace SpotifyAPI.Web
{
[Serializable]
public class APIException : System.Exception
public class APIException : Exception
{
public IResponse Response { get; set; }
public IResponse? Response { get; set; }
public APIException(IResponse response) : base(ParseAPIErrorMessage(response))
{
@ -26,7 +26,7 @@ namespace SpotifyAPI.Web
{
}
public APIException(string message, System.Exception innerException) : base(message, innerException)
public APIException(string message, Exception innerException) : base(message, innerException)
{
}
@ -35,7 +35,7 @@ namespace SpotifyAPI.Web
Response = info.GetValue("APIException.Response", typeof(IResponse)) as IResponse;
}
private static string ParseAPIErrorMessage(IResponse response)
private static string? ParseAPIErrorMessage(IResponse response)
{
var body = response.Body as string;
if (string.IsNullOrEmpty(body))
@ -44,7 +44,7 @@ namespace SpotifyAPI.Web
}
try
{
JObject bodyObject = JObject.Parse(body);
JObject bodyObject = JObject.Parse(body!);
JObject error = bodyObject.Value<JObject>("error");
if (error != null)
{

View File

@ -9,22 +9,22 @@ namespace SpotifyAPI.Web.Http
public class APIConnector : IAPIConnector
{
private readonly Uri _baseAddress;
private readonly IAuthenticator _authenticator;
private readonly IAuthenticator? _authenticator;
private readonly IJSONSerializer _jsonSerializer;
private readonly IHTTPClient _httpClient;
private readonly IRetryHandler _retryHandler;
private readonly IHTTPLogger _httpLogger;
private readonly IRetryHandler? _retryHandler;
private readonly IHTTPLogger? _httpLogger;
public APIConnector(Uri baseAddress, IAuthenticator authenticator) :
this(baseAddress, authenticator, new NewtonsoftJSONSerializer(), new NetHttpClient(), null, null)
{ }
public APIConnector(
Uri baseAddress,
IAuthenticator authenticator,
IAuthenticator? authenticator,
IJSONSerializer jsonSerializer,
IHTTPClient httpClient,
IRetryHandler retryHandler,
IHTTPLogger httpLogger)
IRetryHandler? retryHandler,
IHTTPLogger? httpLogger)
{
_baseAddress = baseAddress;
_authenticator = authenticator;
@ -41,21 +41,21 @@ namespace SpotifyAPI.Web.Http
return SendAPIRequest<T>(uri, HttpMethod.Delete);
}
public Task<T> Delete<T>(Uri uri, IDictionary<string, string> parameters)
public Task<T> Delete<T>(Uri uri, IDictionary<string, string>? parameters)
{
Ensure.ArgumentNotNull(uri, nameof(uri));
return SendAPIRequest<T>(uri, HttpMethod.Delete, parameters);
}
public Task<T> Delete<T>(Uri uri, IDictionary<string, string> parameters, object body)
public Task<T> Delete<T>(Uri uri, IDictionary<string, string>? parameters, object? body)
{
Ensure.ArgumentNotNull(uri, nameof(uri));
return SendAPIRequest<T>(uri, HttpMethod.Delete, parameters, body);
}
public async Task<HttpStatusCode> Delete(Uri uri, IDictionary<string, string> parameters, object body)
public async Task<HttpStatusCode> Delete(Uri uri, IDictionary<string, string>? parameters, object? body)
{
Ensure.ArgumentNotNull(uri, nameof(uri));
@ -70,14 +70,14 @@ namespace SpotifyAPI.Web.Http
return SendAPIRequest<T>(uri, HttpMethod.Get);
}
public Task<T> Get<T>(Uri uri, IDictionary<string, string> parameters)
public Task<T> Get<T>(Uri uri, IDictionary<string, string>? parameters)
{
Ensure.ArgumentNotNull(uri, nameof(uri));
return SendAPIRequest<T>(uri, HttpMethod.Get, parameters);
}
public async Task<HttpStatusCode> Get(Uri uri, IDictionary<string, string> parameters, object body)
public async Task<HttpStatusCode> Get(Uri uri, IDictionary<string, string>? parameters, object? body)
{
Ensure.ArgumentNotNull(uri, nameof(uri));
@ -92,28 +92,28 @@ namespace SpotifyAPI.Web.Http
return SendAPIRequest<T>(uri, HttpMethod.Post);
}
public Task<T> Post<T>(Uri uri, IDictionary<string, string> parameters)
public Task<T> Post<T>(Uri uri, IDictionary<string, string>? parameters)
{
Ensure.ArgumentNotNull(uri, nameof(uri));
return SendAPIRequest<T>(uri, HttpMethod.Post, parameters);
}
public Task<T> Post<T>(Uri uri, IDictionary<string, string> parameters, object body)
public Task<T> Post<T>(Uri uri, IDictionary<string, string>? parameters, object? body)
{
Ensure.ArgumentNotNull(uri, nameof(uri));
return SendAPIRequest<T>(uri, HttpMethod.Post, parameters, body);
}
public Task<T> Post<T>(Uri uri, IDictionary<string, string> parameters, object body, Dictionary<string, string> headers)
public Task<T> Post<T>(Uri uri, IDictionary<string, string>? parameters, object? body, Dictionary<string, string>? headers)
{
Ensure.ArgumentNotNull(uri, nameof(uri));
return SendAPIRequest<T>(uri, HttpMethod.Post, parameters, body, headers);
}
public async Task<HttpStatusCode> Post(Uri uri, IDictionary<string, string> parameters, object body)
public async Task<HttpStatusCode> Post(Uri uri, IDictionary<string, string>? parameters, object? body)
{
Ensure.ArgumentNotNull(uri, nameof(uri));
@ -128,21 +128,21 @@ namespace SpotifyAPI.Web.Http
return SendAPIRequest<T>(uri, HttpMethod.Put);
}
public Task<T> Put<T>(Uri uri, IDictionary<string, string> parameters)
public Task<T> Put<T>(Uri uri, IDictionary<string, string>? parameters)
{
Ensure.ArgumentNotNull(uri, nameof(uri));
return SendAPIRequest<T>(uri, HttpMethod.Put, parameters);
}
public Task<T> Put<T>(Uri uri, IDictionary<string, string> parameters, object body)
public Task<T> Put<T>(Uri uri, IDictionary<string, string>? parameters, object? body)
{
Ensure.ArgumentNotNull(uri, nameof(uri));
return SendAPIRequest<T>(uri, HttpMethod.Put, parameters, body);
}
public async Task<HttpStatusCode> Put(Uri uri, IDictionary<string, string> parameters, object body)
public async Task<HttpStatusCode> Put(Uri uri, IDictionary<string, string>? parameters, object? body)
{
Ensure.ArgumentNotNull(uri, nameof(uri));
@ -150,7 +150,7 @@ namespace SpotifyAPI.Web.Http
return response.StatusCode;
}
public async Task<HttpStatusCode> PutRaw(Uri uri, IDictionary<string, string> parameters, object body)
public async Task<HttpStatusCode> PutRaw(Uri uri, IDictionary<string, string>? parameters, object? body)
{
Ensure.ArgumentNotNull(uri, nameof(uri));
@ -166,19 +166,21 @@ namespace SpotifyAPI.Web.Http
private IRequest CreateRequest(
Uri uri,
HttpMethod method,
IDictionary<string, string> parameters,
object body,
IDictionary<string, string> headers
IDictionary<string, string>? parameters,
object? body,
IDictionary<string, string>? headers
)
{
Ensure.ArgumentNotNull(uri, nameof(uri));
Ensure.ArgumentNotNull(method, nameof(method));
return new Request(headers ?? new Dictionary<string, string>(), parameters ?? new Dictionary<string, string>())
return new Request(
_baseAddress,
uri,
method,
headers ?? new Dictionary<string, string>(),
parameters ?? new Dictionary<string, string>())
{
BaseAddress = _baseAddress,
Endpoint = uri,
Method = method,
Body = body
};
}
@ -222,16 +224,16 @@ namespace SpotifyAPI.Web.Http
|| request.Endpoint.AbsoluteUri.Contains("https://api.spotify.com", StringComparison.InvariantCulture))
#endif
{
await _authenticator.Apply(request, this).ConfigureAwait(false);
await _authenticator!.Apply(request, this).ConfigureAwait(false);
}
}
public Task<IResponse> SendRawRequest(
Uri uri,
HttpMethod method,
IDictionary<string, string> parameters = null,
object body = null,
IDictionary<string, string> headers = null
IDictionary<string, string>? parameters = null,
object? body = null,
IDictionary<string, string>? headers = null
)
{
var request = CreateRequest(uri, method, parameters, body, headers);
@ -241,9 +243,9 @@ namespace SpotifyAPI.Web.Http
public async Task<T> SendAPIRequest<T>(
Uri uri,
HttpMethod method,
IDictionary<string, string> parameters = null,
object body = null,
IDictionary<string, string> headers = null
IDictionary<string, string>? parameters = null,
object? body = null,
IDictionary<string, string>? headers = null
)
{
var request = CreateRequest(uri, method, parameters, body, headers);
@ -254,9 +256,9 @@ namespace SpotifyAPI.Web.Http
public async Task<IResponse> SendAPIRequestDetailed(
Uri uri,
HttpMethod method,
IDictionary<string, string> parameters = null,
object body = null,
IDictionary<string, string> headers = null
IDictionary<string, string>? parameters = null,
object? body = null,
IDictionary<string, string>? headers = null
)
{
var request = CreateRequest(uri, method, parameters, body, headers);

View File

@ -9,7 +9,7 @@ namespace SpotifyAPI.Web.Http
/// </summary>
public class AuthorizationCodeAuthenticator : IAuthenticator
{
public event EventHandler<AuthorizationCodeTokenResponse> TokenRefreshed;
public event EventHandler<AuthorizationCodeTokenResponse>? TokenRefreshed;
/// <summary>
/// Initiate a new instance. The token will be refreshed once it expires.

View File

@ -8,7 +8,7 @@ namespace SpotifyAPI.Web.Http
/// </summary>
public class CredentialsAuthenticator : IAuthenticator
{
private CredentialsTokenResponse _token;
private CredentialsTokenResponse? _token;
/// <summary>
/// Initiate a new instance. The first token will be fetched when the first API call occurs

View File

@ -17,32 +17,32 @@ namespace SpotifyAPI.Web.Http
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716")]
Task<T> Get<T>(Uri uri);
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716")]
Task<T> Get<T>(Uri uri, IDictionary<string, string> parameters);
Task<T> Get<T>(Uri uri, IDictionary<string, string>? parameters);
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716")]
Task<HttpStatusCode> Get(Uri uri, IDictionary<string, string> parameters, object body);
Task<HttpStatusCode> Get(Uri uri, IDictionary<string, string>? parameters, object? body);
Task<T> Post<T>(Uri uri);
Task<T> Post<T>(Uri uri, IDictionary<string, string> parameters);
Task<T> Post<T>(Uri uri, IDictionary<string, string> parameters, object body);
Task<T> Post<T>(Uri uri, IDictionary<string, string> parameters, object body, Dictionary<string, string> headers);
Task<HttpStatusCode> Post(Uri uri, IDictionary<string, string> parameters, object body);
Task<T> Post<T>(Uri uri, IDictionary<string, string>? parameters);
Task<T> Post<T>(Uri uri, IDictionary<string, string>? parameters, object? body);
Task<T> Post<T>(Uri uri, IDictionary<string, string>? parameters, object? body, Dictionary<string, string>? headers);
Task<HttpStatusCode> Post(Uri uri, IDictionary<string, string>? parameters, object? body);
Task<T> Put<T>(Uri uri);
Task<T> Put<T>(Uri uri, IDictionary<string, string> parameters);
Task<T> Put<T>(Uri uri, IDictionary<string, string> parameters, object body);
Task<HttpStatusCode> Put(Uri uri, IDictionary<string, string> parameters, object body);
Task<HttpStatusCode> PutRaw(Uri uri, IDictionary<string, string> parameters, object body);
Task<T> Put<T>(Uri uri, IDictionary<string, string>? parameters);
Task<T> Put<T>(Uri uri, IDictionary<string, string>? parameters, object? body);
Task<HttpStatusCode> Put(Uri uri, IDictionary<string, string>? parameters, object? body);
Task<HttpStatusCode> PutRaw(Uri uri, IDictionary<string, string>? parameters, object? body);
Task<T> Delete<T>(Uri uri);
Task<T> Delete<T>(Uri uri, IDictionary<string, string> parameters);
Task<T> Delete<T>(Uri uri, IDictionary<string, string> parameters, object body);
Task<HttpStatusCode> Delete(Uri uri, IDictionary<string, string> parameters, object body);
Task<T> Delete<T>(Uri uri, IDictionary<string, string>? parameters);
Task<T> Delete<T>(Uri uri, IDictionary<string, string>? parameters, object? body);
Task<HttpStatusCode> Delete(Uri uri, IDictionary<string, string>? parameters, object? body);
Task<T> SendAPIRequest<T>(
Uri uri, HttpMethod method,
IDictionary<string, string> parameters = null,
object body = null,
IDictionary<string, string> headers = null);
IDictionary<string, string>? parameters = null,
object? body = null,
IDictionary<string, string>? headers = null);
void SetRequestTimeout(TimeSpan timeout);
}

View File

@ -4,8 +4,8 @@ namespace SpotifyAPI.Web
{
string Host { get; }
int Port { get; }
string User { get; }
string Password { get; }
string? User { get; }
string? Password { get; }
bool SkipSSLCheck { get; }
/// <summary>
/// Whether to bypass the proxy server for local addresses.

View File

@ -16,6 +16,6 @@ namespace SpotifyAPI.Web.Http
HttpMethod Method { get; }
object Body { get; set; }
object? Body { get; set; }
}
}

View File

@ -5,12 +5,12 @@ namespace SpotifyAPI.Web.Http
{
public interface IResponse
{
object Body { get; }
object? Body { get; }
IReadOnlyDictionary<string, string> Headers { get; }
HttpStatusCode StatusCode { get; }
string ContentType { get; }
string? ContentType { get; }
}
}

View File

@ -10,7 +10,7 @@ namespace SpotifyAPI.Web.Http
{
public class NetHttpClient : IHTTPClient
{
private readonly HttpMessageHandler _httpMessageHandler;
private readonly HttpMessageHandler? _httpMessageHandler;
private readonly HttpClient _httpClient;
public NetHttpClient()

View File

@ -31,10 +31,13 @@ namespace SpotifyAPI.Web.Http
{
Ensure.ArgumentNotNull(response, nameof(response));
if (response.ContentType?.Equals("application/json", StringComparison.Ordinal) is true || response.ContentType == null)
if (
(
response.ContentType?.Equals("application/json", StringComparison.Ordinal) is true || response.ContentType == null
))
{
var body = JsonConvert.DeserializeObject<T>(response.Body as string, _serializerSettings);
return new APIResponse<T>(response, body);
var body = JsonConvert.DeserializeObject<T>(response.Body as string ?? "", _serializerSettings);
return new APIResponse<T>(response, body!);
}
return new APIResponse<T>(response);
}

View File

@ -12,8 +12,8 @@ namespace SpotifyAPI.Web
public string Host { get; }
public int Port { get; }
public string User { get; set; }
public string Password { get; set; }
public string? User { get; set; }
public string? Password { get; set; }
public bool BypassProxyOnLocal { get; set; }
public bool SkipSSLCheck { get; set; }
}

View File

@ -6,22 +6,36 @@ namespace SpotifyAPI.Web.Http
{
public class Request : IRequest
{
public Request()
public Request(Uri baseAddress, Uri endpoint, HttpMethod method)
{
Headers = new Dictionary<string, string>();
Parameters = new Dictionary<string, string>();
BaseAddress = baseAddress;
Endpoint = endpoint;
Method = method;
}
public Request(IDictionary<string, string> headers)
public Request(Uri baseAddress, Uri endpoint, HttpMethod method, IDictionary<string, string> headers)
{
Headers = headers;
Parameters = new Dictionary<string, string>();
BaseAddress = baseAddress;
Endpoint = endpoint;
Method = method;
}
public Request(IDictionary<string, string> headers, IDictionary<string, string> parameters)
public Request(
Uri baseAddress,
Uri endpoint,
HttpMethod method,
IDictionary<string, string> headers,
IDictionary<string, string> parameters)
{
Headers = headers;
Parameters = parameters;
BaseAddress = baseAddress;
Endpoint = endpoint;
Method = method;
}
public Uri BaseAddress { get; set; }
@ -34,6 +48,6 @@ namespace SpotifyAPI.Web.Http
public HttpMethod Method { get; set; }
public object Body { get; set; }
public object? Body { get; set; }
}
}

View File

@ -14,12 +14,12 @@ namespace SpotifyAPI.Web.Http
Headers = new ReadOnlyDictionary<string, string>(headers);
}
public object Body { get; set; }
public object? Body { get; set; }
public IReadOnlyDictionary<string, string> Headers { get; set; }
public HttpStatusCode StatusCode { get; set; }
public string ContentType { get; set; }
public string? ContentType { get; set; }
}
}

View File

@ -12,7 +12,7 @@ namespace SpotifyAPI.Web.Http
{
Ensure.ArgumentNotNull(request, nameof(request));
string parameters = null;
string? parameters = null;
if (request.Parameters != null)
{
parameters = string.Join(",", request.Parameters?.Select(kv => kv.Key + "=" + kv.Value).ToArray());
@ -26,9 +26,9 @@ namespace SpotifyAPI.Web.Http
{
Ensure.ArgumentNotNull(response, nameof(response));
#if NETSTANDARD2_0
string body = response.Body?.ToString().Replace("\n", "");
string? body = response.Body?.ToString().Replace("\n", "");
#else
string body = response.Body?.ToString().Replace("\n", "", StringComparison.InvariantCulture);
string? body = response.Body?.ToString().Replace("\n", "", StringComparison.InvariantCulture);
#endif
body = body?.Substring(0, Math.Min(50, body?.Length ?? 0));

View File

@ -8,8 +8,8 @@ namespace SpotifyAPI.Web
{
public override bool CanConvert(Type objectType) => true;
public override object ReadJson(JsonReader reader, Type objectType,
object existingValue, JsonSerializer serializer)
public override object? ReadJson(JsonReader reader, Type objectType,
object? existingValue, JsonSerializer serializer)
{
Ensure.ArgumentNotNull(serializer, nameof(serializer));
@ -19,7 +19,7 @@ namespace SpotifyAPI.Web
return null;
}
var type = token["type"].Value<string>();
var type = token["type"]?.Value<string>();
if (type == "track")
{
var obj = new FullTrack();
@ -38,10 +38,10 @@ namespace SpotifyAPI.Web
}
}
public override void WriteJson(JsonWriter writer, object value,
JsonSerializer serializer)
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
{
throw new NotSupportedException();
}
}
}

View File

@ -3,6 +3,6 @@ namespace SpotifyAPI.Web
public class AlbumRequest : RequestParams
{
[QueryParam("market")]
public string Market { get; set; }
public string? Market { get; set; }
}
}

View File

@ -3,7 +3,7 @@ namespace SpotifyAPI.Web
public class AlbumTracksRequest : RequestParams
{
[QueryParam("market")]
public string Market { get; set; }
public string? Market { get; set; }
[QueryParam("limit")]
public int? Limit { get; set; }
@ -12,3 +12,4 @@ namespace SpotifyAPI.Web
public int? Offset { get; set; }
}
}

View File

@ -15,6 +15,7 @@ namespace SpotifyAPI.Web
public IList<string> Ids { get; }
[QueryParam("market")]
public string Market { get; set; }
public string? Market { get; set; }
}
}

View File

@ -8,7 +8,7 @@ namespace SpotifyAPI.Web
public IncludeGroups? IncludeGroupsParam { get; set; }
[QueryParam("market")]
public string Market { get; set; }
public string? Market { get; set; }
[QueryParam("limit")]
public int? Limit { get; set; }
@ -34,3 +34,4 @@ namespace SpotifyAPI.Web
}
}
}

View File

@ -15,3 +15,4 @@ namespace SpotifyAPI.Web
public IList<string> Ids { get; }
}
}

View File

@ -13,3 +13,4 @@ namespace SpotifyAPI.Web
public string Market { get; }
}
}

View File

@ -21,3 +21,4 @@ namespace SpotifyAPI.Web
public string ClientSecret { get; }
}
}

View File

@ -25,3 +25,4 @@ namespace SpotifyAPI.Web
public Uri RedirectUri { get; }
}
}

View File

@ -3,10 +3,10 @@ namespace SpotifyAPI.Web
public class CategoriesRequest : RequestParams
{
[QueryParam("country")]
public string Country { get; set; }
public string? Country { get; set; }
[QueryParam("locale")]
public string Locale { get; set; }
public string? Locale { get; set; }
[QueryParam("limit")]
public int? Limit { get; set; }
@ -15,3 +15,4 @@ namespace SpotifyAPI.Web
public int? Offset { get; set; }
}
}

View File

@ -3,7 +3,7 @@ namespace SpotifyAPI.Web
public class CategoriesPlaylistsRequest : RequestParams
{
[QueryParam("country")]
public string Country { get; set; }
public string? Country { get; set; }
[QueryParam("limit")]
public int? Limit { get; set; }
@ -12,3 +12,4 @@ namespace SpotifyAPI.Web
public int? Offset { get; set; }
}
}

View File

@ -3,9 +3,10 @@ namespace SpotifyAPI.Web
public class CategoryRequest : RequestParams
{
[QueryParam("country")]
public string Country { get; set; }
public string? Country { get; set; }
[QueryParam("locale")]
public string Locale { get; set; }
public string? Locale { get; set; }
}
}

View File

@ -17,3 +17,4 @@ namespace SpotifyAPI.Web
public string ClientSecret { get; }
}
}

View File

@ -3,6 +3,7 @@ namespace SpotifyAPI.Web
public class EpisodeRequest : RequestParams
{
[QueryParam("market")]
public string Market { get; set; }
public string? Market { get; set; }
}
}

View File

@ -12,9 +12,10 @@ namespace SpotifyAPI.Web
}
[QueryParam("ids")]
public IList<string> Ids { get; set; }
public IList<string> Ids { get; }
[QueryParam("market")]
public string Market { get; set; }
public string? Market { get; set; }
}
}

View File

@ -5,19 +5,24 @@ namespace SpotifyAPI.Web
public class FeaturedPlaylistsRequest : RequestParams
{
[QueryParam("country")]
public string Country { get; set; }
public string? Country { get; set; }
[QueryParam("locale")]
public string Locale { get; set; }
public string? Locale { get; set; }
[QueryParam("limit")]
public int? Limit { get; set; }
[QueryParam("offset")]
public int? Offset { get; set; }
public DateTime? Timestamp { get; set; }
[QueryParam("timestamp")]
protected string TimestampFormatted
protected string? TimestampFormatted
{
get => Timestamp?.ToString("o", CultureInfo.InvariantCulture);
}
}
}

View File

@ -28,3 +28,4 @@ namespace SpotifyAPI.Web
}
}
}

View File

@ -15,3 +15,4 @@ namespace SpotifyAPI.Web
public IList<string> Ids { get; }
}
}

View File

@ -14,7 +14,7 @@ namespace SpotifyAPI.Web
public int? Limit { get; set; }
[QueryParam("after")]
public string After { get; set; }
public string? After { get; set; }
public enum Type
{
@ -23,3 +23,4 @@ namespace SpotifyAPI.Web
}
}
}

View File

@ -6,3 +6,4 @@ namespace SpotifyAPI.Web
public bool? Public { get; set; }
}
}

View File

@ -28,3 +28,4 @@ namespace SpotifyAPI.Web
}
}
}

View File

@ -9,6 +9,7 @@ namespace SpotifyAPI.Web
public int? Offset { get; set; }
[QueryParam("market")]
public string Market { get; set; }
public string? Market { get; set; }
}
}

View File

@ -16,3 +16,4 @@ namespace SpotifyAPI.Web
public IList<string> Ids { get; }
}
}

View File

@ -15,3 +15,4 @@ namespace SpotifyAPI.Web
public IList<string> Ids { get; }
}
}

View File

@ -15,3 +15,4 @@ namespace SpotifyAPI.Web
public IList<string> Ids { get; }
}
}

View File

@ -15,3 +15,4 @@ namespace SpotifyAPI.Web
public IList<string> Ids { get; }
}
}

View File

@ -15,3 +15,4 @@ namespace SpotifyAPI.Web
public IList<string> Ids { get; }
}
}

View File

@ -15,3 +15,4 @@ namespace SpotifyAPI.Web
public IList<string> Ids { get; }
}
}

View File

@ -15,3 +15,4 @@ namespace SpotifyAPI.Web
public IList<string> Ids { get; }
}
}

View File

@ -15,3 +15,4 @@ namespace SpotifyAPI.Web
public IList<string> Ids { get; }
}
}

View File

@ -15,3 +15,4 @@ namespace SpotifyAPI.Web
public IList<string> Ids { get; }
}
}

View File

@ -9,6 +9,7 @@ namespace SpotifyAPI.Web
public int? Offset { get; set; }
[QueryParam("market")]
public string Market { get; set; }
public string? Market { get; set; }
}
}

View File

@ -9,6 +9,7 @@ namespace SpotifyAPI.Web
public int? Offset { get; set; }
[QueryParam("market")]
public string Market { get; set; }
public string? Market { get; set; }
}
}

View File

@ -21,8 +21,8 @@ namespace SpotifyAPI.Web
public Uri RedirectUri { get; }
public ResponseType ResponseTypeParam { get; }
public string ClientId { get; }
public string State { get; set; }
public ICollection<string> Scope { get; set; }
public string? State { get; set; }
public ICollection<string>? Scope { get; set; }
public bool? ShowDialog { get; set; }
public Uri ToUri()
@ -54,3 +54,4 @@ namespace SpotifyAPI.Web
}
}
}

View File

@ -3,7 +3,7 @@ namespace SpotifyAPI.Web
public class NewReleasesRequest : RequestParams
{
[QueryParam("country")]
public string Country { get; set; }
public string? Country { get; set; }
[QueryParam("limit")]
public int? Limit { get; set; }
@ -12,3 +12,4 @@ namespace SpotifyAPI.Web
public int? Offset { get; set; }
}
}

View File

@ -24,3 +24,4 @@ namespace SpotifyAPI.Web
}
}
}

View File

@ -13,6 +13,7 @@ namespace SpotifyAPI.Web
public string Uri { get; }
[QueryParam("device_id")]
public string DeviceId { get; set; }
public string? DeviceId { get; set; }
}
}

View File

@ -12,7 +12,7 @@ namespace SpotifyAPI.Web
}
[QueryParam("market")]
public string Market { get; set; }
public string? Market { get; set; }
/// <summary>
/// This is set to `"track", "episode"` by default.
@ -32,3 +32,4 @@ namespace SpotifyAPI.Web
}
}
}

View File

@ -34,3 +34,4 @@ namespace SpotifyAPI.Web
}
}
}

View File

@ -3,6 +3,7 @@ namespace SpotifyAPI.Web
public class PlayerPausePlaybackRequest : RequestParams
{
[QueryParam("device_id")]
public string DeviceId { get; set; }
public string? DeviceId { get; set; }
}
}

View File

@ -12,3 +12,4 @@ namespace SpotifyAPI.Web
public long? Before { get; set; }
}
}

View File

@ -6,17 +6,17 @@ namespace SpotifyAPI.Web
public class PlayerResumePlaybackRequest : RequestParams
{
[QueryParam("device_id")]
public string DeviceId { get; set; }
public string? DeviceId { get; set; }
[BodyParam("context_uri")]
public string ContextUri { get; set; }
public string? ContextUri { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227")]
[BodyParam("uris")]
public IList<string> Uris { get; set; }
public IList<string>? Uris { get; set; }
[BodyParam("offset")]
public Offset OffsetParam { get; set; }
public Offset? OffsetParam { get; set; }
[BodyParam("position_ms")]
public int? PositionMs { get; set; }
@ -24,10 +24,11 @@ namespace SpotifyAPI.Web
public class Offset
{
[JsonProperty("uri", NullValueHandling = NullValueHandling.Ignore)]
public string Uri { get; set; }
public string? Uri { get; set; }
[JsonProperty("position", NullValueHandling = NullValueHandling.Ignore)]
public int? Position { get; set; }
}
}
}

View File

@ -11,6 +11,7 @@ namespace SpotifyAPI.Web
public long PositonMs { get; }
[QueryParam("device_id")]
public string DeviceId { get; set; }
public string? DeviceId { get; set; }
}
}

View File

@ -10,7 +10,7 @@ namespace SpotifyAPI.Web
}
[QueryParam("device_id")]
public string DeviceId { get; set; }
public string? DeviceId { get; set; }
[QueryParam("state")]
public State StateParam { get; }
@ -28,3 +28,4 @@ namespace SpotifyAPI.Web
}
}
}

View File

@ -11,6 +11,7 @@ namespace SpotifyAPI.Web
public bool State { get; }
[QueryParam("device_id")]
public string DeviceId { get; set; }
public string? DeviceId { get; set; }
}
}

View File

@ -3,6 +3,7 @@ namespace SpotifyAPI.Web
public class PlayerSkipNextRequest : RequestParams
{
[QueryParam("device_id")]
public string DeviceId { get; set; }
public string? DeviceId { get; set; }
}
}

View File

@ -3,6 +3,7 @@ namespace SpotifyAPI.Web
public class PlayerSkipPreviousRequest : RequestParams
{
[QueryParam("device_id")]
public string DeviceId { get; set; }
public string? DeviceId { get; set; }
}
}

View File

@ -18,3 +18,4 @@ namespace SpotifyAPI.Web
public bool? Play { get; set; }
}
}

View File

@ -11,6 +11,7 @@ namespace SpotifyAPI.Web
public int VolumePercent { get; }
[QueryParam("device_id")]
public string DeviceId { get; set; }
public string? DeviceId { get; set; }
}
}

View File

@ -18,3 +18,4 @@ namespace SpotifyAPI.Web
public int? Position { get; set; }
}
}

View File

@ -3,7 +3,7 @@ namespace SpotifyAPI.Web
public class PlaylistChangeDetailsRequest : RequestParams
{
[BodyParam("name")]
public string Name { get; set; }
public string? Name { get; set; }
[BodyParam("public")]
public bool? Public { get; set; }
@ -12,6 +12,7 @@ namespace SpotifyAPI.Web
public bool? Collaborative { get; set; }
[BodyParam("description")]
public string Description { get; set; }
public string? Description { get; set; }
}
}

View File

@ -19,6 +19,7 @@ namespace SpotifyAPI.Web
public bool? Collaborative { get; set; }
[BodyParam("description")]
public string Description { get; set; }
public string? Description { get; set; }
}
}

View File

@ -9,3 +9,4 @@ namespace SpotifyAPI.Web
public int? Offset { get; set; }
}
}

View File

@ -23,7 +23,7 @@ namespace SpotifyAPI.Web
public int? Offset { get; set; }
[QueryParam("market")]
public string Market { get; set; }
public string? Market { get; set; }
/// <summary>
/// This is set to `"track", "episode"` by default.
@ -43,3 +43,4 @@ namespace SpotifyAPI.Web
}
}
}

View File

@ -30,3 +30,4 @@ namespace SpotifyAPI.Web
}
}
}

View File

@ -9,3 +9,4 @@ namespace SpotifyAPI.Web
public int? Offset { get; set; }
}
}

View File

@ -16,17 +16,18 @@ namespace SpotifyAPI.Web
public IList<Item> Tracks { get; }
[BodyParam("snapshot_id")]
public string SnapshotId { get; set; }
public string? SnapshotId { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1034")]
public class Item
{
[JsonProperty("uri", NullValueHandling = NullValueHandling.Ignore)]
public string Uri { get; set; }
public string? Uri { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227")]
[JsonProperty("positions", NullValueHandling = NullValueHandling.Ignore)]
public List<int> Positions { get; set; }
public List<int>? Positions { get; set; }
}
}
}

View File

@ -18,6 +18,7 @@ namespace SpotifyAPI.Web
public int? RangeLength { get; set; }
[BodyParam("snapshot_id")]
public string SnapshotId { get; set; }
public string? SnapshotId { get; set; }
}
}

View File

@ -15,3 +15,4 @@ namespace SpotifyAPI.Web
public IList<string> Uris { get; }
}
}

View File

@ -28,7 +28,7 @@ namespace SpotifyAPI.Web
public int? Limit { get; set; }
[QueryParam("market")]
public string Market { get; set; }
public string? Market { get; set; }
public Dictionary<string, string> Min { get; }
public Dictionary<string, string> Max { get; }
@ -61,3 +61,4 @@ namespace SpotifyAPI.Web
}
}
}

View File

@ -20,9 +20,8 @@ namespace SpotifyAPI.Web
var obj = new JObject();
foreach (var prop in bodyProps)
{
var attribute = prop.GetCustomAttribute(typeof(BodyParamAttribute)) as BodyParamAttribute;
object value = prop.GetValue(this);
if (value != null)
if (value != null && prop.GetCustomAttribute(typeof(BodyParamAttribute)) is BodyParamAttribute attribute)
{
obj[attribute.Key ?? prop.Name] = JToken.FromObject(value);
}
@ -41,9 +40,8 @@ namespace SpotifyAPI.Web
var queryParams = new Dictionary<string, string>();
foreach (var prop in queryProps)
{
var attribute = prop.GetCustomAttribute(typeof(QueryParamAttribute)) as QueryParamAttribute;
object value = prop.GetValue(this);
if (value != null)
if (value != null && prop.GetCustomAttribute(typeof(QueryParamAttribute)) is QueryParamAttribute attribute)
{
if (value is IList<string> list && list.Count > 0)
{
@ -91,7 +89,6 @@ namespace SpotifyAPI.Web
{
public string Key { get; }
public QueryParamAttribute() { }
public QueryParamAttribute(string key)
{
Key = key;
@ -103,10 +100,10 @@ namespace SpotifyAPI.Web
{
public string Key { get; }
public BodyParamAttribute() { }
public BodyParamAttribute(string key)
{
Key = key;
}
}
}

View File

@ -20,7 +20,7 @@ namespace SpotifyAPI.Web
public string Query { get; set; }
[QueryParam("market")]
public string Market { get; set; }
public string? Market { get; set; }
[QueryParam("limit")]
public int? Limit { get; set; }
@ -57,3 +57,4 @@ namespace SpotifyAPI.Web
}
}
}

View File

@ -9,6 +9,7 @@ namespace SpotifyAPI.Web
public int? Offset { get; set; }
[QueryParam("market")]
public string Market { get; set; }
public string? Market { get; set; }
}
}

View File

@ -3,6 +3,7 @@ namespace SpotifyAPI.Web
public class ShowRequest : RequestParams
{
[QueryParam("market")]
public string Market { get; set; }
public string? Market { get; set; }
}
}

View File

@ -15,6 +15,7 @@ namespace SpotifyAPI.Web
public IList<string> Ids { get; }
[QueryParam("market")]
public string Market { get; set; }
public string? Market { get; set; }
}
}

View File

@ -3,6 +3,7 @@ namespace SpotifyAPI.Web
public class TrackRequest : RequestParams
{
[QueryParam("market")]
public string Market { get; set; }
public string? Market { get; set; }
}
}

View File

@ -12,6 +12,7 @@ namespace SpotifyAPI.Web
}
[QueryParam("ids")]
public IList<string> Ids { get; private set; }
public IList<string> Ids { get; }
}
}

View File

@ -15,6 +15,7 @@ namespace SpotifyAPI.Web
public IList<string> Ids { get; }
[QueryParam("market")]
public string Market { get; set; }
public string? Market { get; set; }
}
}

View File

@ -27,3 +27,4 @@ namespace SpotifyAPI.Web
}
}
}

View File

@ -4,6 +4,7 @@ namespace SpotifyAPI.Web
{
public class Actions
{
public Dictionary<string, bool> Disallows { get; set; }
public Dictionary<string, bool> Disallows { get; set; } = default!;
}
}

View File

@ -4,6 +4,7 @@ namespace SpotifyAPI.Web
{
public class AlbumsResponse
{
public List<FullAlbum> Albums { get; set; }
public List<FullAlbum> Albums { get; set; } = default!;
}
}

View File

@ -4,6 +4,7 @@ namespace SpotifyAPI.Web
{
public class ArtistsRelatedArtistsResponse
{
public List<FullArtist> Artists { get; set; }
public List<FullArtist> Artists { get; set; } = default!;
}
}

View File

@ -4,6 +4,7 @@ namespace SpotifyAPI.Web
{
public class ArtistsResponse
{
public List<FullArtist> Artists { get; set; }
public List<FullArtist> Artists { get; set; } = default!;
}
}

View File

@ -4,6 +4,7 @@ namespace SpotifyAPI.Web
{
public class ArtistsTopTracksResponse
{
public List<FullTrack> Tracks { get; set; }
public List<FullTrack> Tracks { get; set; } = default!;
}
}

View File

@ -1,14 +1,13 @@
using System;
using System.Collections.Generic;
namespace SpotifyAPI.Web
{
public class AuthorizationCodeRefreshResponse
{
public string AccessToken { get; set; }
public string TokenType { get; set; }
public string AccessToken { get; set; } = default!;
public string TokenType { get; set; } = default!;
public int ExpiresIn { get; set; }
public string Scope { get; set; }
public string Scope { get; set; } = default!;
/// <summary>
/// Auto-Initalized to UTC Now
@ -19,3 +18,4 @@ namespace SpotifyAPI.Web
public bool IsExpired { get => CreatedAt.AddSeconds(ExpiresIn) <= DateTime.UtcNow; }
}
}

View File

@ -5,11 +5,11 @@ namespace SpotifyAPI.Web
{
public class AuthorizationCodeTokenResponse
{
public string AccessToken { get; set; }
public string TokenType { get; set; }
public string AccessToken { get; set; } = default!;
public string TokenType { get; set; } = default!;
public int ExpiresIn { get; set; }
public string Scope { get; set; }
public string RefreshToken { get; set; }
public string Scope { get; set; } = default!;
public string RefreshToken { get; set; } = default!;
/// <summary>
/// Auto-Initalized to UTC Now
@ -20,3 +20,4 @@ namespace SpotifyAPI.Web
public bool IsExpired { get => CreatedAt.AddSeconds(ExpiresIn) <= DateTime.UtcNow; }
}
}

Some files were not shown because too many files have changed in this diff Show More