Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace AndreasReitberger.API.REST.Extensions
{
[Obsolete("Use from the core library once available")]
public static class CookieCollectionExtension
{
extension(CookieCollection collection)
Expand Down
22 changes: 22 additions & 0 deletions src/RestApiClientSharp/Extensions/TypeExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System.Reflection;
using System.Runtime.CompilerServices;

namespace AndreasReitberger.API.REST.Extensions
{
[Obsolete("Use from the core library once available")]
public static class TypeExtensions
{
public static bool IsAnonymousType(this Type type)
{
if (type == null)
return false;

return Attribute.IsDefined(type, typeof(CompilerGeneratedAttribute), false)
&& type.IsGenericType
&& type.Name.Contains("AnonymousType")
&& (type.Name.StartsWith("<>") || type.Name.StartsWith("VB$"))
&& (type.Attributes & TypeAttributes.NotPublic) == TypeAttributes.NotPublic;
}

}
}
12 changes: 11 additions & 1 deletion src/RestApiClientSharp/Interfaces/IRestApiClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ public interface IRestApiClient : INotifyPropertyChanged, IDisposable, ICloneabl
public Func<Task>? OnRefresh { get; set; }
#endregion

#region JsonSerializer
public JsonSerializerContext JsonSerializerContext { get; set; }
#endregion

#endregion

#region EventHandlers
Expand Down Expand Up @@ -116,8 +120,14 @@ public interface IRestApiClient : INotifyPropertyChanged, IDisposable, ICloneabl
#endregion

#region Rest
[Obsolete("This method is deprecated. Please use SendRestApiRequestAsync instead.")]
public Task<IRestApiRequestRespone?> SendRestApiRequestLegacyAsync(string? requestTargetUri, Method method, string? command,
Dictionary<string, IAuthenticationHeader> authHeaders, object? jsonObject = null, RestBodyTarget target = RestBodyTarget.Json, CancellationTokenSource? cts = default, Dictionary<string, string>? urlSegments = null, JsonSerializerContext? serializerContext = null
//string? contentType = null, string? accept = null
);

public Task<IRestApiRequestRespone?> SendRestApiRequestAsync(string? requestTargetUri, Method method, string? command,
Dictionary<string, IAuthenticationHeader> authHeaders, object? jsonObject = null, RestBodyTarget target = RestBodyTarget.Json, CancellationTokenSource? cts = default, List<Tuple<string, string>>? urlSegments = null
Dictionary<string, IAuthenticationHeader> authHeaders, object? jsonObject = null, RestBodyTarget target = RestBodyTarget.Json, CancellationTokenSource? cts = default, List<Tuple<string, string>>? urlSegments = null, JsonSerializerContext? serializerContext = null
//string? contentType = null, string? accept = null
);

Expand Down
5 changes: 5 additions & 0 deletions src/RestApiClientSharp/RestApiClient.JsonSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ public partial class RestApiClient : ObservableObject, IRestApiClient

[ObservableProperty]
[JsonIgnore, XmlIgnore]
public partial JsonSerializerContext JsonSerializerContext { get; set; } = RestSourceGenerationContext.Default;

[ObservableProperty]
[JsonIgnore, XmlIgnore]
[Obsolete("This property is deprecated. Use the `JsonSerializerContext` instead.")]
public partial JsonSerializerOptions JsonSerializerSettings { get; set; } = RestSourceGenerationContext.Default.Options;

#region SerializerSettings
Expand Down
25 changes: 18 additions & 7 deletions src/RestApiClientSharp/RestApiClient.Rest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using AndreasReitberger.API.REST.Extensions;

namespace AndreasReitberger.API.REST
{
Expand Down Expand Up @@ -111,6 +112,7 @@ protected virtual IRestApiRequestRespone ValidateResponse(RestResponse? response
#endregion

#region Rest Api
[Obsolete("This method is deprecated. Please use SendRestApiRequestAsync instead.")]
public virtual Task<IRestApiRequestRespone?> SendRestApiRequestLegacyAsync(
string? requestTargetUri,
Method method,
Expand All @@ -119,10 +121,11 @@ protected virtual IRestApiRequestRespone ValidateResponse(RestResponse? response
object? body = null,
RestBodyTarget target = RestBodyTarget.Json,
CancellationTokenSource? cts = default,
Dictionary<string, string>? urlSegments = null
Dictionary<string, string>? urlSegments = null,
JsonSerializerContext? serializerContext = null
)
=> SendRestApiRequestAsync(requestTargetUri, method, command, authHeaders, body, target, cts,
urlSegments is not null ? [.. urlSegments.Select(kvp => new Tuple<string, string>(kvp.Key, kvp.Value))] : null);
urlSegments is not null ? [.. urlSegments.Select(kvp => new Tuple<string, string>(kvp.Key, kvp.Value))] : null, serializerContext);

public virtual async Task<IRestApiRequestRespone?> SendRestApiRequestAsync(
string? requestTargetUri,
Expand All @@ -132,13 +135,16 @@ protected virtual IRestApiRequestRespone ValidateResponse(RestResponse? response
object? body = null,
RestBodyTarget target = RestBodyTarget.Json,
CancellationTokenSource? cts = default,
List<Tuple<string, string>>? urlSegments = null
List<Tuple<string, string>>? urlSegments = null,
JsonSerializerContext? serializerContext = null
)
{
RestApiRequestRespone apiRsponeResult = new() { IsOnline = IsOnline };
try
{
cts ??= new(TimeSpan.FromSeconds(DefaultTimeout));
serializerContext ??= JsonSerializerContext ??= RestSourceGenerationContext.Default;

requestTargetUri ??= string.Empty;
command ??= string.Empty;
if (RestClient == null)
Expand Down Expand Up @@ -188,8 +194,14 @@ protected virtual IRestApiRequestRespone ValidateResponse(RestResponse? response
}
else
{
bodyContent = string.Empty;
//bodyContent = JsonConvert.SerializeObject(body, DefaultNewtonsoftJsonSerializerSettings);
bodyContent = JsonSerializer.Serialize(body!, body.GetType(), RestSourceGenerationContext.Default);
if (body.GetType().IsAnonymousType())
#pragma warning disable IL2026 // Disable warning for anonymous types, as they cannot be preserved with source generation and are only used for internal purposes.
bodyContent = JsonSerializer.Serialize(body!, body.GetType());
#pragma warning restore IL2026 // Restore warnings
else
bodyContent = JsonSerializer.Serialize(body!, body.GetType(), context: serializerContext);
request.AddJsonBody(bodyContent, RestContentType.Json);
}
break;
Expand Down Expand Up @@ -321,7 +333,6 @@ protected virtual IRestApiRequestRespone ValidateResponse(RestResponse? response
{
RestApiRequestRespone apiRsponeResult = new();
if (!IsOnline) return apiRsponeResult;

try
{
// If there is no file specified
Expand All @@ -344,10 +355,10 @@ protected virtual IRestApiRequestRespone ValidateResponse(RestResponse? response
{
switch (authHeader.Value.Target)
{
case Enums.AuthenticationHeaderTarget.UrlSegment:
case AuthenticationHeaderTarget.UrlSegment:
request.AddParameter(authHeader.Key, authHeader.Value.Token, ParameterType.QueryString);
break;
case Enums.AuthenticationHeaderTarget.Header:
case AuthenticationHeaderTarget.Header:
default:
// Examples:
// "X-Api-Key", $"{apiKey}"
Expand Down
67 changes: 47 additions & 20 deletions src/RestApiClientSharp/RestApiConnectionBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,57 @@ public class RestApiConnectionBuilder

#region Methods

/// <summary>
/// Builds the <c>RestApiClient</c> instance with the specified configuration. After calling this method, the builder should not be used anymore, as it does not create a new instance of the client but returns the same one.
/// </summary>
/// <returns><c>RestApiClient</c></returns>
public RestApiClient Build() => _client;


/// <summary>
/// Sets the web address for the connection. This is the base address to which the method paths will be appended when making requests.
/// For instance, if the web address is `https://api.example.com` and a method has the path `get-data`, the full request URI will be `https://api.example.com/get-data`
/// (or `https://api.example.com/version/get-data` if an API version is set).
/// If not set, the client will throw an exception when trying to make a request, as it won't have a valid URI to send the request to.
/// </summary>
/// <param name="webAddress">The web address for the connection</param>
/// <returns>The updated connection builder</returns>
public RestApiConnectionBuilder WithWebAddress(string webAddress)
{
_client.ApiTargetPath = webAddress;
return this;
}

/// <summary>
/// Sets the API version for the connection. This is used to build the full request URI, which is usually in the format `webAddress/version/method`. If not set, the version will be omitted from the request URI.
/// </summary>
/// <param name="version">The API version</param>
/// <returns><c>RestApiConnectionBuilder</c></returns>
public RestApiConnectionBuilder WithVersion(string version)
{
_client.ApiVersion = version;
return this;
}

/// <summary>
/// Sets the API key for the connection. The token name is the name of the header in which the token will be sent (for instance `apikey`).
/// The `AuthenticationHeader` contains the token and other information about how to send it.
/// </summary>
/// <param name="tokenName">The name of the API key</param>
/// <param name="authHeader">The authentication header for the API key</param>
/// <returns><c>RestApiConnectionBuilder</c></returns>
public RestApiConnectionBuilder WithApiKey(string tokenName, IAuthenticationHeader authHeader)
{
_client.AuthHeaders = new Dictionary<string, IAuthenticationHeader>() { { tokenName, authHeader } };
return this;
}

/// <summary>
/// Sets the web address and the api key for the connection. This is a shortcut for setting both values at once.
/// </summary>
/// <param name="webAddress">The rest API web address</param>
/// <param name="tokenName">The name for the API key</param>
/// <param name="authHeader">The authentication header for the API key</param>
/// <returns><c>RestApiConnectionBuilder</c></returns>
public RestApiConnectionBuilder WithWebAddressAndApiKey(string webAddress, string tokenName, IAuthenticationHeader authHeader)
{
_client.ApiTargetPath = webAddress;
Expand Down Expand Up @@ -95,21 +126,6 @@ public RestApiConnectionBuilder WithWebSocket(string webSocketAddress, string? t
_client.WebSocketTargetUri = webSocketAddress;
return this;
}
/*
public RestApiConnectionBuilder WithWebSocket(string webSocketAddress, Dictionary<string, IAuthenticationHeader>? authentication = null, string pingCommand = "", int pingInterval = 0, bool enablePing = true)
{
if (authentication is not null)
foreach (KeyValuePair<string, IAuthenticationHeader> item in authentication)
{
_client.AuthHeaders.Add(item.Key, item.Value);
}
_client.EnablePing = enablePing;
_client.PingCommand = pingCommand;
_client.PingInterval = pingInterval;
_client.WebSocketTargetUri = webSocketAddress;
return this;
}
*/

/// <summary>
/// Sets the WebSocket address for the connection
Expand All @@ -121,16 +137,27 @@ public RestApiConnectionBuilder WithWebSocket(string webSocketAddress, Dictionar
/// <returns><c>RestApiConnectionBuilder</c></returns>
public RestApiConnectionBuilder WithWebSocket(string webSocketAddress, string pingCommand, string? tokenName = null, IAuthenticationHeader? authentication = null, int pingInterval = 0, bool enablePing = true)
=> WithWebSocket(webSocketAddress, tokenName, authentication, pingCommand, pingInterval, enablePing);
/*
public RestApiConnectionBuilder WithWebSocket(string webSocketAddress, object pingCommand, Dictionary<string, IAuthenticationHeader>? authentication = null, int pingInterval = 0, bool enablePing = true)
=> WithWebSocket(webSocketAddress, authentication, JsonConvert.SerializeObject(pingCommand), pingInterval, enablePing);
*/

/// <summary>
/// Sets default headers for the connection. These headers will be sent with every request.
/// </summary>
/// <param name="headers">The headers to set</param>
/// <returns><c>RestApiConnectionBuilder</c></returns>
public RestApiConnectionBuilder WithDefaultHeaders(params RestHeader[] headers)
{
_client.DefaultHeaders = [.. headers];
return this;
}
/// <summary>
/// Sets the <c>JsonSerializerContext</c> for the rest api methods. If not set, the default options will be used.
/// </summary>
/// <param name="serializerContext">The json serializer context</param>
/// <returns><c>RestApiConnectionBuilder</c></returns>
public RestApiConnectionBuilder WithJsonSerializerContext(JsonSerializerContext serializerContext)
{
_client.JsonSerializerContext = serializerContext;
return this;
}
#endregion
}
}
Expand Down
Loading