/// <summary> /// 发送 Get 请求, 返回结果对象;如遇 access_token 超时错误, 会自动获取新的 access_token 并重试 /// </summary> /// <typeparam name="T">结果对象类型</typeparam> /// <param name="url">接口网址, 里边的 $acac$ 会被自动替换成 access_token=xxx </param> /// <param name="config"></param> /// <exception cref="ApiException">返回的 JSON 字符串中包含了错误信息</exception> public static async Task <T> GetResult <T>(string url, ApiConfig config = null) where T : IApiResult { var token = new AsyncOutParameter <string>(); try { var text = await GetStringWithToken(url, config, token).ConfigureAwait(false); return(BuildResult <T>(text, config)); } catch (ApiException ex) { if (ex.Code == ErrorAccessTokenExpired || ex.Code == ErrorAccessTokenInvalid) { var m = config?.AccessTokenManager ?? _defaultConfig.AccessTokenManager; await m.RefreshTokenInfo(token.Value).ConfigureAwait(false); var text = await GetString(url, config).ConfigureAwait(false); return(BuildResult <T>(text, config)); } throw; } }
/// <summary> /// 调用接口 /// </summary> /// <param name="outcoming">请求参数</param> /// <param name="stream">正常情况下返回的数据流, 内容是 CSV 格式的数据</param> /// <param name="incoming">出错时的返回结果</param> /// <returns>正常情况: true, 出错时: false</returns> public async Task <bool> Invoke(Outcoming outcoming, AsyncOutParameter <Stream> stream, AsyncOutParameter <Incoming> incoming) { var url = Stage.GetApiRootUrl(_sandbox) + "pay/downloadbill"; var response = await _requester.GetResponse(url, false, outcoming).ConfigureAwait(false); var netStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); var peekStream = new PeekableStream(netStream, 1); var buffer = new byte[1]; await peekStream.PeekAsync(buffer, 0, 1).ConfigureAwait(false); if (buffer[0] != '<') { stream.SetValue(peekStream); return(true); } using (var reader = new StreamReader(peekStream, Encoding.UTF8)) { var responseBody = await reader.ReadToEndAsync().ConfigureAwait(false); incoming.SetValue(_requester.ParseResponse <Incoming, ErrorCode>(responseBody, _checkSignature)); return(false); } }
/// <summary> /// 上传文件, 并检查返回结果是否用错误;如遇 access_token 超时错误, 会自动获取新的 access_token 并重试 /// </summary> /// <param name="url">接口网址, 里边的 $acac$ 会被自动替换成 access_token=xxx </param> /// <param name="fieldName">文件字段名称</param> /// <param name="fileName">文件名</param> /// <param name="fileStream">文件内容流</param> /// <param name="additionalFields">要在 POST 内容中发送的其它字段</param> /// <param name="config"></param> /// <exception cref="ApiException">返回的 JSON 字符串中包含了错误信息</exception> public static async Task UploadVoid(string url, string fieldName, string fileName, Stream fileStream, KeyValuePair <string, string>[] additionalFields = null, ApiConfig config = null) { var token = new AsyncOutParameter <string>(); try { var text = await UploadStringWithToken(url, fieldName, fileName, fileStream, additionalFields, config, token).ConfigureAwait(false); BuildVoid(text, config); } catch (ApiException ex) { if (ex.Code == ErrorAccessTokenExpired || ex.Code == ErrorAccessTokenInvalid) { var m = config?.AccessTokenManager ?? _defaultConfig.AccessTokenManager; await m.RefreshTokenInfo(token.Value).ConfigureAwait(false); var text = await UploadString(url, fieldName, fileName, fileStream, additionalFields, config).ConfigureAwait(false); BuildVoid(text, config); return; } throw; } }
/// <summary> /// 发送 Post 请求, 并检查返回结果是否用错误;如遇 access_token 超时错误, 会自动获取新的 access_token 并重试 /// </summary> /// <param name="url">接口网址, 里边的 $acac$ 会被自动替换成 access_token=xxx </param> /// <param name="data">将会转换为 JSON 格式作为 Post 请求的正文内容</param> /// <param name="config"></param> /// <exception cref="ApiException">返回的 JSON 字符串中包含了错误信息</exception> public static async Task PostVoid(string url, object data, ApiConfig config = null) { var token = new AsyncOutParameter <string>(); try { var text = await PostStringWithToken(url, data, config, token).ConfigureAwait(false); BuildVoid(text, config); } catch (ApiException ex) { if (ex.Code == ErrorAccessTokenExpired || ex.Code == ErrorAccessTokenInvalid) { var m = config?.AccessTokenManager ?? _defaultConfig.AccessTokenManager; await m.RefreshTokenInfo(token.Value).ConfigureAwait(false); var text = await PostString(url, data, config).ConfigureAwait(false); BuildVoid(text, config); return; } throw; } }
public static void SetValue <T>(this AsyncOutParameter <T> parameter, T value) { if (parameter != null) { parameter.Value = value; } }
private static async Task <string> FormatUrl(string url, ApiConfig config, AsyncOutParameter <string> token) { if (url.IndexOf("$acac$", StringComparison.InvariantCulture) < 0) { return(url); } var m = config?.AccessTokenManager ?? _defaultConfig.AccessTokenManager; var accessToken = await m.GetToken().ConfigureAwait(false); var escapedToken = Uri.EscapeDataString(accessToken); token.SetValue(accessToken); return(url.Replace("$acac$", "access_token=" + escapedToken)); }
private static async Task <Stream> GetStreamWithToken(string url, ApiConfig config, AsyncOutParameter <string> token) { url = await FormatUrl(url, config, token).ConfigureAwait(false); var http = config?.HttpClient ?? _defaultConfig.HttpClient; return(await http.GetStreamAsync(url).ConfigureAwait(false)); }
private static async Task <string> GetStringWithToken(string url, ApiConfig config, AsyncOutParameter <string> token) { var stream = await GetStreamWithToken(url, config, token).ConfigureAwait(false); using (var reader = new StreamReader(stream, Encoding.UTF8)) { return(await reader.ReadToEndAsync().ConfigureAwait(false)); } }
private static async Task <string> UploadStringWithToken(string url, string fieldName, string fileName, Stream fileStream, KeyValuePair <string, string>[] additionalFields, ApiConfig config, AsyncOutParameter <string> token) { var content = BuildUploadContent(fieldName, fileName, fileStream, additionalFields); url = await FormatUrl(url, config, token).ConfigureAwait(false); var http = config?.HttpClient ?? _defaultConfig.HttpClient; var response = await http.PostAsync(url, content).ConfigureAwait(false); return(await response.Content.ReadAsStringAsync().ConfigureAwait(false)); }
private static async Task <Stream> PostStreamWithToken(string url, object data, ApiConfig config, AsyncOutParameter <string> token) { url = await FormatUrl(url, config, token).ConfigureAwait(false); var parser = config?.JsonParser ?? _defaultConfig.JsonParser; var body = parser.ToString(data); var http = config?.HttpClient ?? _defaultConfig.HttpClient; var response = await http.PostAsync(url, new StringContent(body)).ConfigureAwait(false); return(await response.Content.ReadAsStreamAsync().ConfigureAwait(false)); }
/// <summary> /// 发送 Get 请求, 返回流 /// </summary> /// <param name="url">网址</param> /// <param name="config"></param> /// <returns></returns> public static async Task <Stream> GetStream(string url, ApiConfig config = null) { var token = new AsyncOutParameter <string>(); var ms = new MemoryStream(); try { using (var s = await GetStreamWithToken(url, config, token).ConfigureAwait(false)) { await s.CopyToAsync(ms).ConfigureAwait(false); //估计错误消息应该不会大于400字节 if (ms.Length < 400) { var buffer = ms.ToArray(); var text = Encoding.UTF8.GetString(buffer); if (Regex.IsMatch(text, @"^\s*{")) { //如果是失败消息, 这里会抛出异常 BuildVoid(text, config); } } ms.Position = 0; return(ms); } } catch (ApiException ex) { if (ex.Code == ErrorAccessTokenExpired || ex.Code == ErrorAccessTokenInvalid) { ms.SetLength(0); var m = config?.AccessTokenManager ?? _defaultConfig.AccessTokenManager; await m.RefreshTokenInfo(token.Value).ConfigureAwait(false); using (var s = await GetStreamWithToken(url, config, null).ConfigureAwait(false)) { await s.CopyToAsync(ms).ConfigureAwait(false); //估计错误消息应该不会大于400字节 if (ms.Length < 400) { var buffer = ms.ToArray(); var text = Encoding.UTF8.GetString(buffer); if (Regex.IsMatch(text, @"^\s*{")) { //如果是失败消息, 这里会抛出异常 BuildVoid(text, config); } } ms.Position = 0; return(ms); } } throw; } }