using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Reflection; using System.Threading; namespace RestEase.Implementation { /// /// Class containing information to construct a request from. /// An instance of this is created per request by the generated interface implementation /// public class RequestInfo : IRequestInfo { /// /// Gets the HttpMethod which should be used to make the request /// public HttpMethod Method { get; } /// /// Gets or sets the path which should be prepended to if any /// public string? BasePath { get; set; } /// /// Gets the relative path to the resource to request /// public string Path { get; } /// /// Gets or sets the CancellationToken used to cancel the request /// public CancellationToken CancellationToken { get; set; } = CancellationToken.None; /// /// Gets or sets a value indicating whether to suppress the exception on invalid status codes /// public bool AllowAnyStatusCode { get; set; } private List? _queryParams; /// /// Gets the query parameters to append to the request URI /// public IEnumerable QueryParams => this._queryParams ?? Enumerable.Empty(); private List? _rawQueryParameterInfos; /// /// Gets the raw query parameters /// public IEnumerable RawQueryParameters => this._rawQueryParameterInfos ?? Enumerable.Empty(); private List? _pathParams; /// /// Gets the parameters which should be substituted into placeholders in the Path /// public IEnumerable PathParams => this._pathParams ?? Enumerable.Empty(); private List? _pathProperties; /// /// Gets the values from properties which should be substituted into placeholders in the Path /// public IEnumerable PathProperties => this._pathProperties ?? Enumerable.Empty(); private List? _queryProperties; /// /// Gets the values from properties which should be added to all query strings /// public IEnumerable QueryProperties => this._queryProperties ?? Enumerable.Empty(); private List? _httpRequestMessageProperties; /// /// Gets the values from properties which should be added as request properties /// public IEnumerable HttpRequestMessageProperties => this._httpRequestMessageProperties ?? Enumerable.Empty(); /// /// Gets or sets the headers which were applied to the interface /// public IEnumerable>? ClassHeaders { get; set; } private List? _propertyHeaders; /// /// Gets the headers which were applied using properties /// public IEnumerable PropertyHeaders => this._propertyHeaders ?? Enumerable.Empty(); private List>? _methodHeaders; /// /// Gets the headers which were applied to the method being called /// public IEnumerable> MethodHeaders => this._methodHeaders ?? Enumerable.Empty>(); private List? _headerParams; /// /// Gets the headers which were passed to the method as parameters /// public IEnumerable HeaderParams => this._headerParams ?? Enumerable.Empty(); /// /// Gets information the [Body] method parameter, if it exists /// public BodyParameterInfo? BodyParameterInfo { get; private set; } /// /// Gets the MethodInfo of the interface method which was invoked /// public MethodInfo MethodInfo { get; } /// /// Initialises a new instance of the class /// /// HttpMethod to use when making the request /// Relative path to request public RequestInfo(HttpMethod method, string path) : this(method, path, null!) { } /// /// Initialises a new instance of the class /// /// HttpMethod to use when making the request /// Relative path to request /// MethodInfo for the method which was invoked public RequestInfo(HttpMethod method, string path, MethodInfo methodInfo) { this.Method = method; this.Path = path; this.MethodInfo = methodInfo; } /// /// Add a query parameter /// /// value may be an IEnumerable, in which case each value is added separately /// Type of the value to add /// Method to use to serialize the value /// Name of the name/value pair /// Value of the name/value pair /// Format string to use public void AddQueryParameter(QuerySerializationMethod serializationMethod, string name, T value, string? format = null) { if (this._queryParams == null) this._queryParams = new List(); this._queryParams.Add(new QueryParameterInfo(serializationMethod, name, value, format)); } /// /// Add a collection of query parameter values under the same name /// /// Type of the value to add /// Method to use to serialize the value /// Name of the name/values pair /// Values of the name/values pairs /// Format string to use public void AddQueryCollectionParameter(QuerySerializationMethod serializationMethod, string name, IEnumerable values, string? format = null) { if (this._queryParams == null) this._queryParams = new List(); this._queryParams.Add(new QueryCollectionParameterInfo(serializationMethod, name, values, format)); } /// /// Add a query map to the query parameters list, where the type of value is scalar /// /// Type of key in the query map /// Type of value in the query map /// Method to use to serialize the value /// Query map to add public void AddQueryMap(QuerySerializationMethod serializationMethod, IDictionary queryMap) { if (queryMap == null) return; if (this._queryParams == null) this._queryParams = new List(); foreach (var kvp in queryMap) { if (kvp.Key == null) continue; // Backwards compat: if it's a dictionary of object, see if it's ienumerable. // If it is, treat it as an ienumerable (yay covariance) if (serializationMethod == QuerySerializationMethod.ToString && typeof(TValue) == typeof(object) && kvp.Value is IEnumerable enumerable && !(kvp.Value is string)) { this._queryParams.Add(new QueryCollectionParameterInfo(serializationMethod, kvp.Key.ToString(), enumerable, format: null)); } else { this._queryParams.Add(new QueryParameterInfo(serializationMethod, kvp.Key.ToString(), kvp.Value, format: null)); } } } /// /// Add a query map to the query parameters list, where the type of value is enumerable /// /// Type of key in the query map /// Type of value in the query map /// Type of element in the value /// Method to use to serialize the value /// Query map to add public void AddQueryCollectionMap(QuerySerializationMethod serializationMethod, IDictionary queryMap) where TValue : IEnumerable { if (queryMap == null) return; if (this._queryParams == null) this._queryParams = new List(); foreach (var kvp in queryMap) { if (kvp.Key != null) this._queryParams.Add(new QueryCollectionParameterInfo(serializationMethod, kvp.Key.ToString(), kvp.Value, format: null)); } } /// /// Add a raw query parameter, which provides a string which is inserted verbatim into the query string /// /// Type of the raw query parmaeter /// Raw query parameter public void AddRawQueryParameter(T value) { if (this._rawQueryParameterInfos == null) this._rawQueryParameterInfos = new List(); this._rawQueryParameterInfos.Add(new RawQueryParameterInfo(value)); } /// /// Add a path parameter: a [Path] method parameter which is used to substitute a placeholder in the path /// /// Type of the value of the path parameter /// /// Name of the name/value pair /// Value of the name/value pair /// Format string to use /// Whether or not this path parameter should be URL-encoded public void AddPathParameter(PathSerializationMethod serializationMethod, string name, T value, string? format = null, bool urlEncode = true) { if (this._pathParams == null) this._pathParams = new List(); this._pathParams.Add(new PathParameterInfo(name, value, format, urlEncode, serializationMethod)); } /// /// Add a HTTP request message property parameter: a [RequestProperty] method parameter which is used to add HTTP request message property dictionary entry /// /// Key of the key/value pair /// Value of the key/value pair public void AddHttpRequestMessagePropertyParameter(string key, object value) { if (this._httpRequestMessageProperties == null) this._httpRequestMessageProperties = new List(); this._httpRequestMessageProperties.Add(new HttpRequestMessagePropertyInfo(key, value)); } /// /// Add a path parameter from a property: a [Path] property which is used to substitute a placeholder in the path /// /// Type of the value of the path parameter /// Method to use to serialize the value /// Name of the name/value pair /// Value of the name/value pair /// Format string to use /// Whether or not this path parameter should be URL-encoded public void AddPathProperty(PathSerializationMethod serializationMethod, string name, T value, string? format = null, bool urlEncode = true) { if (this._pathProperties == null) this._pathProperties = new List(); this._pathProperties.Add(new PathParameterInfo(name, value, format, urlEncode, serializationMethod)); } /// /// Add a query parameter from a property: a [Query] property which is used to append to the query string of all requests /// /// Type of value of the query parameter /// Method to use to serialize the value /// Name of the name/value pair /// Value of the name/value pair /// Format string to use public void AddQueryProperty(QuerySerializationMethod serializationMethod, string name, T value, string? format = null) { if (this._queryProperties == null) this._queryProperties = new List(); this._queryProperties.Add(new QueryParameterInfo(serializationMethod, name, value, format)); } /// /// Add a HTTP request message property from a property: a [RequestProperty] property which is used to add HTTP request message property dictionary entry /// /// Key of the key/value pair /// Value of the key/value pair public void AddHttpRequestMessagePropertyProperty(string key, object value) { if (this._httpRequestMessageProperties == null) this._httpRequestMessageProperties = new List(); this._httpRequestMessageProperties.Add(new HttpRequestMessagePropertyInfo(key, value)); } /// /// Add a property header /// /// Type of value /// Name of the header /// Value of the header /// Value to use if 'value' == null /// Format string to use public void AddPropertyHeader(string name, T value, string? defaultValue, string? format = null) { if (this._propertyHeaders == null) this._propertyHeaders = new List(); this._propertyHeaders.Add(new HeaderParameterInfo(name, value, defaultValue, format)); } /// /// Add a header which is defined on the method /// /// Name of the header to add /// Value of the header to add public void AddMethodHeader(string name, string value) { if (this._methodHeaders == null) this._methodHeaders = new List>(); this._methodHeaders.Add(new KeyValuePair(name, value)); } /// /// Add a header which is defined as a [Header("foo")] parameter to the method /// /// Type of the value /// Name of the header (passed to the HeaderAttribute) /// Value of the header (value of the parameter) /// Format string to use public void AddHeaderParameter(string name, T value, string? format = null) { if (this._headerParams == null) this._headerParams = new List(); this._headerParams.Add(new HeaderParameterInfo(name, value, null, format)); } /// /// Set the body specified by the optional [Body] method parameter /// /// Method to use to serialize the body /// Body to serialize /// Type of the body's value public void SetBodyParameterInfo(BodySerializationMethod serializationMethod, T value) { this.BodyParameterInfo = new BodyParameterInfo(serializationMethod, value); } } }