Spotify.NET/SpotifyAPI.Web/Models/Request/RequestParams.cs

182 lines
5.3 KiB
C#
Raw Normal View History

2020-05-01 19:05:28 +01:00
using System;
2022-11-27 12:29:35 +00:00
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
2020-05-02 21:48:21 +01:00
using Newtonsoft.Json.Linq;
2020-05-01 19:05:28 +01:00
namespace SpotifyAPI.Web
{
public abstract class RequestParams
{
private static readonly ConcurrentDictionary<Type, List<(PropertyInfo, BodyParamAttribute)>> _bodyParamsCache =
new();
2020-05-02 21:48:21 +01:00
public JObject BuildBodyParams()
{
2020-05-07 12:48:31 +01:00
// Make sure everything is okay before building body params
2020-05-02 21:48:21 +01:00
CustomEnsure();
var body = new JObject();
var type = GetType();
if (!_bodyParamsCache.IsEmpty && _bodyParamsCache.TryGetValue(type, out var bodyParamsCached))
{
foreach (var (info, attribute) in bodyParamsCached)
{
AddBodyParam(body, info, attribute);
}
}
else
2020-05-02 21:48:21 +01:00
{
var bodyProps = GetType()
.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public)
.Where(prop => prop.GetCustomAttributes(typeof(BodyParamAttribute), true).Length > 0);
var cachedParams = new List<(PropertyInfo, BodyParamAttribute)>();
foreach (var prop in bodyProps)
2020-05-02 21:48:21 +01:00
{
2020-11-13 13:43:00 +00:00
var attribute = prop.GetCustomAttribute<BodyParamAttribute>();
if (attribute != null)
{
cachedParams.Add((prop, attribute));
2020-11-13 13:43:00 +00:00
AddBodyParam(body, prop, attribute);
}
2020-05-02 21:48:21 +01:00
}
_bodyParamsCache[type] = cachedParams;
2020-05-02 21:48:21 +01:00
}
return body;
}
private void AddBodyParam(JObject body, PropertyInfo prop, BodyParamAttribute attribute)
{
2020-11-13 13:43:00 +00:00
object? value = prop.GetValue(this);
if (value != null)
{
body[attribute.Key ?? prop.Name] = JToken.FromObject(value);
}
2020-05-02 21:48:21 +01:00
}
private static readonly ConcurrentDictionary<Type, List<(PropertyInfo, QueryParamAttribute)>> _queryParamsCache =
new();
2020-05-01 19:05:28 +01:00
public Dictionary<string, string> BuildQueryParams()
{
// Make sure everything is okay before building query params
2020-05-02 21:48:21 +01:00
CustomEnsure();
var queryParams = new Dictionary<string, string>();
var type = GetType();
if (!_queryParamsCache.IsEmpty && _queryParamsCache.TryGetValue(type, out var queryParamsCached))
{
foreach (var (info, attribute) in queryParamsCached)
{
AddQueryParam(queryParams, info, attribute);
}
}
else
{
var queryProps = GetType().GetProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public)
2020-05-01 19:05:28 +01:00
.Where(prop => prop.GetCustomAttributes(typeof(QueryParamAttribute), true).Length > 0);
var cachedParams = new List<(PropertyInfo, QueryParamAttribute)>();
foreach (var prop in queryProps)
{
2020-11-13 13:43:00 +00:00
var attribute = prop.GetCustomAttribute<QueryParamAttribute>();
if (attribute != null)
{
cachedParams.Add((prop, attribute));
2020-11-13 13:43:00 +00:00
AddQueryParam(queryParams, prop, attribute);
}
}
_queryParamsCache[type] = cachedParams;
}
AddCustomQueryParams(queryParams);
return queryParams;
}
private void AddQueryParam(Dictionary<string, string> queryParams, PropertyInfo prop, QueryParamAttribute attribute)
{
2020-11-13 13:43:00 +00:00
object? value = prop.GetValue(this);
if (value != null)
2020-05-01 19:05:28 +01:00
{
if (value is IList<string> list)
2020-05-01 19:05:28 +01:00
{
if (list.Count > 0)
{
var str = string.Join(",", list);
queryParams.Add(attribute.Key ?? prop.Name, str);
}
}
else if (value is bool valueAsBool)
{
queryParams.Add(attribute.Key ?? prop.Name, valueAsBool ? "true" : "false");
}
else if (value is Enum valueAsEnum)
{
var enumType = valueAsEnum.GetType();
var valueList = new List<string>();
if (enumType.IsDefined(typeof(FlagsAttribute), false))
{
foreach (Enum enumVal in Enum.GetValues(valueAsEnum.GetType()))
{
if (valueAsEnum.HasFlag(enumVal))
{
if (StringAttribute.GetValue(enumType, enumVal, out var stringVal))
{
// .netstandard2.0 requires !
valueList.Add(stringVal!);
}
}
}
2020-05-02 21:48:21 +01:00
}
else
{
if (StringAttribute.GetValue(enumType, valueAsEnum, out var stringVal))
{
// .netstandard2.0 requires !
valueList.Add(stringVal!);
}
}
queryParams.Add(attribute.Key ?? prop.Name, string.Join(",", valueList));
}
else
{
queryParams.Add(attribute.Key ?? prop.Name, value.ToString() ?? throw new APIException("ToString returned null for query parameter"));
2020-05-01 19:05:28 +01:00
}
}
}
2020-05-02 21:48:21 +01:00
protected virtual void CustomEnsure() { }
protected virtual void AddCustomQueryParams(Dictionary<string, string> queryParams) { }
2020-05-01 19:05:28 +01:00
}
[AttributeUsage(AttributeTargets.Property)]
public sealed class QueryParamAttribute : Attribute
2020-05-01 19:05:28 +01:00
{
2020-05-02 13:58:11 +01:00
public string Key { get; }
2020-05-01 19:05:28 +01:00
public QueryParamAttribute(string key)
{
Key = key;
}
}
[AttributeUsage(AttributeTargets.Property)]
public sealed class BodyParamAttribute : Attribute
2020-05-01 19:05:28 +01:00
{
2020-05-02 21:48:21 +01:00
public string Key { get; }
public BodyParamAttribute(string key)
{
Key = key;
}
2020-05-01 19:05:28 +01:00
}
}
2020-05-25 17:00:38 +01:00