/// <summary> /// Initializes a new instance of the <see cref="FluentClient"/> class. /// </summary> /// <param name="serializer">The serializer to convert to and from HttpContent.</param> /// <param name="httpHandler">The HTTP handler stack to use for sending requests.</param> /// <param name="disposeHandler"> /// <c>true</c> if the inner handler should be disposed of by the Dispose method, /// <c>false</c> if you intend to reuse the inner handler. /// </param> /// <param name="interceptors">The list of <see cref="IFluentClientInterceptor"/> for this client..</param> /// <exception cref="System.ArgumentNullException"> /// </exception> public FluentClient(IContentSerializer serializer, HttpMessageHandler httpHandler, bool disposeHandler, IEnumerable <IFluentClientInterceptor> interceptors) { if (serializer == null) { throw new ArgumentNullException(nameof(serializer)); } if (httpHandler == null) { throw new ArgumentNullException(nameof(httpHandler)); } if (interceptors == null) { throw new ArgumentNullException(nameof(interceptors)); } Serializer = serializer; HttpHandler = httpHandler; DisposeHandler = disposeHandler; Interceptors = new List <IFluentClientInterceptor>(interceptors); MaxRetry = 1; _defaultRequest = new FluentRequest(); }
private async Task <HttpRequestMessage> TransformRequest(FluentRequest fluentRequest) { var httpRequest = new HttpRequestMessage(); httpRequest.RequestUri = fluentRequest.RequestUri(); httpRequest.Method = fluentRequest.Method; // add serializer media type httpRequest.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(Serializer.ContentType)); // copy headers foreach (var header in fluentRequest.Headers) { var values = header.Value.ToList(); httpRequest.Headers.Add(header.Key, values); } httpRequest.Content = await GetContent(fluentRequest).ConfigureAwait(false); // run request interceptors var context = new InterceptorRequestContext(this, fluentRequest) { HttpRequest = httpRequest }; foreach (var interceptor in Interceptors) { await interceptor.RequestAsync(context).ConfigureAwait(false); } return(context.HttpRequest ?? httpRequest); }
private async Task <FluentResponse> TransformResponse(FluentRequest fluentRequest, HttpResponseMessage httpResponse) { var fluentResponse = new FluentResponse(Serializer, httpResponse.Content); fluentResponse.ReasonPhrase = httpResponse.ReasonPhrase; fluentResponse.StatusCode = httpResponse.StatusCode; fluentResponse.Request = fluentRequest; var headers = new Dictionary <string, ICollection <string> >(); foreach (var header in httpResponse.Headers) { headers.Add(header.Key, header.Value.ToList()); } fluentResponse.Headers = headers; // run response interceptors var context = new InterceptorResponseContext(this, httpResponse) { Response = fluentResponse }; foreach (var interceptor in Interceptors) { await interceptor.ResponseAsync(context).ConfigureAwait(false); } return(context.Response ?? fluentResponse); }
/// <summary> /// Sends a request using specified fluent request as an asynchronous operation. /// </summary> /// <param name="fluentRequest">The fluent request to send.</param> /// <returns> /// The task object representing the asynchronous operation. /// </returns> /// <exception cref="System.ArgumentNullException"></exception> /// <exception cref="ArgumentNullException"><paramref name="fluentRequest" /> is <see langword="null" />.</exception> public async Task <FluentResponse> SendAsync(FluentRequest fluentRequest) { if (fluentRequest == null) { throw new ArgumentNullException(nameof(fluentRequest)); } var httpClient = new HttpClient(HttpHandler, DisposeHandler); var headerValue = new ProductInfoHeaderValue(ThisAssembly.AssemblyProduct, ThisAssembly.AssemblyVersion); httpClient.DefaultRequestHeaders.UserAgent.Add(headerValue); FluentResponse fluentResponse; int count = 0; do { var httpRequest = await TransformRequest(fluentRequest).ConfigureAwait(false); var httpResponse = await httpClient .SendAsync(httpRequest, fluentRequest.CompletionOption, fluentRequest.CancellationToken) .ConfigureAwait(false); fluentResponse = await TransformResponse(fluentRequest, httpResponse).ConfigureAwait(false); // track call count to prevent infinite loop count++; } while (fluentResponse.ShouldRetry && count <= MaxRetry); return(fluentResponse); }
private async Task <HttpContent> GetContent(FluentRequest fluentRequest) { if (fluentRequest.Method == HttpMethod.Get) { return(null); } if (fluentRequest.ContentData != null) { return(await Serializer.SerializeAsync(fluentRequest.ContentData).ConfigureAwait(false)); } // convert NameValue to KeyValuePair var formData = new List <KeyValuePair <string, string> >(); foreach (var pair in fluentRequest.FormData) { var key = pair.Key; var values = pair.Value.ToList(); formData.AddRange(values.Select(value => new KeyValuePair <string, string>(key, value))); } var httpContent = new FormUrlEncodedContent(formData); return(httpContent); }
/// <summary> /// Set the initial default values for all requests from this instance of <see cref="FluentClient" />. /// </summary> /// <param name="request">The default request.</param> /// <exception cref="ArgumentNullException"><paramref name="request" /> is <see langword="null" />.</exception> public void Defaults(FluentRequest request) { if (request == null) { throw new ArgumentNullException(nameof(request)); } _defaultRequest = request; }
/// <summary> /// Creates a new object that is a copy of the current instance. /// </summary> /// <returns> /// A new object that is a copy of this instance. /// </returns> public FluentRequest Clone() { var request = new FluentRequest { BaseUri = BaseUri, CompletionOption = CompletionOption, Method = Method, Paths = new List <string>(Paths), Headers = new Dictionary <string, ICollection <string> >(Headers), QueryString = new Dictionary <string, ICollection <string> >(QueryString), FormData = new Dictionary <string, ICollection <string> >(FormData) }; return(request); }
/// <summary> /// Initializes a new instance of the <see cref="PostBuilder{TBuilder}"/> class. /// </summary> /// <param name="request">The fluent HTTP request being built.</param> protected PostBuilder(FluentRequest request) : base(request) { }
/// <summary> /// Initializes a new instance of the <see cref="HeaderBuilder"/> class. /// </summary> /// <param name="request">The fluent HTTP request being built.</param> public HeaderBuilder(FluentRequest request) : base(request) { }
/// <summary> /// Initializes a new instance of the <see cref="QueryBuilder" /> class. /// </summary> /// <param name="request">The fluent HTTP request being built.</param> public QueryBuilder(FluentRequest request) : base(request) { }
/// <summary> /// Initializes a new instance of the <see cref="RequestBuilder{TBuilder}"/> class. /// </summary> /// <param name="request">The fluent HTTP request being built.</param> protected RequestBuilder(FluentRequest request) { Request = request; }
/// <summary> /// Initializes a new instance of the <see cref="SendBuilder"/> class. /// </summary> /// <param name="request">The fluent HTTP request being built.</param> public SendBuilder(FluentRequest request) : base(request) { }
/// <summary> /// Initializes a new instance of the <see cref="InterceptorRequestContext"/> class. /// </summary> /// <param name="client">The current <see cref="FluentClient"/>.</param> /// <param name="request">The <see cref="FluentRequest"/> used to build the current request.</param> public InterceptorRequestContext(FluentClient client, FluentRequest request) { Client = client; Request = request; }
/// <summary> /// Initializes a new instance of the <see cref="FormBuilder"/> class. /// </summary> /// <param name="request">The fluent HTTP request being built.</param> public FormBuilder(FluentRequest request) : base(request) { }